diff --git a/hblink.py b/hblink.py index 7cd09e3..c488499 100755 --- a/hblink.py +++ b/hblink.py @@ -293,10 +293,10 @@ class OPENBRIDGE(DatagramProtocol): #This is a v1 packet, so all the extended stuff we can set to default #We are the source server if traffic came over a v1 bridge - sysops are responsible #for bridged in traffic from their system - _source_server == self.CONFIG['SERVER_ID'] - _source_rptr == b'\x00\x00\x00\x00' - _ber == b'\x00' - _rssi == b'\x00' + _source_server = self.CONFIG['SERVER_ID'] + _source_rptr = b'\x00\x00\x00\x00' + _ber = b'\x00' + _rssi = b'\x00' _hops = b'' _seq = _data[4] diff --git a/report_sql.py b/report_sql.py new file mode 100644 index 0000000..8577f4b --- /dev/null +++ b/report_sql.py @@ -0,0 +1,159 @@ +############################################################################### +# Copyright (C) 2022 Simon Adlem, G7RZU +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +############################################################################### + +# Does anybody read this stuff? There's a PEP somewhere that says I should do this. +__author__ = 'Simon Adlem - G7RZU' +__copyright__ = 'Copyright (c) Simon Adlem, G7RZU 2022' +__credits__ = '' +__license__ = 'GNU GPLv3' +__maintainer__ = 'Simon Adlem G7RZU' +__email__ = 'simon@gb7fr.org.uk' + +#This is example code to connect to the report service in FreeDMR / HBLink3 +#It can be used as a skeleton to build logging and monitoring tools. + +import pickle + +from twisted.internet import reactor +from twisted.internet.protocol import ReconnectingClientFactory +from twisted.protocols.basic import NetstringReceiver + +import mysql.connector +from mysql.connector import errorcode + +from reporting_const import * + +class reportClient(NetstringReceiver): + def __init__(self,db): + self.db = db + + def stringReceived(self, data): + + if data[:1] == REPORT_OPCODES['BRDG_EVENT']: + self.bridgeEvent(data[1:].decode('UTF-8')) + elif data[:1] == REPORT_OPCODES['CONFIG_SND']: + self.configSend(data[1:]) + elif data[:1] == REPORT_OPCODES['BRIDGE_SND']: + self.bridgeSend(data[1:]) + elif data == b'bridge updated': + pass + else: + print('Unkown opcode - line:',data) + + def bridgeEvent(self,data): + datalist = data.split(',') + event = { + 'type' : datalist[0], + 'event' : datalist[1], + 'trx' : datalist[2], + 'system' : datalist[3], + 'streamid' : datalist[4], + 'peerid' : datalist[5], + 'subid' : datalist[6], + 'slot' : datalist[7], + 'dstid' : datalist[8], + 'duration' : False + } + + if len(datalist) > 9: + event['duration'] = datalist[9] + + if event['event'] == 'END': + + while not self.db.is_connected(): + self.db.reconnect() + + _cursor = self.db.cursor() + try: + _cursor.execute("insert into feed values (NULL,'{}','{}','{}','{}','{}','{}','{}','{}','{}','{}')".format(event['type'],event['event'], event['trx'],event['system'],event['streamid'],event['peerid'],event['subid'],event['slot'],event['dstid'],event['duration'])) + self.db.commit() + #print("{} {} {} {} {} {} {} {} {}".format(event['type'],event['event'], event['trx'],event['system'],event['streamid'],event['peerid'],event['subid'],event['slot'],event['dstid'],event['duration'])) + except mysql.connector.Error as err: + _cursor.close() + print('(MYSQL) error, problem with cursor execute: {}'.format(err)) + + + def bridgeSend(self,data): + self.BRIDGES = pickle.loads(data) + + def configSend(self,data): + self.CONFIG = pickle.loads(data) + + +class reportClientFactory(ReconnectingClientFactory): + def __init__(self,proto,db): + self.proto = proto + self.db = db + + def startedConnecting(self, connector): + print('Started to connect.') + + def buildProtocol(self, addr): + print('Connected.') + print('Resetting reconnection delay') + self.resetDelay() + return self.proto(db) + + def clientConnectionLost(self, connector, reason): + print('Lost connection. Reason:', reason) + ReconnectingClientFactory.clientConnectionLost(self, connector, reason) + + def clientConnectionFailed(self, connector, reason): + print('Connection failed. Reason:', reason) + ReconnectingClientFactory.clientConnectionFailed(self, connector,reason) + +if __name__ == '__main__': + + from twisted.internet import reactor + from setproctitle import setproctitle + import signal + import sys + import os + + #Set process title early + setproctitle(__file__) + + # Change the current directory to the location of the application + os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) + + def sig_handler(_signal, _frame): + print('SHUTDOWN: TERMINATING WITH SIGNAL {}'.format(str(_signal))) + reactor.stop() + + # Set signal handers so that we can gracefully exit if need be + for sig in [signal.SIGINT, signal.SIGTERM]: + signal.signal(sig, sig_handler) + + try: + db = mysql.connector.connect( + host=sys.argv[3], + user=sys.argv[4], + password=sys.argv[5], + database=sys.argv[6], + ) + except mysql.connector.Error as err: + if err.errno == errorcode.ER_ACCESS_DENIED_ERROR: + sys.exit('(MYSQL) username or password error') + elif err.errno == errorcode.ER_BAD_DB_ERROR: + sys.exit('(MYSQL) DB Error') + else: + sys.exit('(MYSQL) error: %s',err) + + + reactor.connectTCP(sys.argv[1],int(sys.argv[2]), reportClientFactory(reportClient,db)) + reactor.run()