diff --git a/openwebrx.py b/openwebrx.py index e41d6c7..99b1419 100644 --- a/openwebrx.py +++ b/openwebrx.py @@ -2,7 +2,7 @@ from http.server import HTTPServer from owrx.http import RequestHandler from owrx.config import PropertyManager from owrx.feature import FeatureDetector -from owrx.source import SdrService +from owrx.source import SdrService, ClientRegistry from socketserver import ThreadingMixIn from owrx.sdrhu import SdrHuUpdater @@ -45,4 +45,8 @@ Author contact info: Andras Retzler, HA7ILM if __name__ == "__main__": - main() + try: + main() + except KeyboardInterrupt: + for c in ClientRegistry.getSharedInstance().clients: + c.close() diff --git a/owrx/connection.py b/owrx/connection.py index a0442b8..95ce84f 100644 --- a/owrx/connection.py +++ b/owrx/connection.py @@ -1,5 +1,5 @@ from owrx.config import PropertyManager -from owrx.source import DspManager, CpuUsageThread, SdrService, ClientReporterThread +from owrx.source import DspManager, CpuUsageThread, SdrService, ClientRegistry import json import logging @@ -14,7 +14,7 @@ class OpenWebRxClient(object): def __init__(self, conn): self.conn = conn - ClientReporterThread.getSharedInstance().addClient(self) + ClientRegistry.getSharedInstance().addClient(self) self.dsp = None self.sdr = None @@ -68,10 +68,8 @@ class OpenWebRxClient(object): def close(self): self.stopDsp() CpuUsageThread.getSharedInstance().remove_client(self) - try: - ClientReporterThread.getSharedInstance().removeClient(self) - except ValueError: - pass + ClientRegistry.getSharedInstance().removeClient(self) + self.conn.close() logger.debug("connection closed") def stopDsp(self): diff --git a/owrx/controllers.py b/owrx/controllers.py index 9100de4..774ba9b 100644 --- a/owrx/controllers.py +++ b/owrx/controllers.py @@ -3,7 +3,7 @@ import mimetypes from datetime import datetime from owrx.websocket import WebSocketConnection from owrx.config import PropertyManager -from owrx.source import ClientReporterThread +from owrx.source import ClientRegistry from owrx.connection import WebSocketMessageHandler from owrx.version import openwebrx_version @@ -41,7 +41,7 @@ class StatusController(Controller): "status": "active", "name": pm["receiver_name"], "op_email": pm["receiver_admin"], - "users": ClientReporterThread.getSharedInstance().clientCount(), + "users": ClientRegistry.getSharedInstance().clientCount(), "users_max": pm["max_clients"], "gps": pm["receiver_gps"], "asl": pm["receiver_asl"], diff --git a/owrx/sdrhu.py b/owrx/sdrhu.py index b2c6b0f..5f0d7fb 100644 --- a/owrx/sdrhu.py +++ b/owrx/sdrhu.py @@ -10,7 +10,7 @@ logger = logging.getLogger(__name__) class SdrHuUpdater(threading.Thread): def __init__(self): self.doRun = True - super().__init__() + super().__init__(daemon = True) def update(self): pm = PropertyManager.getSharedInstance() diff --git a/owrx/source.py b/owrx/source.py index c45d12f..3efc7d4 100644 --- a/owrx/source.py +++ b/owrx/source.py @@ -467,6 +467,8 @@ class CpuUsageThread(threading.Thread): c.write_cpu_usage(cpu_usage) time.sleep(3) logger.debug("cpu usage thread shut down") + if CpuUsageThread.sharedInstance == self: + CpuUsageThread.sharedInstance = None def get_cpu_usage(self): try: @@ -499,42 +501,49 @@ class CpuUsageThread(threading.Thread): self.shutdown() def shutdown(self): - if self.doRun: - if CpuUsageThread.sharedInstance == self: - CpuUsageThread.sharedInstance = None - self.doRun = False + self.doRun = False + +class ClientReportingThread(threading.Thread): + def __init__(self, registry): + self.doRun = True + self.registry = registry + super().__init__() + def run(self): + while self.doRun: + self.registry.broadcast() + time.sleep(3) + def stop(self): + self.doRun = False class TooManyClientsException(Exception): pass -class ClientReporterThread(threading.Thread): +class ClientRegistry(object): sharedInstance = None @staticmethod def getSharedInstance(): - if ClientReporterThread.sharedInstance is None: - ClientReporterThread.sharedInstance = ClientReporterThread() - ClientReporterThread.sharedInstance.start() - ClientReporterThread.sharedInstance.doRun = True - return ClientReporterThread.sharedInstance + if ClientRegistry.sharedInstance is None: + ClientRegistry.sharedInstance = ClientRegistry() + return ClientRegistry.sharedInstance def __init__(self): - self.doRun = True self.clients = [] + self.reporter = None super().__init__() - def run(self): - while (self.doRun): - n = self.clientCount() - for c in self.clients: - c.write_clients(n) - time.sleep(3) - ClientReporterThread.sharedInstance = None + def broadcast(self): + n = self.clientCount() + for c in self.clients: + c.write_clients(n) def addClient(self, client): pm = PropertyManager.getSharedInstance() if len(self.clients) >= pm["max_clients"]: raise TooManyClientsException() self.clients.append(client) + if self.reporter is None: + self.reporter = ClientReportingThread(self) + self.reporter.start() def clientCount(self): return len(self.clients) @@ -544,5 +553,6 @@ class ClientReporterThread(threading.Thread): self.clients.remove(client) except ValueError: pass - if not self.clients: - self.doRun = False \ No newline at end of file + if not self.clients and self.reporter is not None: + self.reporter.stop() + self.reporter = None diff --git a/owrx/websocket.py b/owrx/websocket.py index 5387782..d0385b8 100644 --- a/owrx/websocket.py +++ b/owrx/websocket.py @@ -72,5 +72,20 @@ class WebSocketConnection(object): else: logger.warning("unsupported opcode: {0}".format(opcode)) + def close(self): + try: + header = self.get_header(0, 8) + self.handler.wfile.write(header) + self.handler.wfile.flush() + except ValueError: + logger.exception("while writing close frame:") + + try: + self.handler.finish() + self.handler.connection.close() + except Exception: + logger.exception("while closing connection:") + + class WebSocketException(Exception): pass