mirror of
https://github.com/zhaojh329/rtty.git
synced 2026-02-27 09:53:17 +08:00
f94ca85650
Signed-off-by: Jianhui Zhao <jianhuizhao329@gmail.com>
135 lines
3.7 KiB
Python
Executable File
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)
|