2019-01-17 16:39:52 +00:00
|
|
|
"""
|
|
|
|
The panopticon provides a way to observe (& control) all running Hugveys trough a web interface
|
|
|
|
"""
|
|
|
|
|
|
|
|
import logging
|
|
|
|
import tornado
|
2019-01-23 21:38:27 +00:00
|
|
|
import string
|
|
|
|
import random
|
2019-01-17 16:39:52 +00:00
|
|
|
|
2019-01-18 18:39:35 +00:00
|
|
|
import tornado.websocket
|
|
|
|
import tornado.web
|
|
|
|
import tornado.ioloop
|
|
|
|
import os
|
|
|
|
from pytz.reference import Central
|
|
|
|
import asyncio
|
2019-01-22 07:59:45 +00:00
|
|
|
import json
|
2019-01-23 14:26:44 +00:00
|
|
|
from urllib.parse import urlparse
|
2019-01-23 21:38:27 +00:00
|
|
|
from hugvey import central_command
|
2019-01-17 16:39:52 +00:00
|
|
|
|
|
|
|
logger = logging.getLogger("panopticon")
|
|
|
|
|
2019-01-22 07:59:45 +00:00
|
|
|
web_dir = os.path.join(os.path.split(__file__)[0], '..', 'www')
|
2019-01-18 18:39:35 +00:00
|
|
|
|
|
|
|
|
2019-01-22 07:59:45 +00:00
|
|
|
def getWebSocketHandler(central_command):
|
|
|
|
class WebSocketHandler(tornado.websocket.WebSocketHandler):
|
2019-01-23 14:26:44 +00:00
|
|
|
CORS_ORIGINS = ['localhost']
|
2019-01-22 07:59:45 +00:00
|
|
|
connections = set()
|
2019-01-23 14:26:44 +00:00
|
|
|
|
|
|
|
def check_origin(self, origin):
|
|
|
|
parsed_origin = urlparse(origin)
|
|
|
|
# parsed_origin.netloc.lower() gives localhost:3333
|
|
|
|
valid = parsed_origin.hostname in self.CORS_ORIGINS
|
|
|
|
return valid
|
2019-01-18 18:39:35 +00:00
|
|
|
|
2019-01-22 07:59:45 +00:00
|
|
|
# the client connected
|
|
|
|
def open(self):
|
|
|
|
self.connections.add(self)
|
|
|
|
logger.info("New client connected")
|
2019-01-18 18:39:35 +00:00
|
|
|
|
2019-01-22 07:59:45 +00:00
|
|
|
# the client sent the message
|
|
|
|
def on_message(self, message):
|
2019-01-23 14:26:44 +00:00
|
|
|
logger.debug(f"recieve: {message}")
|
2019-01-22 07:59:45 +00:00
|
|
|
try:
|
|
|
|
msg = json.loads(message)
|
|
|
|
if msg['action'] == 'init':
|
|
|
|
self.msgInit()
|
|
|
|
if msg['action'] == 'get_status':
|
|
|
|
self.msgStatus()
|
|
|
|
if msg['action'] == 'resume':
|
|
|
|
self.msgResume(msg['hugvey'])
|
|
|
|
if msg['action'] == 'pause':
|
|
|
|
self.msgPause(msg['hugvey'])
|
|
|
|
if msg['action'] == 'restart':
|
|
|
|
self.msgRestart(msg['hugvey'])
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
self.send({'alert': 'Invalid request: {}'.format(e)})
|
|
|
|
|
|
|
|
def send(self, message):
|
|
|
|
j = json.dumps(message)
|
|
|
|
[con.write_message(j) for con in self.connections]
|
|
|
|
|
|
|
|
# client disconnected
|
|
|
|
def on_close(self):
|
|
|
|
self.connections.remove(self)
|
|
|
|
logger.info("Client disconnected")
|
|
|
|
|
|
|
|
def getStatusMsg(self):
|
|
|
|
msg = central_command.getStatusSummary()
|
|
|
|
msg['action'] = 'status'
|
|
|
|
|
|
|
|
return msg
|
|
|
|
|
|
|
|
def msgStatus(self):
|
|
|
|
self.send(self.getStatusMsg())
|
|
|
|
|
|
|
|
def msgInit(self):
|
|
|
|
msg = self.getStatusMsg()
|
|
|
|
self.send(msg)
|
|
|
|
|
|
|
|
def msgResume(self, hv_id):
|
|
|
|
central_command.hugveys[hv_id].eventQueue.put({'event': 'resume'})
|
|
|
|
|
|
|
|
def msgPause(self, hv_id):
|
|
|
|
central_command.hugveys[hv_id].eventQueue.put({'event': 'pause'})
|
|
|
|
|
|
|
|
def msgRestart(self, hv_id):
|
|
|
|
central_command.hugveys[hv_id].eventQueue.put({'event': 'restart'})
|
|
|
|
|
|
|
|
return WebSocketHandler
|
2019-01-18 18:39:35 +00:00
|
|
|
|
2019-01-23 21:38:27 +00:00
|
|
|
def getUploadHandler(central_command):
|
|
|
|
class UploadHandler(tornado.web.RequestHandler):
|
|
|
|
def post(self):
|
|
|
|
print('upload')
|
|
|
|
langCode = self.get_argument("language")
|
|
|
|
langFile = os.path.join(central_command.config['web']['files_dir'] , central_command.languageFiles[langCode])
|
|
|
|
|
|
|
|
print(self.request.files['json'][0])
|
|
|
|
storyData = json.loads(self.request.files['json'][0]['body'])
|
|
|
|
print(storyData)
|
|
|
|
|
|
|
|
if 'audio' in self.request.files:
|
|
|
|
msgId = self.get_argument("message_id")
|
|
|
|
audioFile = self.request.files['audio'][0]
|
|
|
|
original_fname = audioFile['filename']
|
|
|
|
fname = ''.join(random.choice(string.ascii_lowercase + string.digits) for x in range(10))
|
|
|
|
ext = os.path.splitext(original_fname)[1]
|
|
|
|
audioFilename = os.path.join(central_command.config['web']['files_dir'], fname + ext)
|
|
|
|
for i, data in enumerate(storyData):
|
|
|
|
if data['@id'] != msgId:
|
|
|
|
continue
|
|
|
|
storyData[i]['audio'] = {
|
|
|
|
'file': audioFilename,
|
|
|
|
'original_name': original_fname
|
|
|
|
}
|
|
|
|
with open(audioFilename, 'r') as fp:
|
|
|
|
logger.info(f'Save {original_fname} to {audioFilename}')
|
|
|
|
# fp.write(audioFile['body'])
|
|
|
|
break
|
|
|
|
|
|
|
|
with open(langFile, 'r') as fp:
|
|
|
|
logger.info(f'Save story to {langFile}')
|
|
|
|
# json.dump(storyData, fp)
|
|
|
|
self.finish()
|
|
|
|
return UploadHandler
|
2019-01-18 18:39:35 +00:00
|
|
|
|
2019-01-17 16:39:52 +00:00
|
|
|
class Panopticon(object):
|
2019-01-18 18:39:35 +00:00
|
|
|
def __init__(self, central_command, config):
|
|
|
|
self.command = central_command
|
|
|
|
self.config = config
|
|
|
|
self.application = tornado.web.Application([
|
2019-01-22 07:59:45 +00:00
|
|
|
(r"/ws", getWebSocketHandler(self.command)),
|
2019-01-23 14:26:44 +00:00
|
|
|
(r"/local/(.*)", tornado.web.StaticFileHandler,
|
2019-01-23 21:38:27 +00:00
|
|
|
{"path": config['web']['files_dir']}),
|
|
|
|
(r"/upload", getUploadHandler(self.command)),
|
2019-01-22 07:59:45 +00:00
|
|
|
(r"/(.*)", tornado.web.StaticFileHandler,
|
2019-01-23 21:38:27 +00:00
|
|
|
{"path": web_dir, "default_filename": 'index.html'}),
|
2019-01-18 18:39:35 +00:00
|
|
|
], debug=True)
|
2019-01-22 07:59:45 +00:00
|
|
|
|
2019-01-18 18:39:35 +00:00
|
|
|
self.application.listen(config['web']['port'])
|
|
|
|
# self.loop.configure(evt_loop)
|
|
|
|
|
|
|
|
def start(self):
|
|
|
|
evt_loop = asyncio.new_event_loop()
|
|
|
|
asyncio.set_event_loop(evt_loop)
|
2019-01-22 07:59:45 +00:00
|
|
|
|
2019-01-18 18:39:35 +00:00
|
|
|
self.loop = tornado.ioloop.IOLoop.current()
|
2019-01-23 14:26:44 +00:00
|
|
|
logger.info(f"Start Panopticon on http://localhost:{self.config['web']['port']}")
|
2019-01-18 18:39:35 +00:00
|
|
|
self.loop.start()
|
2019-01-22 07:59:45 +00:00
|
|
|
|
2019-01-18 18:39:35 +00:00
|
|
|
def stop(self):
|
|
|
|
self.loop.stop()
|