Files
archived-rtty/server/rtty.py
T
Jianhui Zhao f94ca85650 optimize code format
Signed-off-by: Jianhui Zhao <jianhuizhao329@gmail.com>
2018-01-12 16:31:38 +08:00

135 lines
3.7 KiB
Python
Executable File

#!/usr/bin/python3
import sys
import json
import random
import syslog
import getopt
from hashlib import md5
import asyncio
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
from aiohttp import web, WSMsgType
class Devices:
devs = {}
def add(self, ws, mac):
self.devs[mac] = {'ws': ws, 'active': 3}
def active(self, mac):
self.devs[mac]['active'] = 3
def flush(self):
for mac in list(self.devs):
self.devs[mac]['active'] -= 1
if self.devs[mac]['active'] == 0:
self.devs[mac]['ws'].close()
del self.devs[mac]
def login(self, ws, mac):
sid = md5((mac + str(random.uniform(1, 100))).encode('utf8')).hexdigest()
dev = self.devs.get(mac)
if not dev:
ws.send_str(json.dumps({'type':'login', 'err': 'Device off-line'}))
return False
ws.send_str(json.dumps({'type':'login', 'sid': sid}))
dev[sid] = ws
dev['ws'].send_str(json.dumps({'type': 'login', 'mac': mac, 'sid': sid}))
syslog.syslog('new logged to ' + mac)
return sid
def logout(self, mac, sid):
dev = self.devs.get(mac)
del dev[sid]
dev['ws'].send_str(json.dumps({'type': 'logout', 'mac': mac, 'sid': sid}))
def send_data2user(self, msg):
mac = msg['mac']
sid = msg['sid']
self.devs[mac][sid].send_str(json.dumps(msg))
def send_data2device(self, msg):
mac = msg['mac']
sid = msg['sid']
self.devs[mac]['ws'].send_str(json.dumps(msg))
devices = Devices()
syslog.openlog('rttyd')
async def websocket_handler_device(request):
ws = web.WebSocketResponse()
await ws.prepare(request)
mac = request.query['mac']
devices.add(ws, mac)
syslog.syslog('New device ' + mac)
async for msg in ws:
if msg.type == WSMsgType.TEXT:
msg = json.loads(msg.data)
typ = msg['type']
if typ == 'ping':
mac = msg['mac']
devices.active(mac)
elif typ == 'data' or typ == 'logout':
devices.send_data2user(msg)
elif msg.type == WSMsgType.ERROR:
syslog.syslog('device connection closed with exception %s' % ws.exception())
return ws
async def websocket_handler_browser(request):
ws = web.WebSocketResponse()
await ws.prepare(request)
mac = request.query['mac']
sid = devices.login(ws, mac)
if not sid:
ws.close()
return ws
async for msg in ws:
if msg.type == WSMsgType.TEXT:
msg = json.loads(msg.data)
typ = msg['type']
if typ == 'data':
devices.send_data2device(msg)
elif msg.type == WSMsgType.ERROR:
syslog.syslog('browser connection closed with exception %s' % ws.exception())
devices.logout(mac, sid)
return ws
async def handle_list(request):
return web.json_response(list(devices.devs.keys()))
async def handle_root(request):
return web.Response(status = 302, headers = {'location': '/rtty.html'})
port = 5912
document = './www'
opts, args = getopt.getopt(sys.argv[1:], "p:d:")
for op, value in opts:
if op == '-p':
port = int(value)
elif op == '-d':
document = value
app = web.Application()
app.router.add_get('/list', handle_list)
app.router.add_get('/ws/device', websocket_handler_device)
app.router.add_get('/ws/browser', websocket_handler_browser)
app.router.add_get('/', handle_root)
app.router.add_static('/', path = document, name = 'static')
def keepalive(loop):
devices.flush()
loop.call_later(5, keepalive, loop)
loop = asyncio.get_event_loop()
loop.call_later(5, keepalive, loop)
web.run_app(app, port = port)