diff --git a/fieldpoc/config.py b/fieldpoc/config.py index 4bf47c4..cc63765 100644 --- a/fieldpoc/config.py +++ b/fieldpoc/config.py @@ -15,6 +15,9 @@ class ControllerConfig(ConfigBase): def __init__(self, c): self._c = c +class DatabaseConfig(ConfigBase): + pass + class DectConfig(ConfigBase): def __init__(self, c): @@ -23,12 +26,17 @@ class DectConfig(ConfigBase): def check(self): return True +class YateConfig(ConfigBase): + pass + class Config: def __init__(self, c): self._c = c self.controller = ControllerConfig(c.get("controller", {})) + self.database = DatabaseConfig(c.get("database", {})) self.dect = DectConfig(c.get("dect", {})) + self.yate = YateConfig(c.get("yate", {})) def check(self): return self.dect.check() diff --git a/fieldpoc/fieldpoc.py b/fieldpoc/fieldpoc.py index eb8131c..8ebc00b 100644 --- a/fieldpoc/fieldpoc.py +++ b/fieldpoc/fieldpoc.py @@ -9,6 +9,7 @@ import threading from . import config from . import controller from . import dect +from . import ywsd logger = logging.getLogger("fieldpoc.fieldpoc") @@ -32,6 +33,7 @@ class FieldPOC: logger.info("initialising components") self._controller = controller.Controller(self) self._dect = dect.Dect(self) + self._ywsd = ywsd.Ywsd(self) def queue_all(self, msg): """ @@ -41,8 +43,20 @@ class FieldPOC: for queue in self.queues.values(): queue.put(msg) + def init(self): + """ + Prepare some data structures. + Run this once before using FieldPOC. + """ + + logger.info("initialize datastructures") + + self._ywsd.init() + + logger.info("initialization complete") + def run(self): - logger.info("stating components") + logger.info("starting components") self._controller_thread = threading.Thread(target=self._controller.run) self._controller_thread.start() @@ -50,6 +64,9 @@ class FieldPOC: self._dect_thread = threading.Thread(target=self._dect.run) self._dect_thread.start() + self._ywsd_thread = threading.Thread(target=self._ywsd.run, daemon=True) + self._ywsd_thread.start() + logger.info("started components") def _load_config(self): diff --git a/fieldpoc/run.py b/fieldpoc/run.py index c0e4f60..811f2cc 100644 --- a/fieldpoc/run.py +++ b/fieldpoc/run.py @@ -13,6 +13,7 @@ logger = logging.getLogger("fieldpoc.run") ap = argparse.ArgumentParser(prog="fieldpoc") ap.add_argument("-c", "--config", dest="config_file_path", default="fieldpoc_config.json", help="Path to the fieldpoc config file") ap.add_argument("-e", "--extensions", dest="extensions_file_path", default="fieldpoc_extensions.json", help="Path to the fieldpoc extensions file") +ap.add_argument('--init', dest="init", action='store_true') ap.add_argument('--debug', dest="debug", action='store_true') def run(): @@ -33,6 +34,11 @@ def run(): logger.info("prepared signal handling") fp = fieldpoc.FieldPOC(config_file_path=args.config_file_path, extensions_file_path=args.extensions_file_path) + + if args.init: + fp.init() + exit() + fp.run() logger.info("handle signals") diff --git a/fieldpoc/ywsd.py b/fieldpoc/ywsd.py new file mode 100644 index 0000000..bcca4af --- /dev/null +++ b/fieldpoc/ywsd.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 + +import aiopg.sa +import asyncio +import logging +import ywsd.engine +import ywsd.objects +import ywsd.settings + +import yate.asyncio + +logger = logging.getLogger("fieldpoc.ywsd") + +class Ywsd: + def __init__(self, fp): + self.fp = fp + + self.event_loop = asyncio.SelectorEventLoop() + + def settings(self): + class Settings(ywsd.settings.Settings): + def __init__(self, config): + self.config = config + + return Settings({ + "RINGBACK_TOP_DIRECTORY": "/opt/sounds", + "DB_CONFIG": { + "host": self.fp.config.database.hostname, + "user": self.fp.config.database.username, + "password": self.fp.config.database.password, + "database": self.fp.config.database.database, + }, + "STAGE2_DB_CONFIG":{ + "host": self.fp.config.database.hostname, + "user": self.fp.config.database.username, + "password": self.fp.config.database.password, + "database": self.fp.config.database.database, + }, + "LOCAL_YATE_ID": 1, + "INTERNAL_YATE_LISTENER": "voip", + "CACHE_IMPLEMENTATION": "ywsd.routing_cache.PythonDictRoutingCache", + "YATE_CONNECTION":{ + "host": self.fp.config.yate.host, + "port": self.fp.config.yate.port, + }, + }) + + def init(self): + async def amain(settings): + async with aiopg.sa.create_engine(**settings.DB_CONFIG) as engine: + async with engine.acquire() as conn: + await ywsd.objects.regenerate_database_objects(conn) + + asyncio.run(amain(self.settings())) + + + def run(self): + # Mokey patch python-yate so I don't have to fork it yet + async def setup_for_tcp(self, host, port): + self.reader, self.writer = await asyncio.open_connection(host, port) + self.send_connect() + yate.asyncio.YateAsync.setup_for_tcp = setup_for_tcp + + # Mokey patch ywsd so I don't have to fork it yet + asyncio.set_event_loop(self.event_loop) + def add_signal_handler(*args, **kwargs): + raise NotImplementedError("Disable signal handling so we can run ywsd in a thread") + asyncio.get_event_loop().add_signal_handler = add_signal_handler + + logger.info("starting ywsd") + self.app = ywsd.engine.YateRoutingEngine(settings=self.settings(), web_only=False, **self.settings().YATE_CONNECTION) + self.app.event_loop = self.event_loop + self.app.run() + + logger.info("stopped ywsd") diff --git a/fieldpoc_config.json b/fieldpoc_config.json index 85747b0..d50da62 100644 --- a/fieldpoc_config.json +++ b/fieldpoc_config.json @@ -7,5 +7,15 @@ "host": "192.168.0.100", "username": "omm", "password": "xxx" + }, + "yate": { + "host": "127.0.0.1", + "port": 5039 + }, + "database": { + "hostname": "127.0.0.1", + "username": "fieldpoc", + "password": "fieldpoc", + "database": "fieldpoc" } }