Merge branch 'develop' into router

This commit is contained in:
Bastian Schroll 2019-02-28 12:01:46 +01:00
commit 71d87b080f
23 changed files with 381 additions and 504 deletions

View file

@ -1,131 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""!
____ ____ ______ __ __ __ _____
/ __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ /
/ __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ <
/ /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ /
/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/
German BOS Information Script
by Bastian Schroll
@file: config.py
@date: 25.12.2017
@author: Bastian Schroll
@description: Module for the configuration
"""
import logging
import configparser
logging.debug("- %s loaded", __name__)
class Config:
_sharePoints = {}
def __init__(self):
"""!Create a new config object and load the ini file directly"""
self._config = configparser.ConfigParser()
def loadConfigFile(self, configPath, sharePoint=""):
"""!loads a given configuration in the class wide config variable
@param configPath: Path to the config file
@param sharePoint: If you want to share the config set name here
@return True or False"""
logging.debug("load config file from: %s", configPath)
try:
self._config.read(configPath, "utf-8")
if sharePoint:
self._shareConfig(sharePoint)
return True
except: # pragma: no cover
logging.exception("cannot load config file")
return False
def _shareConfig(self, sharePoint):
"""!Shares the configuration
Shares the local _config to the class wide global _sharedConfig
@param sharePoint: Name of the global share point
@return True or False"""
if sharePoint in self._sharePoints:
logging.error("cannot share config - name is always in use: %s", sharePoint)
return False
else:
self._sharePoints[sharePoint] = self._config
logging.debug("add config sharePoint: %s", sharePoint)
return True
def getInt(self, section, key, sharePoint=""):
"""!Method to read a single config entry as integer
@param section: Section to read from
@param key: Value to read
@param sharePoint: Name of the global config share (empty is only local)
@return An Integer or None"""
value = self._get(section, key, sharePoint)
if value is None:
return None
return int(value)
def getBool(self, section, key, sharePoint=""):
"""!Method to read a single config entry as boolean
@param section: Section to read from
@param key: Value to read
@param sharePoint: Name of the global config share (empty is only local)
@return True or False"""
if self._get(section, key, sharePoint).lower() in ["1", "true", "yes"]:
return True
return False
def getStr(self, section, key, sharePoint=""):
"""!Method to read a single config entry as string
@param section: Section to read from
@param key: Value to read
@param sharePoint: Name of the global config share (empty is only local)
@return The value or None"""
value = self._get(section, key, sharePoint)
if value is None:
return None
return str(value)
def _get(self, section, key, sharePoint=""):
"""!Method to read a single config entry
@param section: Section to read from
@param key: Value to read
@param sharePoint: Name of the global config share (empty is only local)
@return The value or None"""
if sharePoint:
try:
return self._sharePoints[sharePoint].get(section, key)
except KeyError:
logging.error("no sharePoint named: %s", sharePoint)
except configparser.NoSectionError:
logging.warning("no shared config section: %s", section)
except configparser.NoOptionError:
logging.warning("no shared config option: %s", key)
except: # pragma: no cover
logging.exception("error while reading shared config")
return None
else:
try:
return self._config.get(section, key)
except configparser.NoSectionError:
logging.warning("no local config section: %s", section)
except configparser.NoOptionError:
logging.warning("no local config option: %s", key)
except: # pragma: no cover
logging.exception("error while reading local config")
return None
def getAllSharepoints(self):
"""!Return a python dict of all set sharepoints
@return Sharepoint dict"""
return self._sharePoints

79
boswatch/configYaml.py Normal file
View file

@ -0,0 +1,79 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""!
____ ____ ______ __ __ __ _____
/ __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ /
/ __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ <
/ /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ /
/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/
German BOS Information Script
by Bastian Schroll
@file: configYaml.py
@date: 27.02.2019
@author: Bastian Schroll
@description: Module for the configuration in yaml format
"""
import logging
import yaml
logging.debug("- %s loaded", __name__)
__sharePoints = {}
def loadConfigFile(configPath, sharePoint=""):
"""!loads a given configuration
@param configPath: Path to the config file
@param sharePoint: If you want to share the config set name here
@return python dict of config or None"""
logging.debug("load config file from: %s", configPath)
try:
with open(configPath) as f:
# use safe_load instead load
config = yaml.safe_load(f)
if sharePoint:
_shareConfig(config, sharePoint)
return config
except: # pragma: no cover
logging.exception("cannot load config file")
return None
def loadConfigSharepoint(sharePoint):
"""!loads a given configuration from an sharepoint
@param sharePoint: Name of the sharepoint
@return python dict of config or None"""
try:
return __sharePoints[sharePoint]
except KeyError:
logging.error("no sharePoint named: %s", sharePoint)
except: # pragma: no cover
logging.exception("error while reading shared config")
return None
def _shareConfig(config, sharePoint):
"""!Shares the configuration
Shares the local _config to the class wide global _sharedConfig
@param config: Python dict of the configuration
@param sharePoint: Name of the global share point
@return True or False"""
if sharePoint in __sharePoints:
logging.error("cannot share config - name is always in use: %s", sharePoint)
return False
else:
__sharePoints[sharePoint] = config
logging.debug("add config sharePoint: %s", sharePoint)
return True
def getAllSharepoints():
"""!Return a python dict of all set sharepoints
@return Sharepoint dict"""
return __sharePoints

