0DMRMaster version 0.4
Этот коммит содержится в:
Executable
+140
@@ -0,0 +1,140 @@
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from argparse import ArgumentParser
|
||||
|
||||
from api.dmrapi import start_api
|
||||
from dmrtools import Dispatcher
|
||||
from dmrtools.app import App
|
||||
from dmrtools.asyncnetwork import AsyncDatagramServer
|
||||
from dmrtools.auth import IPeerAuth
|
||||
|
||||
|
||||
class DMRMaster:
|
||||
def __init__(self) -> None:
|
||||
self.interface: str = '0.0.0.0'
|
||||
self.port: int = 62031
|
||||
self.web_interface: str = '0.0.0.0'
|
||||
self.web_port: int = 8000
|
||||
self.dispatcher: Dispatcher|None = None
|
||||
self.dg_server: AsyncDatagramServer|None = None
|
||||
|
||||
def setup(self) -> None:
|
||||
ap = ArgumentParser(
|
||||
prog="dmrmaster.py",
|
||||
description='0DMRMaster Server by Alexander Mokrov (UR6LKW)')
|
||||
|
||||
ap.add_argument('-i', '--interface', type=str,
|
||||
help='Interface to listen on. Defaults to 0.0.0.0.')
|
||||
ap.add_argument('-p', '--port', type=int,
|
||||
help='UDP port to listen on. Defaults to 62031.')
|
||||
ap.add_argument('--web-interface', type=str,
|
||||
help='Interface to run API on. Defaults to 0.0.0.0.')
|
||||
ap.add_argument('--web-port', type=int,
|
||||
help='TCP port to run API on. Defaults to 8000.')
|
||||
ap.add_argument('-l', '--log-file', type=str, help='Log filename')
|
||||
ap.add_argument('-d', '--ll-debug', action='store_true',
|
||||
help='Log level (INFO/DEBUG)')
|
||||
|
||||
args = ap.parse_args()
|
||||
# print(args)
|
||||
|
||||
if args.interface is not None:
|
||||
self.interface = args.interface
|
||||
if args.port is not None:
|
||||
self.port = args.port
|
||||
if args.web_interface is not None:
|
||||
self.web_interface = args.web_interface
|
||||
if args.web_port is not None:
|
||||
self.web_port = args.web_port
|
||||
|
||||
log_level = logging.DEBUG if args.ll_debug else logging.INFO
|
||||
self.setup_log(log_level, args.log_file)
|
||||
|
||||
def setup_log(self, log_level = logging.DEBUG, log_file = None) -> None:
|
||||
handlers = [logging.StreamHandler()]
|
||||
|
||||
if log_file:
|
||||
file_handler = logging.FileHandler(log_file)
|
||||
handlers.append(file_handler) # type: ignore[arg-type]
|
||||
|
||||
logging.basicConfig(
|
||||
level=log_level,
|
||||
format='%(asctime)s [%(levelname)s] %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
handlers=handlers
|
||||
)
|
||||
|
||||
def set_peer_auth(self, peer_auth: IPeerAuth) -> None:
|
||||
if self.dispatcher is None:
|
||||
logging.error("Can't set auth: no dispatcher")
|
||||
return
|
||||
logging.debug(f"Peer auth set to {peer_auth}")
|
||||
self.dispatcher.peer_auth = peer_auth
|
||||
|
||||
def register_app(self, app: App) -> None:
|
||||
if self.dispatcher is None:
|
||||
logging.error("Can't register app: no dispatcher")
|
||||
return
|
||||
self.dispatcher.app_keeper.register(app)
|
||||
|
||||
def config(self) -> None:
|
||||
"""
|
||||
Local config
|
||||
"""
|
||||
pass
|
||||
|
||||
def run(self) -> None:
|
||||
"""
|
||||
Run, go async and handle KeyboardInterupt
|
||||
"""
|
||||
try:
|
||||
asyncio.run(self.__async_run())
|
||||
except KeyboardInterrupt:
|
||||
logging.info("Interrupted by user (Ctrl+C). Exiting gracefully.")
|
||||
|
||||
async def __async_run(self) -> None:
|
||||
await self.__start_udp()
|
||||
|
||||
if not isinstance(self.dg_server, AsyncDatagramServer):
|
||||
logging.critical(f"Can't listen on {self.interface}:{self.port}")
|
||||
return
|
||||
|
||||
self.dispatcher = Dispatcher(self.dg_server)
|
||||
|
||||
self.config() # local config for apps
|
||||
|
||||
logging.info(f"Starting API on {self.web_interface}:{self.web_port}")
|
||||
|
||||
try:
|
||||
await start_api(self.web_interface, self.web_port, self.dispatcher)
|
||||
# await asyncio.Future() # Run forever
|
||||
finally:
|
||||
self.stop()
|
||||
|
||||
async def __start_udp(self) -> None:
|
||||
logging.info(
|
||||
f"Starting server listening on {self.interface}:{self.port}")
|
||||
|
||||
loop = asyncio.get_running_loop()
|
||||
transport, self.dg_server = await loop.create_datagram_endpoint(
|
||||
lambda: AsyncDatagramServer(),
|
||||
local_addr=(self.interface, self.port))
|
||||
|
||||
def stop(self) -> None:
|
||||
if self.dispatcher is not None:
|
||||
self.dispatcher.shutdown()
|
||||
self.dispatcher = None
|
||||
if self.dg_server is not None:
|
||||
self.dg_server.close()
|
||||
self.dg_server = None
|
||||
|
||||
|
||||
def main():
|
||||
master = DMRMaster();
|
||||
master.setup()
|
||||
master.run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Ссылка в новой задаче
Block a user