You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

149 lines
4.9 KiB

#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)