split config and property code, first test
This commit is contained in:
parent
7948b7bfa1
commit
541c38151f
@ -1,6 +1,6 @@
|
|||||||
from http.server import HTTPServer
|
from http.server import HTTPServer
|
||||||
from owrx.http import RequestHandler
|
from owrx.http import RequestHandler
|
||||||
from owrx.config import PropertyManager, Config
|
from owrx.config import Config
|
||||||
from owrx.feature import FeatureDetector
|
from owrx.feature import FeatureDetector
|
||||||
from owrx.sdr import SdrService
|
from owrx.sdr import SdrService
|
||||||
from socketserver import ThreadingMixIn
|
from socketserver import ThreadingMixIn
|
||||||
@ -36,7 +36,7 @@ Support and info: https://groups.io/g/openwebrx
|
|||||||
|
|
||||||
logger.info("OpenWebRX version {0} starting up...".format(openwebrx_version))
|
logger.info("OpenWebRX version {0} starting up...".format(openwebrx_version))
|
||||||
|
|
||||||
pm = PropertyManager.getSharedInstance().loadConfig()
|
pm = Config.get()
|
||||||
|
|
||||||
configErrors = Config.validateConfig()
|
configErrors = Config.validateConfig()
|
||||||
if configErrors:
|
if configErrors:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
from owrx.metrics import Metrics, DirectMetric
|
from owrx.metrics import Metrics, DirectMetric
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ class ClientRegistry(object):
|
|||||||
c.write_clients(n)
|
c.write_clients(n)
|
||||||
|
|
||||||
def addClient(self, client):
|
def addClient(self, client):
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
if len(self.clients) >= pm["max_clients"]:
|
if len(self.clients) >= pm["max_clients"]:
|
||||||
raise TooManyClientsException()
|
raise TooManyClientsException()
|
||||||
self.clients.append(client)
|
self.clients.append(client)
|
||||||
|
173
owrx/config.py
173
owrx/config.py
@ -1,155 +1,15 @@
|
|||||||
|
from owrx.property import PropertyManager
|
||||||
import importlib.util
|
import importlib.util
|
||||||
import logging
|
|
||||||
import os
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Subscription(object):
|
|
||||||
def __init__(self, subscriptee, subscriber):
|
|
||||||
self.subscriptee = subscriptee
|
|
||||||
self.subscriber = subscriber
|
|
||||||
|
|
||||||
def call(self, *args, **kwargs):
|
|
||||||
self.subscriber(*args, **kwargs)
|
|
||||||
|
|
||||||
def cancel(self):
|
|
||||||
self.subscriptee.unwire(self)
|
|
||||||
|
|
||||||
|
|
||||||
class Property(object):
|
|
||||||
def __init__(self, value=None):
|
|
||||||
self.value = value
|
|
||||||
self.subscribers = []
|
|
||||||
|
|
||||||
def getValue(self):
|
|
||||||
return self.value
|
|
||||||
|
|
||||||
def setValue(self, value):
|
|
||||||
if self.value == value:
|
|
||||||
return self
|
|
||||||
self.value = value
|
|
||||||
for c in self.subscribers:
|
|
||||||
try:
|
|
||||||
c.call(self.value)
|
|
||||||
except Exception as e:
|
|
||||||
logger.exception(e)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def wire(self, callback):
|
|
||||||
sub = Subscription(self, callback)
|
|
||||||
self.subscribers.append(sub)
|
|
||||||
if not self.value is None:
|
|
||||||
sub.call(self.value)
|
|
||||||
return sub
|
|
||||||
|
|
||||||
def unwire(self, sub):
|
|
||||||
try:
|
|
||||||
self.subscribers.remove(sub)
|
|
||||||
except ValueError:
|
|
||||||
# happens when already removed before
|
|
||||||
pass
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigNotFoundException(Exception):
|
class ConfigNotFoundException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PropertyManager(object):
|
|
||||||
sharedInstance = None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def getSharedInstance():
|
|
||||||
if PropertyManager.sharedInstance is None:
|
|
||||||
PropertyManager.sharedInstance = PropertyManager()
|
|
||||||
return PropertyManager.sharedInstance
|
|
||||||
|
|
||||||
def collect(self, *props):
|
|
||||||
return PropertyManager(
|
|
||||||
{name: self.getProperty(name) if self.hasProperty(name) else Property() for name in props}
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self, properties=None):
|
|
||||||
self.properties = {}
|
|
||||||
self.subscribers = []
|
|
||||||
if properties is not None:
|
|
||||||
for (name, prop) in properties.items():
|
|
||||||
self.add(name, prop)
|
|
||||||
|
|
||||||
def add(self, name, prop):
|
|
||||||
self.properties[name] = prop
|
|
||||||
|
|
||||||
def fireCallbacks(value):
|
|
||||||
for c in self.subscribers:
|
|
||||||
try:
|
|
||||||
c.call(name, value)
|
|
||||||
except Exception as e:
|
|
||||||
logger.exception(e)
|
|
||||||
|
|
||||||
prop.wire(fireCallbacks)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __contains__(self, name):
|
|
||||||
return self.hasProperty(name)
|
|
||||||
|
|
||||||
def __getitem__(self, name):
|
|
||||||
return self.getPropertyValue(name)
|
|
||||||
|
|
||||||
def __setitem__(self, name, value):
|
|
||||||
if not self.hasProperty(name):
|
|
||||||
self.add(name, Property())
|
|
||||||
self.getProperty(name).setValue(value)
|
|
||||||
|
|
||||||
def __dict__(self):
|
|
||||||
return {k: v.getValue() for k, v in self.properties.items()}
|
|
||||||
|
|
||||||
def hasProperty(self, name):
|
|
||||||
return name in self.properties
|
|
||||||
|
|
||||||
def getProperty(self, name):
|
|
||||||
if not self.hasProperty(name):
|
|
||||||
self.add(name, Property())
|
|
||||||
return self.properties[name]
|
|
||||||
|
|
||||||
def getPropertyValue(self, name):
|
|
||||||
return self.getProperty(name).getValue()
|
|
||||||
|
|
||||||
def wire(self, callback):
|
|
||||||
sub = Subscription(self, callback)
|
|
||||||
self.subscribers.append(sub)
|
|
||||||
return sub
|
|
||||||
|
|
||||||
def unwire(self, sub):
|
|
||||||
try:
|
|
||||||
self.subscribers.remove(sub)
|
|
||||||
except ValueError:
|
|
||||||
# happens when already removed before
|
|
||||||
pass
|
|
||||||
return self
|
|
||||||
|
|
||||||
def defaults(self, other_pm):
|
|
||||||
for (key, p) in self.properties.items():
|
|
||||||
if p.getValue() is None:
|
|
||||||
p.setValue(other_pm[key])
|
|
||||||
return self
|
|
||||||
|
|
||||||
def loadConfig(self):
|
|
||||||
for file in ["/etc/openwebrx/config_webrx.py", "./config_webrx.py"]:
|
|
||||||
try:
|
|
||||||
spec = importlib.util.spec_from_file_location("config_webrx", file)
|
|
||||||
cfg = importlib.util.module_from_spec(spec)
|
|
||||||
spec.loader.exec_module(cfg)
|
|
||||||
for name, value in cfg.__dict__.items():
|
|
||||||
if name.startswith("__"):
|
|
||||||
continue
|
|
||||||
self[name] = value
|
|
||||||
return self
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
raise ConfigNotFoundException("no usable config found! please make sure you have a valid configuration file!")
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigError(object):
|
class ConfigError(object):
|
||||||
def __init__(self, key, message):
|
def __init__(self, key, message):
|
||||||
self.key = key
|
self.key = key
|
||||||
@ -160,9 +20,34 @@ class ConfigError(object):
|
|||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
|
sharedConfig = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _loadConfig():
|
||||||
|
pm = PropertyManager()
|
||||||
|
for file in ["/etc/openwebrx/config_webrx.py", "./config_webrx.py"]:
|
||||||
|
try:
|
||||||
|
spec = importlib.util.spec_from_file_location("config_webrx", file)
|
||||||
|
cfg = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(cfg)
|
||||||
|
for name, value in cfg.__dict__.items():
|
||||||
|
if name.startswith("__"):
|
||||||
|
continue
|
||||||
|
pm[name] = value
|
||||||
|
return pm
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
raise ConfigNotFoundException("no usable config found! please make sure you have a valid configuration file!")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get():
|
||||||
|
if Config.sharedConfig is None:
|
||||||
|
Config.sharedConfig = Config._loadConfig()
|
||||||
|
return Config.sharedConfig
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validateConfig():
|
def validateConfig():
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
errors = [
|
errors = [
|
||||||
Config.checkTempDirectory(pm)
|
Config.checkTempDirectory(pm)
|
||||||
]
|
]
|
||||||
@ -172,7 +57,7 @@ class Config:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def checkTempDirectory(pm: PropertyManager):
|
def checkTempDirectory(pm: PropertyManager):
|
||||||
key = "temporary_directory"
|
key = "temporary_directory"
|
||||||
if not key in pm or pm[key] is None:
|
if key not in pm or pm[key] is None:
|
||||||
return ConfigError(key, "temporary directory is not set")
|
return ConfigError(key, "temporary directory is not set")
|
||||||
if not os.path.exists(pm[key]):
|
if not os.path.exists(pm[key]):
|
||||||
return ConfigError(key, "temporary directory doesn't exist")
|
return ConfigError(key, "temporary directory doesn't exist")
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
from owrx.dsp import DspManager
|
from owrx.dsp import DspManager
|
||||||
from owrx.cpu import CpuUsageThread
|
from owrx.cpu import CpuUsageThread
|
||||||
from owrx.sdr import SdrService
|
from owrx.sdr import SdrService
|
||||||
@ -93,7 +93,7 @@ class OpenWebRxReceiverClient(Client):
|
|||||||
self.close()
|
self.close()
|
||||||
raise
|
raise
|
||||||
|
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
|
|
||||||
self.setSdr()
|
self.setSdr()
|
||||||
|
|
||||||
@ -198,7 +198,7 @@ class OpenWebRxReceiverClient(Client):
|
|||||||
configProps = (
|
configProps = (
|
||||||
self.sdr.getProps()
|
self.sdr.getProps()
|
||||||
.collect(*OpenWebRxReceiverClient.config_keys)
|
.collect(*OpenWebRxReceiverClient.config_keys)
|
||||||
.defaults(PropertyManager.getSharedInstance())
|
.defaults(Config.get())
|
||||||
)
|
)
|
||||||
|
|
||||||
def sendConfig(key, value):
|
def sendConfig(key, value):
|
||||||
@ -247,15 +247,16 @@ class OpenWebRxReceiverClient(Client):
|
|||||||
self.sdr.removeSpectrumClient(self)
|
self.sdr.removeSpectrumClient(self)
|
||||||
|
|
||||||
def setParams(self, params):
|
def setParams(self, params):
|
||||||
|
config = Config.get()
|
||||||
# allow direct configuration only if enabled in the config
|
# allow direct configuration only if enabled in the config
|
||||||
keys = PropertyManager.getSharedInstance()["configurable_keys"]
|
keys = config["configurable_keys"]
|
||||||
if not keys:
|
if not keys:
|
||||||
return
|
return
|
||||||
# only the keys in the protected property manager can be overridden from the web
|
# only the keys in the protected property manager can be overridden from the web
|
||||||
protected = (
|
protected = (
|
||||||
self.sdr.getProps()
|
self.sdr.getProps()
|
||||||
.collect(*keys)
|
.collect(*keys)
|
||||||
.defaults(PropertyManager.getSharedInstance())
|
.defaults(config)
|
||||||
)
|
)
|
||||||
for key, value in params.items():
|
for key, value in params.items():
|
||||||
protected[key] = value
|
protected[key] = value
|
||||||
@ -333,7 +334,7 @@ class MapConnection(Client):
|
|||||||
def __init__(self, conn):
|
def __init__(self, conn):
|
||||||
super().__init__(conn)
|
super().__init__(conn)
|
||||||
|
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
self.write_config(pm.collect("google_maps_api_key", "receiver_gps", "map_position_retention_time").__dict__())
|
self.write_config(pm.collect("google_maps_api_key", "receiver_gps", "map_position_retention_time").__dict__())
|
||||||
|
|
||||||
Map.getSharedInstance().addClient(self)
|
Map.getSharedInstance().addClient(self)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from . import Controller
|
from . import Controller
|
||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
@ -47,7 +47,7 @@ class OwrxAssetsController(AssetsController):
|
|||||||
|
|
||||||
class AprsSymbolsController(AssetsController):
|
class AprsSymbolsController(AssetsController):
|
||||||
def __init__(self, handler, request, options):
|
def __init__(self, handler, request, options):
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
path = pm["aprs_symbols_path"]
|
path = pm["aprs_symbols_path"]
|
||||||
if not path.endswith("/"):
|
if not path.endswith("/"):
|
||||||
path += "/"
|
path += "/"
|
||||||
|
@ -2,14 +2,14 @@ from . import Controller
|
|||||||
from owrx.client import ClientRegistry
|
from owrx.client import ClientRegistry
|
||||||
from owrx.version import openwebrx_version
|
from owrx.version import openwebrx_version
|
||||||
from owrx.sdr import SdrService
|
from owrx.sdr import SdrService
|
||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
|
||||||
class StatusController(Controller):
|
class StatusController(Controller):
|
||||||
def indexAction(self):
|
def indexAction(self):
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
# TODO keys that have been left out since they are no longer simple strings: sdr_hw, bands, antenna
|
# TODO keys that have been left out since they are no longer simple strings: sdr_hw, bands, antenna
|
||||||
vars = {
|
vars = {
|
||||||
"status": "active",
|
"status": "active",
|
||||||
@ -42,7 +42,7 @@ class StatusController(Controller):
|
|||||||
return stats
|
return stats
|
||||||
|
|
||||||
def jsonAction(self):
|
def jsonAction(self):
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
|
|
||||||
gps = pm["receiver_gps"]
|
gps = pm["receiver_gps"]
|
||||||
status = {
|
status = {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
from owrx.meta import MetaParser
|
from owrx.meta import MetaParser
|
||||||
from owrx.wsjt import WsjtParser
|
from owrx.wsjt import WsjtParser
|
||||||
from owrx.aprs import AprsParser
|
from owrx.aprs import AprsParser
|
||||||
@ -39,7 +39,7 @@ class DspManager(csdr.output):
|
|||||||
"temporary_directory",
|
"temporary_directory",
|
||||||
"center_freq",
|
"center_freq",
|
||||||
)
|
)
|
||||||
.defaults(PropertyManager.getSharedInstance())
|
.defaults(Config.get())
|
||||||
)
|
)
|
||||||
|
|
||||||
self.dsp = csdr.dsp(self)
|
self.dsp = csdr.dsp(self)
|
||||||
|
@ -4,7 +4,7 @@ from operator import and_, or_
|
|||||||
import re
|
import re
|
||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
import inspect
|
import inspect
|
||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
import shlex
|
import shlex
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -95,7 +95,7 @@ class FeatureDetector(object):
|
|||||||
return inspect.getdoc(self._get_requirement_method(requirement))
|
return inspect.getdoc(self._get_requirement_method(requirement))
|
||||||
|
|
||||||
def command_is_runnable(self, command):
|
def command_is_runnable(self, command):
|
||||||
tmp_dir = PropertyManager.getSharedInstance()["temporary_directory"]
|
tmp_dir = Config.get()["temporary_directory"]
|
||||||
cmd = shlex.split(command)
|
cmd = shlex.split(command)
|
||||||
try:
|
try:
|
||||||
process = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=tmp_dir)
|
process = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, cwd=tmp_dir)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
from csdr import csdr
|
from csdr import csdr
|
||||||
import threading
|
import threading
|
||||||
from owrx.source import SdrSource
|
from owrx.source import SdrSource
|
||||||
@ -23,7 +23,7 @@ class SpectrumThread(csdr.output):
|
|||||||
"csdr_print_bufsizes",
|
"csdr_print_bufsizes",
|
||||||
"csdr_through",
|
"csdr_through",
|
||||||
"temporary_directory",
|
"temporary_directory",
|
||||||
).defaults(PropertyManager.getSharedInstance())
|
).defaults(Config.get())
|
||||||
|
|
||||||
self.dsp = dsp = csdr.dsp(self)
|
self.dsp = dsp = csdr.dsp(self)
|
||||||
dsp.nc_port = self.sdrSource.getPort()
|
dsp.nc_port = self.sdrSource.getPort()
|
||||||
|
@ -2,7 +2,7 @@ import socket
|
|||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ TFESC = 0xDD
|
|||||||
|
|
||||||
class DirewolfConfig(object):
|
class DirewolfConfig(object):
|
||||||
def getConfig(self, port, is_service):
|
def getConfig(self, port, is_service):
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
|
|
||||||
config = """
|
config = """
|
||||||
ACHANNELS 1
|
ACHANNELS 1
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import threading, time
|
from owrx.config import Config
|
||||||
from owrx.config import PropertyManager
|
|
||||||
from owrx.bands import Band
|
from owrx.bands import Band
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -105,7 +106,7 @@ class Map(object):
|
|||||||
# TODO broadcast removal to clients
|
# TODO broadcast removal to clients
|
||||||
|
|
||||||
def removeOldPositions(self):
|
def removeOldPositions(self):
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
retention = timedelta(seconds=pm["map_position_retention_time"])
|
retention = timedelta(seconds=pm["map_position_retention_time"])
|
||||||
cutoff = datetime.now() - retention
|
cutoff = datetime.now() - retention
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
from urllib import request
|
from urllib import request
|
||||||
import json
|
import json
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
@ -54,7 +54,7 @@ class DmrMetaEnricher(object):
|
|||||||
del self.threads[id]
|
del self.threads[id]
|
||||||
|
|
||||||
def enrich(self, meta):
|
def enrich(self, meta):
|
||||||
if not PropertyManager.getSharedInstance()["digital_voice_dmr_id_lookup"]:
|
if not Config.get()["digital_voice_dmr_id_lookup"]:
|
||||||
return None
|
return None
|
||||||
if not "source" in meta:
|
if not "source" in meta:
|
||||||
return None
|
return None
|
||||||
|
121
owrx/property/__init__.py
Normal file
121
owrx/property/__init__.py
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Subscription(object):
|
||||||
|
def __init__(self, subscriptee, subscriber):
|
||||||
|
self.subscriptee = subscriptee
|
||||||
|
self.subscriber = subscriber
|
||||||
|
|
||||||
|
def call(self, *args, **kwargs):
|
||||||
|
self.subscriber(*args, **kwargs)
|
||||||
|
|
||||||
|
def cancel(self):
|
||||||
|
self.subscriptee.unwire(self)
|
||||||
|
|
||||||
|
|
||||||
|
class Property(object):
|
||||||
|
def __init__(self, value=None):
|
||||||
|
self.value = value
|
||||||
|
self.subscribers = []
|
||||||
|
|
||||||
|
def getValue(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
def setValue(self, value):
|
||||||
|
if self.value == value:
|
||||||
|
return self
|
||||||
|
self.value = value
|
||||||
|
for c in self.subscribers:
|
||||||
|
try:
|
||||||
|
c.call(self.value)
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def wire(self, callback):
|
||||||
|
sub = Subscription(self, callback)
|
||||||
|
self.subscribers.append(sub)
|
||||||
|
if self.value is not None:
|
||||||
|
sub.call(self.value)
|
||||||
|
return sub
|
||||||
|
|
||||||
|
def unwire(self, sub):
|
||||||
|
try:
|
||||||
|
self.subscribers.remove(sub)
|
||||||
|
except ValueError:
|
||||||
|
# happens when already removed before
|
||||||
|
pass
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyManager(object):
|
||||||
|
def collect(self, *props):
|
||||||
|
return PropertyManager(
|
||||||
|
{name: self.getProperty(name) if self.hasProperty(name) else Property() for name in props}
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, properties=None):
|
||||||
|
self.properties = {}
|
||||||
|
self.subscribers = []
|
||||||
|
if properties is not None:
|
||||||
|
for (name, prop) in properties.items():
|
||||||
|
self.add(name, prop)
|
||||||
|
|
||||||
|
def add(self, name, prop):
|
||||||
|
self.properties[name] = prop
|
||||||
|
|
||||||
|
def fireCallbacks(value):
|
||||||
|
for c in self.subscribers:
|
||||||
|
try:
|
||||||
|
c.call(name, value)
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
|
||||||
|
prop.wire(fireCallbacks)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __contains__(self, name):
|
||||||
|
return self.hasProperty(name)
|
||||||
|
|
||||||
|
def __getitem__(self, name):
|
||||||
|
return self.getPropertyValue(name)
|
||||||
|
|
||||||
|
def __setitem__(self, name, value):
|
||||||
|
if not self.hasProperty(name):
|
||||||
|
self.add(name, Property())
|
||||||
|
self.getProperty(name).setValue(value)
|
||||||
|
|
||||||
|
def __dict__(self):
|
||||||
|
return {k: v.getValue() for k, v in self.properties.items()}
|
||||||
|
|
||||||
|
def hasProperty(self, name):
|
||||||
|
return name in self.properties
|
||||||
|
|
||||||
|
def getProperty(self, name):
|
||||||
|
if not self.hasProperty(name):
|
||||||
|
self.add(name, Property())
|
||||||
|
return self.properties[name]
|
||||||
|
|
||||||
|
def getPropertyValue(self, name):
|
||||||
|
return self.getProperty(name).getValue()
|
||||||
|
|
||||||
|
def wire(self, callback):
|
||||||
|
sub = Subscription(self, callback)
|
||||||
|
self.subscribers.append(sub)
|
||||||
|
return sub
|
||||||
|
|
||||||
|
def unwire(self, sub):
|
||||||
|
try:
|
||||||
|
self.subscribers.remove(sub)
|
||||||
|
except ValueError:
|
||||||
|
# happens when already removed before
|
||||||
|
pass
|
||||||
|
return self
|
||||||
|
|
||||||
|
def defaults(self, other_pm):
|
||||||
|
for (key, p) in self.properties.items():
|
||||||
|
if p.getValue() is None:
|
||||||
|
p.setValue(other_pm[key])
|
||||||
|
return self
|
@ -5,7 +5,7 @@ import random
|
|||||||
import socket
|
import socket
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from operator import and_
|
from operator import and_
|
||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
from owrx.version import openwebrx_version
|
from owrx.version import openwebrx_version
|
||||||
from owrx.locator import Locator
|
from owrx.locator import Locator
|
||||||
from owrx.metrics import Metrics, CounterMetric
|
from owrx.metrics import Metrics, CounterMetric
|
||||||
@ -36,7 +36,7 @@ class PskReporter(object):
|
|||||||
def getSharedInstance():
|
def getSharedInstance():
|
||||||
with PskReporter.creationLock:
|
with PskReporter.creationLock:
|
||||||
if PskReporter.sharedInstance is None:
|
if PskReporter.sharedInstance is None:
|
||||||
if PropertyManager.getSharedInstance()["pskreporter_enabled"]:
|
if Config.get()["pskreporter_enabled"]:
|
||||||
PskReporter.sharedInstance = PskReporter()
|
PskReporter.sharedInstance = PskReporter()
|
||||||
else:
|
else:
|
||||||
PskReporter.sharedInstance = PskReporterDummy()
|
PskReporter.sharedInstance = PskReporterDummy()
|
||||||
@ -181,7 +181,7 @@ class Uploader(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def getReceiverInformation(self):
|
def getReceiverInformation(self):
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
callsign = pm["pskreporter_callsign"]
|
callsign = pm["pskreporter_callsign"]
|
||||||
locator = Locator.fromCoordinates(pm["receiver_gps"])
|
locator = Locator.fromCoordinates(pm["receiver_gps"])
|
||||||
decodingSoftware = "OpenWebRX " + openwebrx_version
|
decodingSoftware = "OpenWebRX " + openwebrx_version
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
|
from owrx.property import PropertyManager
|
||||||
from owrx.feature import FeatureDetector, UnknownFeatureException
|
from owrx.feature import FeatureDetector, UnknownFeatureException
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -14,7 +15,7 @@ class SdrService(object):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def loadProps():
|
def loadProps():
|
||||||
if SdrService.sdrProps is None:
|
if SdrService.sdrProps is None:
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
featureDetector = FeatureDetector()
|
featureDetector = FeatureDetector()
|
||||||
|
|
||||||
def loadIntoPropertyManager(dict: dict):
|
def loadIntoPropertyManager(dict: dict):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
from urllib import request, parse
|
from urllib import request, parse
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -14,7 +14,7 @@ class SdrHuUpdater(threading.Thread):
|
|||||||
super().__init__(daemon=True)
|
super().__init__(daemon=True)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
pm = PropertyManager.getSharedInstance().collect("server_hostname", "web_port", "sdrhu_key")
|
pm = Config.get().collect("server_hostname", "web_port", "sdrhu_key")
|
||||||
data = parse.urlencode({
|
data = parse.urlencode({
|
||||||
"url": "http://{server_hostname}:{web_port}".format(**pm.__dict__()),
|
"url": "http://{server_hostname}:{web_port}".format(**pm.__dict__()),
|
||||||
"apikey": pm["sdrhu_key"]
|
"apikey": pm["sdrhu_key"]
|
||||||
|
@ -5,9 +5,10 @@ from owrx.bands import Bandplan
|
|||||||
from csdr.csdr import dsp, output
|
from csdr.csdr import dsp, output
|
||||||
from owrx.wsjt import WsjtParser
|
from owrx.wsjt import WsjtParser
|
||||||
from owrx.aprs import AprsParser
|
from owrx.aprs import AprsParser
|
||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
from owrx.source.resampler import Resampler
|
from owrx.source.resampler import Resampler
|
||||||
from owrx.feature import FeatureDetector
|
from owrx.feature import FeatureDetector
|
||||||
|
from owrx.property import PropertyManager
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
from .schedule import ServiceScheduler
|
from .schedule import ServiceScheduler
|
||||||
|
|
||||||
@ -96,7 +97,7 @@ class ServiceHandler(object):
|
|||||||
# this looks overly complicated... but i'd like modes with no requirements to be always available without
|
# this looks overly complicated... but i'd like modes with no requirements to be always available without
|
||||||
# being listed in the hash above
|
# being listed in the hash above
|
||||||
unavailable = [mode for mode, req in requirements.items() if not fd.is_available(req)]
|
unavailable = [mode for mode, req in requirements.items() if not fd.is_available(req)]
|
||||||
configured = PropertyManager.getSharedInstance()["services_decoders"]
|
configured = Config.get()["services_decoders"]
|
||||||
available = [mode for mode in configured if mode not in unavailable]
|
available = [mode for mode in configured if mode not in unavailable]
|
||||||
|
|
||||||
return mode in available
|
return mode in available
|
||||||
@ -260,7 +261,7 @@ class Services(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def start():
|
def start():
|
||||||
if not PropertyManager.getSharedInstance()["services_enabled"]:
|
if not Config.get()["services_enabled"]:
|
||||||
return
|
return
|
||||||
for source in SdrService.getSources().values():
|
for source in SdrService.getSources().values():
|
||||||
props = source.getProps()
|
props = source.getProps()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from datetime import datetime, timezone, timedelta
|
from datetime import datetime, timezone, timedelta
|
||||||
from owrx.source import SdrSource
|
from owrx.source import SdrSource
|
||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
import threading
|
import threading
|
||||||
import math
|
import math
|
||||||
from abc import ABC, ABCMeta, abstractmethod
|
from abc import ABC, ABCMeta, abstractmethod
|
||||||
@ -134,7 +134,7 @@ class DaylightSchedule(TimerangeSchedule):
|
|||||||
self.schedule = scheduleDict
|
self.schedule = scheduleDict
|
||||||
|
|
||||||
def getSunTimes(self, date):
|
def getSunTimes(self, date):
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
lat, lng = pm["receiver_gps"]
|
lat, lng = pm["receiver_gps"]
|
||||||
degtorad = math.pi / 180
|
degtorad = math.pi / 180
|
||||||
radtodeg = 180 / math.pi
|
radtodeg = 180 / math.pi
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
import threading
|
import threading
|
||||||
import subprocess
|
import subprocess
|
||||||
import os
|
import os
|
||||||
@ -35,7 +35,7 @@ class SdrSource(ABC):
|
|||||||
self.props = props
|
self.props = props
|
||||||
self.profile_id = None
|
self.profile_id = None
|
||||||
self.activateProfile()
|
self.activateProfile()
|
||||||
self.rtlProps = self.props.collect(*self.getEventNames()).defaults(PropertyManager.getSharedInstance())
|
self.rtlProps = self.props.collect(*self.getEventNames()).defaults(Config.get())
|
||||||
self.wireEvents()
|
self.wireEvents()
|
||||||
self.commandMapper = None
|
self.commandMapper = None
|
||||||
|
|
||||||
|
@ -7,8 +7,7 @@ from multiprocessing.connection import Pipe
|
|||||||
from owrx.map import Map, LocatorLocation
|
from owrx.map import Map, LocatorLocation
|
||||||
import re
|
import re
|
||||||
from queue import Queue, Full
|
from queue import Queue, Full
|
||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
from owrx.bands import Bandplan
|
|
||||||
from owrx.metrics import Metrics, CounterMetric, DirectMetric
|
from owrx.metrics import Metrics, CounterMetric, DirectMetric
|
||||||
from owrx.pskreporter import PskReporter
|
from owrx.pskreporter import PskReporter
|
||||||
from owrx.parser import Parser
|
from owrx.parser import Parser
|
||||||
@ -45,7 +44,7 @@ class WsjtQueue(Queue):
|
|||||||
def getSharedInstance():
|
def getSharedInstance():
|
||||||
with WsjtQueue.creationLock:
|
with WsjtQueue.creationLock:
|
||||||
if WsjtQueue.sharedInstance is None:
|
if WsjtQueue.sharedInstance is None:
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
WsjtQueue.sharedInstance = WsjtQueue(maxsize=pm["wsjt_queue_length"], workers=pm["wsjt_queue_workers"])
|
WsjtQueue.sharedInstance = WsjtQueue(maxsize=pm["wsjt_queue_length"], workers=pm["wsjt_queue_workers"])
|
||||||
return WsjtQueue.sharedInstance
|
return WsjtQueue.sharedInstance
|
||||||
|
|
||||||
@ -89,7 +88,7 @@ class WsjtQueue(Queue):
|
|||||||
class WsjtChopper(threading.Thread):
|
class WsjtChopper(threading.Thread):
|
||||||
def __init__(self, source):
|
def __init__(self, source):
|
||||||
self.source = source
|
self.source = source
|
||||||
self.tmp_dir = PropertyManager.getSharedInstance()["temporary_directory"]
|
self.tmp_dir = Config.get()["temporary_directory"]
|
||||||
(self.wavefilename, self.wavefile) = self.getWaveFile()
|
(self.wavefilename, self.wavefile) = self.getWaveFile()
|
||||||
self.switchingLock = threading.Lock()
|
self.switchingLock = threading.Lock()
|
||||||
self.timer = None
|
self.timer = None
|
||||||
@ -193,7 +192,7 @@ class WsjtChopper(threading.Thread):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def decoding_depth(self, mode):
|
def decoding_depth(self, mode):
|
||||||
pm = PropertyManager.getSharedInstance()
|
pm = Config.get()
|
||||||
# mode-specific setting?
|
# mode-specific setting?
|
||||||
if "wsjt_decoding_depths" in pm and mode in pm["wsjt_decoding_depths"]:
|
if "wsjt_decoding_depths" in pm and mode in pm["wsjt_decoding_depths"]:
|
||||||
return pm["wsjt_decoding_depths"][mode]
|
return pm["wsjt_decoding_depths"][mode]
|
||||||
|
4
sdrhu.py
4
sdrhu.py
@ -22,14 +22,14 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from owrx.sdrhu import SdrHuUpdater
|
from owrx.sdrhu import SdrHuUpdater
|
||||||
from owrx.config import PropertyManager
|
from owrx.config import Config
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
pm = PropertyManager.getSharedInstance().loadConfig()
|
pm = Config.get()
|
||||||
|
|
||||||
if "sdrhu_public_listing" not in pm or not pm["sdrhu_public_listing"]:
|
if "sdrhu_public_listing" not in pm or not pm["sdrhu_public_listing"]:
|
||||||
logger.error('Public listing on sdr.hu is not activated. Please check "sdrhu_public_listing" in your config.')
|
logger.error('Public listing on sdr.hu is not activated. Please check "sdrhu_public_listing" in your config.')
|
||||||
|
0
test/__init__.py
Normal file
0
test/__init__.py
Normal file
0
test/property/__init__.py
Normal file
0
test/property/__init__.py
Normal file
8
test/property/test_property.py
Normal file
8
test/property/test_property.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import unittest
|
||||||
|
from owrx.property import Property
|
||||||
|
|
||||||
|
|
||||||
|
class PropertyTest(unittest.TestCase):
|
||||||
|
def testSimple(self):
|
||||||
|
prop = Property("testvalue")
|
||||||
|
self.assertEqual(prop.getValue(), "testvalue")
|
Loading…
Reference in New Issue
Block a user