From dd092070669cde345d02c5e2a87d0e45a9e18aba Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Wed, 11 Sep 2019 21:00:06 +0200 Subject: [PATCH] Save path into image & fetch latest image --- server.py | 103 +++++++++++++++++++++++++++++++++++---- www/generated/.gitignore | 0 www/index.html | 79 +++++++++++++++++++++++------- 3 files changed, 156 insertions(+), 26 deletions(-) create mode 100644 www/generated/.gitignore diff --git a/server.py b/server.py index 6875c68..727c0b3 100644 --- a/server.py +++ b/server.py @@ -1,11 +1,15 @@ +import argparse +import json +import logging +import os import tornado.ioloop import tornado.web import tornado.websocket -import logging -import coloredlogs -import argparse -import json from urllib.parse import urlparse +import uuid + +import coloredlogs +import glob logger = logging.getLogger("drawing") @@ -23,11 +27,38 @@ argParser.add_argument( action="store_true", ) +generated_image_dir = os.path.join('www','generated') + +def strokes2D(strokes): + # strokes to a d attribute for a path + d = ""; + last_stroke = None; + cmd = ""; + for stroke in strokes: + if not last_stroke: + d += f"M{stroke[0]},{stroke[1]} " + cmd = 'M' + else: + if last_stroke[2] == 1: + d += " m" + cmd = 'm' + elif cmd != 'l': + d+=' l ' + cmd = 'l' + + rel_stroke = [stroke[0] - last_stroke[0], stroke[1] - last_stroke[1]]; + d += f"{rel_stroke[0]},{rel_stroke[1]} " + last_stroke = stroke; + return d; + + class StaticFileWithHeaderHandler(tornado.web.StaticFileHandler): def set_extra_headers(self, path): """For subclass to add extra headers to the response""" if path[-5:] == '.html': self.set_header("Access-Control-Allow-Origin", "*") + if path[-4:] == '.svg': + self.set_header("Content-Type", "image/svg+xml") class WebSocketHandler(tornado.websocket.WebSocketHandler): CORS_ORIGINS = ['localhost', '.mturk.com'] @@ -43,20 +74,36 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler): def open(self, p = None): self.__class__.connections.add(self) logger.info("New client connected") - self.write_message("hello!") + self.strokes = [] +# self.write_message("hello!") # the client sent the message def on_message(self, message): logger.debug(f"recieve: {message}") try: msg = json.loads(message) + # TODO: sanitize input: min/max, limit strokes if msg['action'] == 'move': - pass + # TODO: min/max input + point = [float(msg['direction'][0]),float(msg['direction'][1]), 0] + self.strokes.append(point) + elif msg['action'] == 'up': logger.info(f'up: {msg}') + point = [msg['direction'][0],msg['direction'][1], 1] + self.strokes.append(point) + elif msg['action'] == 'submit': logger.info(f'up: {msg}') - self.write_message(json.dumps('submitted')) + id = self.submit_strokes() + if not id: + self.write_message(json.dumps('error')) + return + + self.write_message(json.dumps({ + 'action': 'submitted', + 'msg': f"Submission ok, please refer to your submission as: {id}" + })) elif msg['action'] == 'down': # not used, implicit in move? pass @@ -72,17 +119,54 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler): def on_close(self): self.__class__.rmConnection(self) logger.info("Client disconnected") + + def submit_strokes(self): + if len(self.strokes) < 1: + return False + + d = strokes2D(self.strokes) + svg = f""" + + + + """ + + id = uuid.uuid4().hex + + filename = os.path.join(generated_image_dir , id+'.svg') + with open(filename, 'w') as fp: + logger.info(f"Wrote {filename}") + fp.write(svg) + + return id @classmethod def rmConnection(cls, client): if client not in cls.connections: return cls.connections.remove(client) - + + +class LatestImageHandler(tornado.web.RequestHandler): + def get(self): + self.set_header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + self.set_header("Content-Type", "image/svg+xml") + + list_of_files = glob.glob(os.path.join(generated_image_dir,'*.svg')) + latest_file = max(list_of_files, key=os.path.getctime) + with open(latest_file, 'r') as fp: + self.write(fp.read()) if __name__ == "__main__": args = argParser.parse_args() - print(logger.level) + coloredlogs.install( level=logging.DEBUG if args.verbose else logging.INFO, ) @@ -98,6 +182,7 @@ if __name__ == "__main__": application = tornado.web.Application([ (r"/ws(.*)", WebSocketHandler), + (r"/latest.svg", LatestImageHandler), # TODO: have js request the right image, based on a 'start' button. This way we can trace the history of a drawing (r"/(.*)", StaticFileWithHeaderHandler, {"path": 'www', "default_filename": 'index.html'}), ], debug=True) diff --git a/www/generated/.gitignore b/www/generated/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/www/index.html b/www/index.html index f95ccb7..6566df2 100644 --- a/www/index.html +++ b/www/index.html @@ -4,10 +4,14 @@ MT Request: draw over the image
- +
+ - + - +
+
+ + +
+