diff --git a/boswatch/watchdog/watchdog.py b/boswatch/watchdog/watchdog.py new file mode 100644 index 0000000..05ed5f2 --- /dev/null +++ b/boswatch/watchdog/watchdog.py @@ -0,0 +1,29 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +"""! + ____ ____ ______ __ __ __ _____ + / __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ / + / __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ < + / /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ / +/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/ + German BOS Information Script + by Bastian Schroll + +@file: watchdog.py +@date: ##.##.2018 +@author: Bastian Schroll +@description: Watchdog to _check if BOSWatch client, server, rtl_fm or multimon-ng is still running +""" + +import logging + +logging.debug("- %s loaded", __name__) + + +class Watchdog: + """!Class for an Watchdog to observe, + if needed subprocess still running""" + + def __init__(self): + """!Create a new instance""" + pass diff --git a/bw_client.py b/bw_client.py new file mode 100644 index 0000000..9243ffd --- /dev/null +++ b/bw_client.py @@ -0,0 +1,118 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" + ____ ____ ______ __ __ __ _____ + / __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ / + / __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ < + / /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ / +/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/ + German BOS Information Script + by Bastian Schroll + +@file: bw_client.py +@date: 09.12.2017 +@author: Bastian Schroll +@description: BOSWatch client application +""" +from boswatch.utils import paths + +if not paths.makeDirIfNotExist(paths.LOG_PATH): + print("cannot find/create log directory: %s", paths.LOG_PATH) + exit(1) + +try: + import logging + import logging.config + + logging.config.fileConfig(paths.CONFIG_PATH + "logger_client.ini") + logging.debug("") + logging.debug("######################## NEW LOG ############################") + logging.debug("BOSWatch client has started ...") +except Exception as e: # pragma: no cover + print("cannot load logger") + print(e) + exit(1) + +try: + logging.debug("Import python modules") + import argparse + logging.debug("- argparse") + import subprocess + logging.debug("- subprocess") + # following is temp for testing + import time + + logging.debug("Import BOSWatch modules") + from boswatch.config import Config + from boswatch.network.client import TCPClient + from boswatch.decoder import decoder + from boswatch.utils import header +except Exception as e: # pragma: no cover + logging.exception("cannot import modules") + print("cannot import modules") + print(e) + exit(1) + +try: + header.logoToLog() + header.infoToLog() + header.logoToScreen() + + logging.debug("parse args") + # With -h or --help you get the Args help + parser = argparse.ArgumentParser(prog="bw_client.py", + description="""BOSWatch is a Python Script to receive and + decode german BOS information with rtl_fm and multimon-NG""", + epilog="""More options you can find in the extern client.ini + file in the folder /config""") + parser.add_argument("-c", "--config", help="Name to configuration File", required=True) + parser.add_argument("-t", "--test", help="Client will send some testdata", action="store_true") # todo implement testmode + args = parser.parse_args() + + bwConfig = Config() + if bwConfig.loadConfigFile(paths.CONFIG_PATH + args.config, "clientConfig") is False: + logging.exception("cannot load config file") + print("cannot load config file") + exit(1) # without config cannot _run + + bwClient = TCPClient() + if bwClient.connect(bwConfig.getStr("Server", "IP"), bwConfig.getInt("Server", "PORT")): + + while 1: + for i in range(0, 5): + time.sleep(1) + print("Alarm Nr #" + str(i)) + + data = "ZVEI1: 12345" + bwPacket = decoder.getDecoder(data).decode(data) + + if bwPacket: + bwPacket.printInfo() + bwPacket.addClientData() + bwClient.transmit(str(bwPacket)) + + # todo should we do this in an thread, to not block receiving ??? + # todo but then we should use transmit() and receive() with Lock() + failedTransmits = 0 + while not bwClient.receive() == "[ack]": # wait for ack or timeout + if failedTransmits >= 3: + logging.error("cannot transmit after 5 retires") + break + failedTransmits += 1 + logging.warning("attempt %d to resend packet", failedTransmits) + bwClient.transmit(str(bwPacket)) # try to resend + + logging.debug("ack ok") + + bwClient.disconnect() + break +# test for server #################################### + +except KeyboardInterrupt: # pragma: no cover + logging.warning("Keyboard interrupt") +except SystemExit: # pragma: no cover + logging.error("BOSWatch interrupted by an error") +except: # pragma: no cover + logging.exception("BOSWatch interrupted by an error") +finally: # pragma: no cover + logging.debug("BOSWatch has ended ...") diff --git a/bw_server.py b/bw_server.py new file mode 100644 index 0000000..0ea943c --- /dev/null +++ b/bw_server.py @@ -0,0 +1,177 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" + ____ ____ ______ __ __ __ _____ + / __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ / + / __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ < + / /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ / +/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/ + German BOS Information Script + by Bastian Schroll + +@file: bw_server.py +@date: 09.12.2017 +@author: Bastian Schroll +@description: BOSWatch server application +""" +from boswatch.utils import paths +if not paths.makeDirIfNotExist(paths.LOG_PATH): + print("cannot find/create log directory: %s", paths.LOG_PATH) + exit(1) + +try: + import logging + import logging.config + print(paths.CONFIG_PATH + "logger_server.ini") + logging.config.fileConfig(paths.CONFIG_PATH + "logger_server.ini") + logging.debug("") + logging.debug("######################## NEW LOG ############################") + logging.debug("BOSWatch server has started ...") +except Exception as e: # pragma: no cover + print("cannot load logger") + print(e) + exit(1) + + +try: + logging.debug("Import python modules") + import argparse + logging.debug("- argparse") + # following is temp for testing + import time + import sys + import threading + import threading + + logging.debug("Import BOSWatch modules") + from boswatch.config import Config + from boswatch.network.server import TCPServer + from boswatch.packet.packet import Packet + from boswatch.plugin.pluginManager import PluginManager + from boswatch.descriptor.descriptor import Descriptor + from boswatch.filter.doubeFilter import DoubleFilter + from boswatch.utils import header +except Exception as e: # pragma: no cover + logging.exception("cannot import modules") + print("cannot import modules") + print(e) + exit(1) + +try: + header.logoToLog() + header.infoToLog() + header.logoToScreen() + + logging.debug("parse args") + # With -h or --help you get the Args help + parser = argparse.ArgumentParser(prog="bw_server.py", + description="""BOSWatch is a Python Script to receive and + decode german BOS information with rtl_fm and multimon-NG""", + epilog="""More options you can find in the extern client.ini + file in the folder /config""") + parser.add_argument("-c", "--config", help="Name to configuration File", required=True) + args = parser.parse_args() + + bwConfig = Config() + if bwConfig.loadConfigFile(paths.CONFIG_PATH + args.config, "serverConfig") is False: + logging.exception("cannot load config file") + print("cannot load config file") + exit(1) # without config cannot run + + bwPluginManager = PluginManager() + bwPluginManager.searchPluginDir() + bwPluginManager.importAllPlugins() + bwPluginManager.loadAllPlugins() + + bwDescriptor = Descriptor() + if bwConfig.getBool("Description", "fms"): + bwDescriptor.loadDescription("fms") + if bwConfig.getBool("Description", "pocsag"): + bwDescriptor.loadDescription("pocsag") + if bwConfig.getBool("Description", "zvei"): + bwDescriptor.loadDescription("zvei") + + bwDoubleFilter = DoubleFilter() + + serverPaused = False # flag to pause alarming of server + serverStop = False # flag to stop the whole server application + + # server flags test code + # ---------------------- + # import threading + # def eins(): + # global serverPaused + # serverPaused = True + # def zwei(): + # global serverPaused + # serverPaused = False + def drei(): + global serverStop + serverStop = True + # + # t1 = threading.Timer(1, eins) + # t2 = threading.Timer(5, zwei) + t3 = threading.Timer(15, drei) + # t1.start() + # t2.start() + t3.start() + + bwServer = TCPServer(bwConfig.getInt("Server", "PORT")) + if bwServer.start(): + + while 1: + if serverPaused: + logging.warning("Server pause flag received ...") + logging.debug("But all received packages will be cached!") + packetsOld = 0 + while serverPaused is True: + time.sleep(0.2) # reduce cpu load (run all 200ms) + packetsNew = bwServer.countPacketsInQueue() + if packetsNew is not packetsOld: + logging.debug("%s packet(s) waiting in queue", packetsNew) + packetsOld = packetsNew + logging.warning("Server resumed ...") + + if serverStop: + logging.warning("Server stop flag received ...") + break + + if not bwServer.countPacketsInQueue(): # pause only when no data + time.sleep(0.1) # reduce cpu load (run all 100ms) + + data = bwServer.getDataFromQueue() + if data is not None: + logging.info("get data from %s (waited in queue %0.3f sec.)", data[0], time.time() - data[2]) + logging.debug("%s packet(s) waiting in queue", bwServer.countPacketsInQueue()) + bwPacket = Packet((data[1])) + + if not bwDoubleFilter.filter(bwPacket): + continue + + bwPacket.set("clientIP", data[0]) + bwPacket.addServerData() + + if bwConfig.getBool("Description", bwPacket.get("mode")): + bwDescriptor.addDescriptions(bwPacket) + + bwPluginManager.runAllPlugins(bwPacket) + # print(bwPacket.get("clientVersion")["major"]) + +except KeyboardInterrupt: # pragma: no cover + logging.warning("Keyboard interrupt") +except SystemExit: # pragma: no cover + logging.error("BOSWatch interrupted by an error") +except: # pragma: no cover + logging.exception("BOSWatch interrupted by an error") +finally: # pragma: no cover + # try-except-blocks are necessary because there is a change that the vars + # bwServer or bwPluginManager are not defined in case of an early error + try: + bwServer.stop() + except: # pragma: no cover + pass + try: + bwPluginManager.unloadAllPlugins() + except: # pragma: no cover + pass + logging.debug("BOSWatch has ended ...") diff --git a/test/test_doubleFilter.py b/test/test_doubleFilter.py new file mode 100644 index 0000000..93e4c07 --- /dev/null +++ b/test/test_doubleFilter.py @@ -0,0 +1,28 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +"""! + ____ ____ ______ __ __ __ _____ + / __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ / + / __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ < + / /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ / +/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/ + German BOS Information Script + by Bastian Schroll + +@file: test_doubleFilter.py +@date: 15.12.2017 +@author: Bastian Schroll +@description: Unittests for BOSWatch. File must be _run as "pytest" unittest +""" +import logging + +import boswatch.filter.doubeFilter + + +class Test_DoubleFilter: + + def setup_method(self, method): + logging.debug("[TEST] %s.%s" % (type(self).__name__, method.__name__)) + + def test_none(self): + pass diff --git a/test/test_watchdog.py b/test/test_watchdog.py new file mode 100644 index 0000000..cfcf14e --- /dev/null +++ b/test/test_watchdog.py @@ -0,0 +1,28 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +"""! + ____ ____ ______ __ __ __ _____ + / __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ / + / __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ < + / /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ / +/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/ + German BOS Information Script + by Bastian Schroll + +@file: test_watchdog.py +@date: 15.12.2017 +@author: Bastian Schroll +@description: Unittests for BOSWatch. File must be _run as "pytest" unittest +""" +import logging + +# import boswatch.watchdog.watchdog + + +class Test_Watchdog: + + def setup_method(self, method): + logging.debug("[TEST] %s.%s" % (type(self).__name__, method.__name__)) + + def test_none(self): + pass