Further Modularization
This commit is contained in:
parent
31cc1f41b5
commit
f27af4c4dd
@ -107,6 +107,12 @@ def get_info(_id, _dict):
|
||||
return _dict[_id]
|
||||
return _id
|
||||
|
||||
def get_alias(_id, _dict):
|
||||
_int_id = int_id(_id)
|
||||
if _int_id in _dict:
|
||||
return _dict[_int_id]
|
||||
return _int_id
|
||||
|
||||
# These are the functions you should use to look up IDs in the dictionaries
|
||||
# But they don't work here because they reference dictionraries not avaialbe
|
||||
# in this scope
|
||||
|
@ -33,7 +33,7 @@ from twisted.internet import task
|
||||
|
||||
# Things we import from the main hblink module
|
||||
from hblink import HBSYSTEM, systems, int_id, hblink_handler
|
||||
from dmr_utils import hex_str_3, int_id, get_info
|
||||
from dmr_utils import hex_str_3, int_id, get_alias
|
||||
import dec_dmr
|
||||
import bptc
|
||||
import hb_config
|
||||
@ -51,7 +51,6 @@ __email__ = 'n0mjs@me.com'
|
||||
__status__ = 'pre-alpha'
|
||||
|
||||
# Module gobal varaibles
|
||||
GROUP_HANGTIME = 5
|
||||
|
||||
# Import Bridging rules
|
||||
# Note: A stanza *must* exist for any MASTER or CLIENT configured in the main
|
||||
@ -86,27 +85,26 @@ def make_bridges(_hb_confbridge_bridges):
|
||||
# ACL may be a single list of subscriber IDs
|
||||
# Global action is to allow or deny them. Multiple lists with different actions and ranges
|
||||
# are not yet implemented.
|
||||
def build_acl():
|
||||
def build_acl(_sub_acl):
|
||||
try:
|
||||
from sub_acl import ACL_ACTION, ACL
|
||||
# uses more memory to build hex strings, but processes MUCH faster when checking for matches
|
||||
for i, e in enumerate(ACL):
|
||||
ACL[i] = hex_str_3(ACL[i])
|
||||
logger.info('Subscriber access control file found, subscriber ACL imported')
|
||||
acl_file = import_module(_sub_acl)
|
||||
for i, e in enumerate(acl_file.ACL):
|
||||
acl_file.ACL[i] = hex_str_3(acl_file.ACL[i])
|
||||
logger.info('ACL file found and ACL entries imported')
|
||||
except ImportError:
|
||||
logger.critical('\'sub_acl.py\' not found - all subscriber IDs are valid')
|
||||
logger.info('ACL file not found or invalid - all subscriber IDs are valid')
|
||||
ACL_ACTION = 'NONE'
|
||||
|
||||
# Depending on which type of ACL is used (PERMIT, DENY... or there isn't one)
|
||||
# define a differnet function to be used to check the ACL
|
||||
global allow_sub
|
||||
if ACL_ACTION == 'PERMIT':
|
||||
if acl_file.ACL_ACTION == 'PERMIT':
|
||||
def allow_sub(_sub):
|
||||
if _sub in ACL:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
elif ACL_ACTION == 'DENY':
|
||||
elif acl_file.ACL_ACTION == 'DENY':
|
||||
def allow_sub(_sub):
|
||||
if _sub not in ACL:
|
||||
return True
|
||||
@ -115,6 +113,8 @@ def build_acl():
|
||||
else:
|
||||
def allow_sub(_sub):
|
||||
return True
|
||||
|
||||
return acl_file.ACL
|
||||
|
||||
|
||||
# Run this every minute for rule timer updates
|
||||
@ -223,7 +223,8 @@ class routerSYSTEM(HBSYSTEM):
|
||||
|
||||
# This is a new call stream
|
||||
self.STATUS['RX_START'] = pkt_time
|
||||
logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s', self._system, int_id(_stream_id), sub_alias(_rf_src), int_id(_rf_src), peer_alias(_radio_id), int_id(_radio_id), tg_alias(_dst_id), int_id(_dst_id), _slot)
|
||||
logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s', \
|
||||
self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_radio_id, peer_ids), int_id(_radio_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot)
|
||||
|
||||
# If we can, use the LC from the voice header as to keep all options intact
|
||||
if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD:
|
||||
@ -254,11 +255,11 @@ class routerSYSTEM(HBSYSTEM):
|
||||
# From the same group as the last TX to this HBSystem, but from a different subscriber, and it has been less than stream timeout
|
||||
# The "continue" at the end of each means the next iteration of the for loop that tests for matching rules
|
||||
#
|
||||
if ((_target['TGID'] != _target_status[_target['TS']]['RX_TGID']) and ((pkt_time - _target_status[_target['TS']]['RX_TIME']) < GROUP_HANGTIME)):
|
||||
if ((_target['TGID'] != _target_status[_target['TS']]['RX_TGID']) and ((pkt_time - _target_status[_target['TS']]['RX_TIME']) < self._config['GROUP_HANGTIME'])):
|
||||
if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD and self.STATUS[_slot]['RX_STREAM_ID'] != _seq:
|
||||
logger.info('(%s) Call not routed to TGID %s, target active or in group hangtime: HBSystem: %s, TS: %s, TGID: %s', self._system, int_id(_target['TGID']), _target['SYSTEM'], _target['TS'], int_id(_target_status[_target['TS']]['RX_TGID']))
|
||||
continue
|
||||
if ((_target['TGID'] != _target_status[_target['TS']]['TX_TGID']) and ((pkt_time - _target_status[_target['TS']]['TX_TIME']) < GROUP_HANGTIME)):
|
||||
if ((_target['TGID'] != _target_status[_target['TS']]['TX_TGID']) and ((pkt_time - _target_status[_target['TS']]['TX_TIME']) < self._config['GROUP_HANGTIME'])):
|
||||
if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD and self.STATUS[_slot]['RX_STREAM_ID'] != _seq:
|
||||
logger.info('(%s) Call not routed to TGID%s, target in group hangtime: HBSystem: %s, TS: %s, TGID: %s', self._system, int_id(_target['TGID']), _target['SYSTEM'], _target['TS'], int_id(_target_status[_target['TS']]['TX_TGID']))
|
||||
continue
|
||||
@ -322,7 +323,8 @@ class routerSYSTEM(HBSYSTEM):
|
||||
# Final actions - Is this a voice terminator?
|
||||
if (_frame_type == hb_const.HBPF_DATA_SYNC) and (_dtype_vseq == hb_const.HBPF_SLT_VTERM) and (self.STATUS[_slot]['RX_TYPE'] != hb_const.HBPF_SLT_VTERM):
|
||||
call_duration = pkt_time - self.STATUS['RX_START']
|
||||
logger.info('(%s) *CALL END* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s, Duration: %s', self._system, int_id(_stream_id), sub_alias(_rf_src), int_id(_rf_src), peer_alias(_radio_id), int_id(_radio_id), tg_alias(_dst_id), int_id(_dst_id), _slot, call_duration)
|
||||
logger.info('(%s) *CALL END* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s, Duration: %s', \
|
||||
self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_radio_id, peer_ids), int_id(_radio_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot, call_duration)
|
||||
|
||||
#
|
||||
# Begin in-band signalling for call end. This has nothign to do with routing traffic directly.
|
||||
@ -455,16 +457,7 @@ if __name__ == '__main__':
|
||||
talkgroup_ids = mk_id_dict(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['TGID_FILE'])
|
||||
if talkgroup_ids:
|
||||
logger.info('ID ALIAS MAPPER: talkgroup_ids dictionary is available')
|
||||
|
||||
# These are the functions to look up IDs in the dictionaries
|
||||
def sub_alias(_sub_id):
|
||||
return get_info(int_id(_sub_id), subscriber_ids)
|
||||
|
||||
def peer_alias(_peer_id):
|
||||
return get_info(int_id(_peer_id), peer_ids)
|
||||
|
||||
def tg_alias(_tgid):
|
||||
return get_info(int_id(_tgid), talkgroup_ids)
|
||||
|
||||
#
|
||||
# START HB_ROUTER
|
||||
@ -474,7 +467,7 @@ if __name__ == '__main__':
|
||||
BRIDGES = make_bridges('hb_confbridge_rules')
|
||||
|
||||
# Build the Access Control List
|
||||
build_acl()
|
||||
ACL = build_acl('sub_acl')
|
||||
|
||||
# HBlink instance creation
|
||||
logger.info('HBlink \'hb_router.py\' (c) 2016 N0MJS & the K0USY Group - SYSTEM STARTING...')
|
||||
|
@ -1,21 +1,45 @@
|
||||
'''
|
||||
THIS EXAMPLE WILL NOT WORK AS IT IS - YOU MUST SPECIFY YOUR OWN VALUES!!!
|
||||
|
||||
This file is organized around the "Conference Bridges" that you wish to use. If you're a c-Bridge
|
||||
person, think of these as "bridge groups". You might also liken them to a "reflector". If a particular
|
||||
system is "ACTIVE" on a particular conference bridge, any traffid from that system will be sent
|
||||
to any other system that is active on the bridge as well. This is not an "end to end" method, because
|
||||
each system must independently be activated on the bridge.
|
||||
|
||||
The first level (e.g. "WORLDWIDE" or "STATEWIDE" in the examples) is the name of the conference
|
||||
bridge. This is any arbitrary ASCII text string you want to use. Under each conference bridge
|
||||
definition are the following items -- one line for each HBSystem as defined in the main HBlink
|
||||
configuration file.
|
||||
|
||||
* SYSTEM - The name of the sytem as listed in the main hblink configuration file (e.g. hblink.cfg)
|
||||
This MUST be the exact same name as in the main config file!!!
|
||||
* TS - Timeslot used for matching traffic to this confernce bridge
|
||||
* TGID - Talkgroup ID used for matching traffic to this conference bridge
|
||||
* ON and OFF are LISTS of Talkgroup IDs used to trigger this system off and on. Even if you
|
||||
only want one (as shown in the ON example), it has to be in list format. None can be
|
||||
handled with an empty list, such as " 'ON': [] ".
|
||||
* TO_TYPE is timeout type. If you want to use timers, ON means when it's turned on, it will
|
||||
turn off afer the timout period and OFF means it will turn back on after the timout
|
||||
period. If you don't want to use timers, set it to anything else, but 'NONE' might be
|
||||
a good value for documentation!
|
||||
* TIMOUT is a value in minutes for the timout timer. No, I won't make it 'seconds', so don't
|
||||
ask. Timers are performance "expense".
|
||||
|
||||
'''
|
||||
|
||||
BRIDGES = {
|
||||
'WORLDWIDE': [
|
||||
{'SYSTEM': 'MASTER-1', 'TS': 1, 'TGID': 1, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'ON', 'ON': [2,], 'OFF': [9,]},
|
||||
{'SYSTEM': 'CLIENT-1', 'TS': 1, 'TGID': 3100, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'ON', 'ON': [2,], 'OFF': [9,]},
|
||||
{'SYSTEM': 'MASTER-1', 'TS': 1, 'TGID': 1, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'ON', 'ON': [2,], 'OFF': [9,10]},
|
||||
{'SYSTEM': 'CLIENT-1', 'TS': 1, 'TGID': 3100, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'ON', 'ON': [2,], 'OFF': [9,10]},
|
||||
],
|
||||
'ENGLISH': [
|
||||
{'SYSTEM': 'MASTER-1', 'TS': 1, 'TGID': 13, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'NONE', 'ON': [3,], 'OFF': [8,]},
|
||||
{'SYSTEM': 'CLIENT-2', 'TS': 1, 'TGID': 13, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'NONE', 'ON': [3,], 'OFF': [8,]},
|
||||
{'SYSTEM': 'MASTER-1', 'TS': 1, 'TGID': 13, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'NONE', 'ON': [3,], 'OFF': [8,10]},
|
||||
{'SYSTEM': 'CLIENT-2', 'TS': 1, 'TGID': 13, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'NONE', 'ON': [3,], 'OFF': [8,10]},
|
||||
],
|
||||
'STATEWIDE': [
|
||||
{'SYSTEM': 'MASTER-1', 'TS': 2, 'TGID': 3129, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'NONE', 'ON': [4,], 'OFF': [7,]},
|
||||
{'SYSTEM': 'CLIENT-2', 'TS': 2, 'TGID': 3129, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'NONE', 'ON': [4,], 'OFF': [7,]},
|
||||
{'SYSTEM': 'MASTER-1', 'TS': 2, 'TGID': 3129, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'NONE', 'ON': [4,], 'OFF': [7,10]},
|
||||
{'SYSTEM': 'CLIENT-2', 'TS': 2, 'TGID': 3129, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'NONE', 'ON': [4,], 'OFF': [7,10]},
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,8 @@ def build_config(_config_file):
|
||||
'SLOTS': config.get(section, 'SLOTS'),
|
||||
'URL': config.get(section, 'URL').ljust(124)[:124],
|
||||
'SOFTWARE_ID': config.get(section, 'SOFTWARE_ID').ljust(40)[:40],
|
||||
'PACKAGE_ID': config.get(section, 'PACKAGE_ID').ljust(40)[:40]
|
||||
'PACKAGE_ID': config.get(section, 'PACKAGE_ID').ljust(40)[:40],
|
||||
'GROUP_HANGTIME': config.getint(section, 'GROUP_HANGTIME')
|
||||
}})
|
||||
CONFIG['SYSTEMS'][section].update({'STATS': {
|
||||
'CONNECTION': 'NO', # NO, RTPL_SENT, AUTHENTICATED, CONFIG-SENT, YES
|
||||
@ -124,7 +125,8 @@ def build_config(_config_file):
|
||||
'EXPORT_AMBE': config.getboolean(section, 'EXPORT_AMBE'),
|
||||
'IP': gethostbyname(config.get(section, 'IP')),
|
||||
'PORT': config.getint(section, 'PORT'),
|
||||
'PASSPHRASE': config.get(section, 'PASSPHRASE')
|
||||
'PASSPHRASE': config.get(section, 'PASSPHRASE'),
|
||||
'GROUP_HANGTIME': config.getint(section, 'GROUP_HANGTIME')
|
||||
}})
|
||||
CONFIG['SYSTEMS'][section].update({'CLIENTS': {}})
|
||||
|
||||
|
@ -12,8 +12,8 @@ NOTES:
|
||||
period. If you don't want to use timers, set it to anything else, but 'NONE' might be
|
||||
a good value for documentation!
|
||||
* TIMOUT is a value in minutes for the timout timer. No, I won't make it 'seconds', so don't
|
||||
|
||||
ask. Timers are performance "expense".
|
||||
|
||||
DO YOU THINK THIS FILE IS TOO COMPLICATED?
|
||||
Because you guys all want more and more features, this file is getting complicated. I have
|
||||
dabbled with using a parser to make it easier to build. I'm torn. There is a HUGE benefit
|
||||
|
@ -68,6 +68,7 @@ EXPORT_AMBE: False
|
||||
IP:
|
||||
PORT: 54000
|
||||
PASSPHRASE: s3cr37w0rd
|
||||
GROUP_HANGTIME: 5
|
||||
|
||||
# CLIENT INSTANCES - DUPLICATE SECTION FOR MULTIPLE CLIENTS
|
||||
# There are a LOT of errors in the HB Protocol specifications on this one!
|
||||
@ -100,3 +101,4 @@ DESCRIPTION: This is a cool repeater
|
||||
URL: www.w1abc.org
|
||||
SOFTWARE_ID: HBlink
|
||||
PACKAGE_ID: v0.1
|
||||
GROUP_HANGTIME: 5
|
Loading…
Reference in New Issue
Block a user