View file

@ -18,7 +18,7 @@
import logging
import time
from boswatch.config import Config
from boswatch import configYaml
logging.debug("- %s loaded", __name__)
@ -28,7 +28,7 @@ class DoubleFilter:
def __init__(self):
"""!init"""
self._config = Config()
self._config = configYaml.loadConfigSharepoint("serverConfig")["filter"]["doubleFilter"]
self._filterLists = {}
def filter(self, bwPacket):
@ -57,14 +57,14 @@ class DoubleFilter:
# delete entries that are to old
counter = 0
for listPacket in self._filterLists[bwPacket.get("mode")][1:]: # [1:] skip first entry, thats the new one
if listPacket.get("timestamp") < (time.time() - self._config.getInt("doubleFilter", "IgnoreTime", "serverConfig")):
if listPacket.get("timestamp") < (time.time() - self._config["ignoreTime"]):
self._filterLists[bwPacket.get("mode")].remove(listPacket)
counter += 1
if counter:
logging.debug("%d old entry(s) removed", counter)
# delete last entry if list is to big
if len(self._filterLists[bwPacket.get("mode")]) > self._config.getInt("doubleFilter", "MaxEntry", "serverConfig"):
if len(self._filterLists[bwPacket.get("mode")]) > self._config["maxEntry"]:
logging.debug("MaxEntry reached - delete oldest")
self._filterLists[bwPacket.get("mode")].pop()

View file

@ -101,12 +101,18 @@ class BroadcastServer:
self._serverShutdown = False
self._servePort = servePort
def __del__(self):
if self.isRunning:
self.stop()
while self.isRunning:
pass
def start(self):
"""!Start the broadcast server in a new thread
@return True or False"""
try:
if not self._serverThread:
if not self.isRunning:
logging.debug("start udp broadcast server")
self._serverThread = threading.Thread(target=self._listen)
self._serverThread.name = "BroadServ"
@ -130,7 +136,7 @@ class BroadcastServer:
@return True or False"""
try:
if self._serverThread:
if self.isRunning:
logging.debug("stop udp broadcast server")
self._serverShutdown = True
return True

View file

@ -40,12 +40,15 @@ class TCPClient:
@param port: Server Port (8080)
@return True or False"""
try:
self._sock = socket
self._sock.setdefaulttimeout(self._timeout)
self._sock = socket.create_connection((host, port))
logging.debug("connected to %s:%s", host, port)
return True
if not self.isConnected:
self._sock = socket
self._sock.setdefaulttimeout(self._timeout)
self._sock = socket.create_connection((host, port))
logging.debug("connected to %s:%s", host, port)
return True
else:
logging.warning("client always connected")
return True
except ConnectionRefusedError:
logging.error("cannot connect to %s:%s - connection refused", host, port)
return False
@ -61,9 +64,14 @@ class TCPClient:
@return True or False"""
try:
self._sock.close()
logging.debug("disconnected")
return True
if self.isConnected:
self._sock.close()
self._sock = None
logging.debug("disconnected")
return True
else:
logging.warning("client not connected")
return True
except AttributeError:
logging.error("cannot disconnect - no connection established")
return False
@ -111,3 +119,10 @@ class TCPClient:
except: # pragma: no cover
logging.exception("error while receiving")
return False
@property
def isConnected(self):
"""!Property of client connected state"""
if self._sock:
return True
return False

View file

@ -82,6 +82,10 @@ class TCPServer:
self._clientsConnectedLock = threading.Lock()
self._clientsConnected = {}
def __del__(self):
if self.isRunning:
self.stop()
def start(self, port=8080):
"""!Start a threaded TCP socket server
@ -93,21 +97,23 @@ class TCPServer:
@return True or False"""
try:
self._server = ThreadedTCPServer(("", port), ThreadedTCPRequestHandler)
self._server.timeout = self._timeout
self._server.alarmQueue = self._alarmQueue
if not self.isRunning:
self._server = ThreadedTCPServer(("", port), ThreadedTCPRequestHandler)
self._server.timeout = self._timeout
self._server.alarmQueue = self._alarmQueue
self._server.clientsConnctedLock = self._clientsConnectedLock
self._server.clientsConnected = self._clientsConnected
self._server.clientsConnctedLock = self._clientsConnectedLock
self._server.clientsConnected = self._clientsConnected
self._server_thread = threading.Thread(target=self._server.serve_forever)
self._server_thread.name = "Thread-BWServer"
self._server_thread.daemon = True
self._server_thread.start()
logging.debug("TCPServer started in Thread: %s", self._server_thread.name)
return True
except OSError:
logging.exception("server always running?")
self._server_thread = threading.Thread(target=self._server.serve_forever)
self._server_thread.name = "Thread-BWServer"
self._server_thread.daemon = True
self._server_thread.start()
logging.debug("TCPServer started in Thread: %s", self._server_thread.name)
return True
else:
logging.warning("server always started")
return True
except: # pragma: no cover
logging.exception("cannot start the server")
return False
@ -117,16 +123,17 @@ class TCPServer:
@return True or False"""
try:
self._server.shutdown()
self._server_thread.join()
self._server_thread = None
self._server.socket.close()
self._server = None
logging.debug("TCPServer stopped")
return True
except AttributeError:
logging.exception("cannot stop - server not started?")
return False
if self.isRunning:
self._server.shutdown()
self._server_thread.join()
self._server_thread = None
self._server.socket.close()
self._server = None
logging.debug("TCPServer stopped")
return True
else:
logging.warning("server always stopped")
return True
except: # pragma: no cover
logging.exception("cannot stop the server")
return False
@ -147,3 +154,10 @@ class TCPServer:
# todo return full list or write a print/debug method?
with self._clientsConnectedLock: # because our list is not threadsafe
return self._clientsConnected
@property
def isRunning(self):
"""!Property of server running state"""
if self._server:
return True
return False

