#fs imports from fastapi import FastAPI, HTTPException from uvicorn import run as UR from contextlib import asynccontextmanager #sys imports import argparse import traceback import sys import asyncio from time import time from typing import List, Dict #msh imports from transport_serial import SerialTransport from mesht_device import MeshtDevice from mesht_models import * from mesht_models import _wait_for_config_complete class Servlet: app: FastAPI transport = None device: MeshtDevice pulse = 0 channels: Dict[int, Channel] = {} nodes: Dict[int, Node] = {} message: List[Message] = [] msh_state = NOT_CONNECTED def __init__(self, args): self.app = FastAPI(lifespan=self.lifespan) self.args = args if args.transport == "serial": self.transport = SerialTransport(port=args.serial_port, baudrate=args.serial_baudrate) self.device = MeshtDevice(self.transport) self.buildRoutes() def run(self): UR(self.app, host=self.args.host, port=self.args.port)#, reload = True)#todo @asynccontextmanager async def lifespan(self, app: FastAPI): print("server is started, now connect to mesh") asyncio.create_task(self.meshWorker()) yield print("server is shutdown now") async def meshWorker(self): run = True while run: try: await self.device.start() self.msh_state = WAIT_CONFIG init_data = await _wait_for_config_complete(self.device) for from_radio in init_data:#todo check dubs self.meshCollector(from_radio) while True: self.msh_state = AVAILABLE self.pulse = time() from_radio, _ = await self.device.recv() self.meshCollector(from_radio) except asyncio.exceptions.CancelledError: print("Web close") run = False pass except: self.msh_state = ERR print("Mesh worker is has error, reconnect to mesh device after seconds...") traceback.print_exc() self.msh_state = RECONNECT await asyncio.sleep(1) finally: await self.device.close() def meshCollector(self, from_radio): try: print(from_radio) if Channel.isThis(from_radio): print("Found channel packet") channel = Channel(from_radio) self.channels[channel.index] = channel return if Node.isThis(from_radio): print("Found node packet") node = Node(from_radio) self.nodes[node.num] = node return if Message.isThis(from_radio): print("Found message packet") self.message.append(Message(from_radio)) except: print("cannot parse packet") traceback.print_exc() def buildRoutes(self): route = "/mesh/api" @self.app.get(route) async def root(): return {"status": self.msh_state} @self.app.get(route + "/nodes") async def getNodeList(): return [{"id": node.num, "name": str(node)} for node in self.nodes.values()] @self.app.get(route + "/nodes/{id}") async def getNodeInfo(id: int): if id in self.nodes: return self.nodes[id] else: raise HTTPException(404) @self.app.get(route + "/channels") async def getChannelList(): return [channel for channel in self.channels.values()] @self.app.get(route + "/messages")#todo before after async def getMessages(): return self.message @self.app.post(route + "/messages") #curl -X POST -d '{"txt":"test", "node_id":"xxxxxxxxxx"}' -H "Content-Type: application/json" http://127.0.0.1:8868/mesh/api/messages async def postMessage(msg: NewMessage): if msg.node_id: return await self.device.sendMsgToDM(msg.txt, msg.node_id) else: return await self.device.sendMsgToChannel(msg.txt, msg.channel_id) if __name__ == "__main__": parser = argparse.ArgumentParser() #msh parser.add_argument("--transport", default="serial") parser.add_argument("--serial-port", default="/dev/tty.usbmodemD0CF1309D56C1")#todo parser.add_argument("--serial-baudrate", default=115200) #srv parser.add_argument("--host", default="0.0.0.0") parser.add_argument("--port", default=8868) args = parser.parse_args() if (args.transport == "serial"): Servlet(args).run() else: print("Exists only serial transport") sys.exit(1)