View file

@ -16,7 +16,7 @@
"""
import logging
import time
from boswatch.config import Config
from boswatch import configYaml
from boswatch import version
logging.debug("- %s loaded", __name__)
@ -73,14 +73,14 @@ class Packet:
- clientBranch
- inputSource
- frequency"""
config = Config()
config = configYaml.loadConfigSharepoint("clientConfig")
logging.debug("add client data to bwPacket")
self.set("clientName", config.getStr("Client", "Name", "clientConfig"))
self.set("clientName", config["client"]["name"])
self.set("clientVersion", version.client)
self.set("clientBuildDate", version.date)
self.set("clientBranch", version.branch)
self.set("inputSource", config.getStr("Client", "InputSource", "clientConfig"))
self.set("frequency", config.getStr("Stick", "Frequency", "clientConfig"))
self.set("inputSource", config["client"]["inputSource"])
self.set("frequency", config["inputSource"]["sdr"]["frequency"])
def addServerData(self):
"""!Add the server information to the decoded data
@ -90,9 +90,9 @@ class Packet:
- serverVersion
- serverBuildDate
- serverBranch"""
config = Config()
config = configYaml.loadConfigSharepoint("serverConfig")
logging.debug("add server data to bwPacket")
self.set("serverName", config.getStr("Server", "Name", "serverConfig"))
self.set("serverName", config["server"]["name"])
self.set("serverVersion", version.server)
self.set("serverBuildDate", version.date)
self.set("serverBranch", version.branch)

View file

@ -18,7 +18,7 @@ import logging
import time
from boswatch.utils import paths
from boswatch.config import Config
from boswatch import configYaml
from boswatch.utils import wildcard
logging.debug("- %s loaded", __name__)
@ -52,9 +52,8 @@ class Plugin:
self._alarmErrorCount = 0
self._teardownErrorCount = 0
if paths.fileExist(paths.PLUGIN_PATH + pluginName + "/" + pluginName + ".ini"):
self.config = Config()
self.config.loadConfigFile(paths.PLUGIN_PATH + pluginName + "/" + pluginName + ".ini")
if paths.fileExist(paths.PLUGIN_PATH + pluginName + "/" + pluginName + ".yaml"):
self.config = configYaml.loadConfigFile(paths.PLUGIN_PATH + pluginName + "/" + pluginName + ".yaml")
else:
logging.debug("no config for %s found", pluginName)

View file

@ -20,7 +20,7 @@ import os
import time
import importlib
from boswatch.config import Config
from boswatch import configYaml
from boswatch.utils import paths
logging.debug("- %s loaded", __name__)
@ -33,7 +33,7 @@ class PluginManager:
def __init__(self):
"""!init comment"""
self._config = Config()
self._config = configYaml.loadConfigSharepoint("serverConfig")
self._pluginList = []
def searchPluginDir(self):
@ -45,7 +45,7 @@ class PluginManager:
if not os.path.isdir(location) or not name + ".py" in os.listdir(location):
continue
pluginPriority = self._config.getInt("Plugins", name, "serverConfig")
pluginPriority = self._config["plugins"][name]
if pluginPriority is None:
logging.warning("no entry in server config for plugin: %s", name)