|
|
|
@ -11,30 +11,34 @@ import html
@@ -11,30 +11,34 @@ import html
|
|
|
|
|
import argparse |
|
|
|
|
import coloredlogs |
|
|
|
|
import glob |
|
|
|
|
import svganim.strokes |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger("svganim.webserver") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DateTimeEncoder(json.JSONEncoder): |
|
|
|
|
def default(self, o): |
|
|
|
|
if isinstance(o, datetime.datetime): |
|
|
|
|
return o.isoformat(timespec='milliseconds') |
|
|
|
|
return o.isoformat(timespec="milliseconds") |
|
|
|
|
|
|
|
|
|
return super().default(self, o) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class StaticFileWithHeaderHandler(tornado.web.StaticFileHandler): |
|
|
|
|
def set_extra_headers(self, path): |
|
|
|
|
"""For subclass to add extra headers to the response""" |
|
|
|
|
if path[-5:] == '.html': |
|
|
|
|
if path[-5:] == ".html": |
|
|
|
|
self.set_header("Access-Control-Allow-Origin", "*") |
|
|
|
|
if path[-4:] == '.svg': |
|
|
|
|
if path[-4:] == ".svg": |
|
|
|
|
self.set_header("Content-Type", "image/svg+xml") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class WebSocketHandler(tornado.websocket.WebSocketHandler): |
|
|
|
|
""" |
|
|
|
|
Websocket from the workers |
|
|
|
|
Websocket from the drawing |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
# CORS_ORIGINS = ['localhost'] |
|
|
|
|
connections = set() |
|
|
|
|
|
|
|
|
@ -51,29 +55,39 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
@@ -51,29 +55,39 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
|
|
|
|
|
# return valid |
|
|
|
|
|
|
|
|
|
# the client connected |
|
|
|
|
def open(self, p = None): |
|
|
|
|
def open(self, p=None): |
|
|
|
|
self.__class__.connections.add(self) |
|
|
|
|
self.prefix = datetime.datetime.now().strftime('%Y-%m-%d-') |
|
|
|
|
self.filename = self.prefix + str(self.check_filenr()) + '-' + uuid.uuid4().hex[:6] |
|
|
|
|
self.prefix = datetime.datetime.now().strftime("%Y-%m-%d-") |
|
|
|
|
self.filename = ( |
|
|
|
|
self.prefix + str(self.check_filenr()) + "-" + uuid.uuid4().hex[:6] |
|
|
|
|
) |
|
|
|
|
logger.info(f"{self.filename=}") |
|
|
|
|
self.write_message(json.dumps({ |
|
|
|
|
"filename": self.filename |
|
|
|
|
})) |
|
|
|
|
self.write_message(json.dumps({"filename": self.filename})) |
|
|
|
|
|
|
|
|
|
def check_filenr(self): |
|
|
|
|
files = glob.glob(os.path.join(self.config.storage, self.prefix +'*')) |
|
|
|
|
files = glob.glob(os.path.join(self.config.storage, self.prefix + "*")) |
|
|
|
|
return len(files) + 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def appendEvent(self, row): |
|
|
|
|
# write to an appendable json format. So basically a file that should be wrapped in [] to be json-parsable |
|
|
|
|
with open(os.path.join(self.config.storage,self.filename +'.json_appendable'), 'a') as fp: |
|
|
|
|
with open( |
|
|
|
|
os.path.join(self.config.storage, self.filename + ".json_appendable"), "a" |
|
|
|
|
) as fp: |
|
|
|
|
if not self.hasWritten: |
|
|
|
|
#metadata to first row, but only on demand |
|
|
|
|
fp.write(json.dumps([datetime.datetime.now().strftime("%Y-%m-%d %T"), self.dimensions[0], self.dimensions[1]])) |
|
|
|
|
# metadata to first row, but only on demand |
|
|
|
|
fp.write( |
|
|
|
|
json.dumps( |
|
|
|
|
[ |
|
|
|
|
datetime.datetime.now().strftime("%Y-%m-%d %T"), |
|
|
|
|
self.dimensions[0], |
|
|
|
|
self.dimensions[1], |
|
|
|
|
] |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
# writer.writerow() |
|
|
|
|
self.hasWritten = True |
|
|
|
|
|
|
|
|
|
fp.write(',\n') |
|
|
|
|
fp.write(",\n") |
|
|
|
|
# first column is color, rest is points |
|
|
|
|
fp.write(json.dumps(row)) |
|
|
|
|
|
|
|
|
@ -83,18 +97,18 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
@@ -83,18 +97,18 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
msg = json.loads(message) |
|
|
|
|
if msg['event'] == 'stroke': |
|
|
|
|
logger.info('stroke') |
|
|
|
|
if msg["event"] == "stroke": |
|
|
|
|
logger.info("stroke") |
|
|
|
|
self.appendEvent(msg) |
|
|
|
|
elif msg['event'] == 'dimensions': |
|
|
|
|
self.dimensions = [int(msg['width']), int(msg['height'])] |
|
|
|
|
elif msg["event"] == "dimensions": |
|
|
|
|
self.dimensions = [int(msg["width"]), int(msg["height"])] |
|
|
|
|
logger.info(f"{self.dimensions=}") |
|
|
|
|
elif msg['event'] == 'viewbox': |
|
|
|
|
logger.info('move or resize') |
|
|
|
|
elif msg["event"] == "viewbox": |
|
|
|
|
logger.info("move or resize") |
|
|
|
|
self.appendEvent(msg) |
|
|
|
|
else: |
|
|
|
|
# self.send({'alert': 'Unknown request: {}'.format(message)}) |
|
|
|
|
logger.warn('Unknown request: {}'.format(message)) |
|
|
|
|
logger.warn("Unknown request: {}".format(message)) |
|
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
# self.send({'alert': 'Invalid request: {}'.format(e)}) |
|
|
|
@ -103,25 +117,24 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
@@ -103,25 +117,24 @@ class WebSocketHandler(tornado.websocket.WebSocketHandler):
|
|
|
|
|
# client disconnected |
|
|
|
|
def on_close(self): |
|
|
|
|
self.__class__.rmConnection(self) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info(f"Client disconnected: {self.request.remote_ip}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
def rmConnection(cls, client): |
|
|
|
|
if client not in cls.connections: |
|
|
|
|
return |
|
|
|
|
cls.connections.remove(client) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
def hasConnection(cls, client): |
|
|
|
|
return client in cls.connections |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AudioListingHandler(tornado.web.RequestHandler): |
|
|
|
|
def initialize(self, config): |
|
|
|
|
self.config = config |
|
|
|
|
self.audiodir = os.path.join(self.config.storage, 'audio') |
|
|
|
|
self.audiodir = os.path.join(self.config.storage, "audio") |
|
|
|
|
|
|
|
|
|
def get(self): |
|
|
|
|
# filename = self.get_argument("file", None) |
|
|
|
@ -129,10 +142,16 @@ class AudioListingHandler(tornado.web.RequestHandler):
@@ -129,10 +142,16 @@ class AudioListingHandler(tornado.web.RequestHandler):
|
|
|
|
|
if not os.path.exists(self.audiodir): |
|
|
|
|
names = [] |
|
|
|
|
else: |
|
|
|
|
names = sorted([f"/audio/{name}" for name in os.listdir(self.audiodir) if name not in ['.gitignore']]) |
|
|
|
|
names = sorted( |
|
|
|
|
[ |
|
|
|
|
f"/audio/{name}" |
|
|
|
|
for name in os.listdir(self.audiodir) |
|
|
|
|
if name not in [".gitignore"] |
|
|
|
|
] |
|
|
|
|
) |
|
|
|
|
print(names) |
|
|
|
|
self.write(json.dumps(names)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AnimationHandler(tornado.web.RequestHandler): |
|
|
|
|
def initialize(self, config): |
|
|
|
@ -141,88 +160,149 @@ class AnimationHandler(tornado.web.RequestHandler):
@@ -141,88 +160,149 @@ class AnimationHandler(tornado.web.RequestHandler):
|
|
|
|
|
def get(self, filename): |
|
|
|
|
self.set_header("Content-Type", "application/json") |
|
|
|
|
# filename = self.get_argument("file", None) |
|
|
|
|
if filename == '': |
|
|
|
|
if filename == "": |
|
|
|
|
files = [] |
|
|
|
|
names = [name for name in os.listdir(self.config.storage) if name.endswith('json_appendable')] |
|
|
|
|
names = [ |
|
|
|
|
name |
|
|
|
|
for name in os.listdir(self.config.storage) |
|
|
|
|
if name.endswith("json_appendable") |
|
|
|
|
] |
|
|
|
|
for name in names: |
|
|
|
|
with open(os.path.join(self.config.storage, name), 'r') as fp: |
|
|
|
|
with open(os.path.join(self.config.storage, name), "r") as fp: |
|
|
|
|
first_line = fp.readline().strip() |
|
|
|
|
if first_line.endswith(','): |
|
|
|
|
if first_line.endswith(","): |
|
|
|
|
first_line = first_line[:-1] |
|
|
|
|
print(first_line) |
|
|
|
|
metadata = json.loads(first_line) |
|
|
|
|
files.append({ |
|
|
|
|
'name': f"/files/{name[:-16]}", |
|
|
|
|
"time": metadata[0], |
|
|
|
|
"dimensions": [metadata[1], metadata[2]], |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
files.sort(key=lambda k: k['time']) |
|
|
|
|
files.append( |
|
|
|
|
{ |
|
|
|
|
"name": f"/files/{name[:-16]}", |
|
|
|
|
"time": metadata[0], |
|
|
|
|
"dimensions": [metadata[1], metadata[2]], |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
files.sort(key=lambda k: k["time"]) |
|
|
|
|
self.write(json.dumps(files)) |
|
|
|
|
else: |
|
|
|
|
path = os.path.join(self.config.storage,os.path.basename(filename)+".json_appendable") |
|
|
|
|
drawing = { |
|
|
|
|
"file": filename, |
|
|
|
|
"shape": [] |
|
|
|
|
} |
|
|
|
|
with open(path, 'r') as fp: |
|
|
|
|
events = json.loads('['+fp.read()+']') |
|
|
|
|
path = os.path.join( |
|
|
|
|
self.config.storage, os.path.basename(filename) + ".json_appendable" |
|
|
|
|
) |
|
|
|
|
drawing = {"file": filename, "shape": []} |
|
|
|
|
with open(path, "r") as fp: |
|
|
|
|
events = json.loads("[" + fp.read() + "]") |
|
|
|
|
for i, event in enumerate(events): |
|
|
|
|
if i == 0: |
|
|
|
|
# metadata on first line |
|
|
|
|
drawing['time'] = event[0] |
|
|
|
|
drawing['dimensions'] = [event[1], event[2]] |
|
|
|
|
drawing["time"] = event[0] |
|
|
|
|
drawing["dimensions"] = [event[1], event[2]] |
|
|
|
|
else: |
|
|
|
|
if event['event'] == 'viewbox': |
|
|
|
|
if event["event"] == "viewbox": |
|
|
|
|
pass |
|
|
|
|
if event['event'] == 'stroke': |
|
|
|
|
if event["event"] == "stroke": |
|
|
|
|
# points = [] |
|
|
|
|
# for i in range(int(len(stroke) / 4)): |
|
|
|
|
# p = stroke[i*4:i*4+4] |
|
|
|
|
# points.append([float(p[0]), float(p[1]), int(p[2]), float(p[3])]) |
|
|
|
|
drawing['shape'].append({ |
|
|
|
|
'color': event['color'], |
|
|
|
|
'points': event['points'] |
|
|
|
|
}) |
|
|
|
|
drawing["shape"].append( |
|
|
|
|
{"color": event["color"], "points": event["points"]} |
|
|
|
|
) |
|
|
|
|
self.write(json.dumps(drawing)) |
|
|
|
|
|
|
|
|
|
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' |
|
|
|
|
|
|
|
|
|
class TagHandler(tornado.web.RequestHandler): |
|
|
|
|
"""List all tags""" |
|
|
|
|
|
|
|
|
|
def initialize(self, config, index: svganim.strokes.AnnotationIndex): |
|
|
|
|
self.config = config |
|
|
|
|
self.index = index |
|
|
|
|
self.metadir = os.path.join(self.config.storage, "metadata") |
|
|
|
|
|
|
|
|
|
def get(self): |
|
|
|
|
self.set_header("Content-Type", "application/json") |
|
|
|
|
tags = self.index.tags.keys() |
|
|
|
|
self.write(json.dumps(list(tags))) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TagAnnotationsHandler(tornado.web.RequestHandler): |
|
|
|
|
"""List all annotations for given tag""" |
|
|
|
|
|
|
|
|
|
def initialize(self, config, index: svganim.strokes.AnnotationIndex): |
|
|
|
|
self.config = config |
|
|
|
|
self.index = index |
|
|
|
|
self.metadir = os.path.join(self.config.storage, "metadata") |
|
|
|
|
|
|
|
|
|
def get(self, tag): |
|
|
|
|
if tag not in self.index.tags: |
|
|
|
|
raise tornado.web.HTTPError(404) |
|
|
|
|
|
|
|
|
|
self.set_header("Content-Type", "application/json") |
|
|
|
|
annotations = self.index.tags[tag] |
|
|
|
|
self.write(json.dumps(list([a.id for a in annotations]))) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AnnotationHandler(tornado.web.RequestHandler): |
|
|
|
|
"""Get annotation as svg""" |
|
|
|
|
|
|
|
|
|
def initialize(self, config, index: svganim.strokes.AnnotationIndex): |
|
|
|
|
self.config = config |
|
|
|
|
self.index = index |
|
|
|
|
self.metadir = os.path.join(self.config.storage, "metadata") |
|
|
|
|
|
|
|
|
|
def get(self, annotation_id): |
|
|
|
|
if annotation_id[-4:] == ".svg": |
|
|
|
|
extension = "svg" |
|
|
|
|
annotation_id = annotation_id[:-4] |
|
|
|
|
elif annotation_id[-4:] == ".mp3": |
|
|
|
|
extension = "mp3" |
|
|
|
|
annotation_id = annotation_id[:-4] |
|
|
|
|
elif annotation_id[-4:] == ".wav": |
|
|
|
|
extension = "wav" |
|
|
|
|
annotation_id = annotation_id[:-4] |
|
|
|
|
else: |
|
|
|
|
if last_stroke[2] == 1: |
|
|
|
|
d += " m" |
|
|
|
|
cmd = 'm' |
|
|
|
|
elif cmd != 'l': |
|
|
|
|
d+=' l ' |
|
|
|
|
cmd = 'l' |
|
|
|
|
extension = None |
|
|
|
|
|
|
|
|
|
logger.info(f"annotation {annotation_id=}, {extension=}") |
|
|
|
|
if annotation_id not in self.index.annotations: |
|
|
|
|
raise tornado.web.HTTPError(404) |
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
annotation = self.index.annotations[annotation_id] |
|
|
|
|
|
|
|
|
|
if extension == "svg": |
|
|
|
|
self.set_header("Content-Type", "image/svg+xml") |
|
|
|
|
self.write(annotation.get_as_svg()) |
|
|
|
|
elif extension == "mp3": |
|
|
|
|
self.set_header("Content-Type", "audio/mp3") |
|
|
|
|
self.write(annotation.getAnimationSlice().audio.export(format="mp3").read()) |
|
|
|
|
elif extension == "wav": |
|
|
|
|
self.set_header("Content-Type", "audio/wav") |
|
|
|
|
self.write(annotation.getAnimationSlice().audio.export(format="wav").read()) |
|
|
|
|
else: |
|
|
|
|
self.set_header("Content-Type", "application/json") |
|
|
|
|
self.write(json.dumps({ |
|
|
|
|
"id": annotation.id, |
|
|
|
|
"tag": annotation.tag, |
|
|
|
|
"audio": f"/annotation/{annotation.id}.mp3", |
|
|
|
|
})) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AnnotationsHandler(tornado.web.RequestHandler): |
|
|
|
|
def initialize(self, config): |
|
|
|
|
self.config = config |
|
|
|
|
self.metadir = os.path.join(self.config.storage, 'metadata') |
|
|
|
|
self.metadir = os.path.join(self.config.storage, "metadata") |
|
|
|
|
|
|
|
|
|
def prepare(self): |
|
|
|
|
if self.request.headers.get("Content-Type", "").startswith("application/json"): |
|
|
|
|
self.json_args = json.loads(self.request.body) |
|
|
|
|
else: |
|
|
|
|
self.json_args = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_filenames(self): |
|
|
|
|
return [name[:-16] for name in os.listdir(self.config.storage) if name.endswith('json_appendable')] |
|
|
|
|
return [ |
|
|
|
|
name[:-16] |
|
|
|
|
for name in os.listdir(self.config.storage) |
|
|
|
|
if name.endswith("json_appendable") |
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
def get(self, filename): |
|
|
|
|
self.set_header("Content-Type", "application/json") |
|
|
|
@ -233,71 +313,106 @@ class AnnotationsHandler(tornado.web.RequestHandler):
@@ -233,71 +313,106 @@ class AnnotationsHandler(tornado.web.RequestHandler):
|
|
|
|
|
if filename not in filenames: |
|
|
|
|
raise tornado.web.HTTPError(404) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
meta_file = os.path.join(self.metadir, filename +'.json') |
|
|
|
|
meta_file = os.path.join(self.metadir, filename + ".json") |
|
|
|
|
if not os.path.exists(meta_file): |
|
|
|
|
self.set_status(404) |
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
with open(meta_file, 'r') as fp: |
|
|
|
|
with open(meta_file, "r") as fp: |
|
|
|
|
self.write(json.load(fp)) |
|
|
|
|
|
|
|
|
|
def post(self, filename): |
|
|
|
|
# filename = self.get_argument("file", None) |
|
|
|
|
# filename = self.argument("file", None) |
|
|
|
|
|
|
|
|
|
filenames = self.get_filenames() |
|
|
|
|
print(filenames, filename) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if filename not in filenames: |
|
|
|
|
raise tornado.web.HTTPError(404) |
|
|
|
|
|
|
|
|
|
if not os.path.exists(self.metadir): |
|
|
|
|
os.mkdir(self.metadir) |
|
|
|
|
|
|
|
|
|
meta_file = os.path.join(self.metadir, filename +'.json') |
|
|
|
|
with open(meta_file, 'w') as fp: |
|
|
|
|
meta_file = os.path.join(self.metadir, filename + ".json") |
|
|
|
|
with open(meta_file, "w") as fp: |
|
|
|
|
json.dump(self.json_args, fp) |
|
|
|
|
|
|
|
|
|
class IndexHandler(tornado.web.RequestHandler): |
|
|
|
|
"""Get annotation as svg""" |
|
|
|
|
|
|
|
|
|
def initialize(self, config, index: svganim.strokes.AnnotationIndex): |
|
|
|
|
self.config = config |
|
|
|
|
self.index = index |
|
|
|
|
|
|
|
|
|
def get(self): |
|
|
|
|
self.render("templates/index.html", index=self.index) |
|
|
|
|
|
|
|
|
|
class Server: |
|
|
|
|
""" |
|
|
|
|
Server for HIT -> plotter events |
|
|
|
|
As well as for the Status interface |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
loop = None |
|
|
|
|
|
|
|
|
|
def __init__(self, config, logger): |
|
|
|
|
self.config = config |
|
|
|
|
self.logger = logger |
|
|
|
|
|
|
|
|
|
#self.config['server']['port'] |
|
|
|
|
self.web_root = os.path.join('www') |
|
|
|
|
# self.config['server']['port'] |
|
|
|
|
self.web_root = os.path.join("www") |
|
|
|
|
|
|
|
|
|
self.index = svganim.strokes.AnnotationIndex( |
|
|
|
|
"annotation_index.shelve", "files", "files/metadata" |
|
|
|
|
) |
|
|
|
|
self.logger.info("Loading Annotation Index") |
|
|
|
|
self.index.refresh() |
|
|
|
|
self.logger.info("\tloaded annotation index") |
|
|
|
|
|
|
|
|
|
def start(self): |
|
|
|
|
application = tornado.web.Application([ |
|
|
|
|
(r"/ws(.*)", WebSocketHandler, { |
|
|
|
|
'config': self.config, |
|
|
|
|
}), |
|
|
|
|
|
|
|
|
|
(r"/files/(.*)", AnimationHandler, |
|
|
|
|
{'config': self.config}), |
|
|
|
|
(r"/audio/(.+)", tornado.web.StaticFileHandler, |
|
|
|
|
{"path": os.path.join(self.config.storage, 'audio')}), |
|
|
|
|
(r"/audio", AudioListingHandler, |
|
|
|
|
{'config': self.config}), |
|
|
|
|
(r"/annotations/(.+)", AnnotationsHandler, |
|
|
|
|
{'config': self.config}), |
|
|
|
|
(r"/(.*)", StaticFileWithHeaderHandler, |
|
|
|
|
{"path": self.web_root}), |
|
|
|
|
], debug=True, autoreload=True) |
|
|
|
|
application.listen(self.config.port) |
|
|
|
|
tornado.ioloop.IOLoop.current().start() |
|
|
|
|
|
|
|
|
|
application = tornado.web.Application( |
|
|
|
|
[ |
|
|
|
|
( |
|
|
|
|
r"/ws(.*)", |
|
|
|
|
WebSocketHandler, |
|
|
|
|
{ |
|
|
|
|
"config": self.config, |
|
|
|
|
}, |
|
|
|
|
), |
|
|
|
|
(r"/files/(.*)", AnimationHandler, {"config": self.config}), |
|
|
|
|
( |
|
|
|
|
r"/audio/(.+)", |
|
|
|
|
tornado.web.StaticFileHandler, |
|
|
|
|
{"path": os.path.join(self.config.storage, "audio")}, |
|
|
|
|
), |
|
|
|
|
(r"/audio", AudioListingHandler, {"config": self.config}), |
|
|
|
|
(r"/annotations/(.+)", AnnotationsHandler, {"config": self.config}), |
|
|
|
|
(r"/tags", TagHandler, {"config": self.config, "index": self.index}), |
|
|
|
|
( |
|
|
|
|
r"/tags/(.+)", |
|
|
|
|
TagAnnotationsHandler, |
|
|
|
|
{"config": self.config, "index": self.index}, |
|
|
|
|
), |
|
|
|
|
( |
|
|
|
|
r"/annotation/(.+)", |
|
|
|
|
AnnotationHandler, |
|
|
|
|
{"config": self.config, "index": self.index}, |
|
|
|
|
), |
|
|
|
|
(r"/(.+)", StaticFileWithHeaderHandler, {"path": self.web_root}), |
|
|
|
|
|
|
|
|
|
(r"/", IndexHandler, {"config": self.config, "index": self.index}), |
|
|
|
|
], |
|
|
|
|
debug=True, |
|
|
|
|
autoreload=True, |
|
|
|
|
) |
|
|
|
|
application.listen(self.config.port) |
|
|
|
|
tornado.ioloop.IOLoop.current().start() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|
argParser = argparse.ArgumentParser( |
|
|
|
|
description='Start up the vector animation server') |
|
|
|
|
description="Start up the vector animation server" |
|
|
|
|
) |
|
|
|
|
# argParser.add_argument( |
|
|
|
|
# '--config', |
|
|
|
|
# '-c', |
|
|
|
@ -305,50 +420,40 @@ if __name__ == "__main__":
@@ -305,50 +420,40 @@ if __name__ == "__main__":
|
|
|
|
|
# type=str, |
|
|
|
|
# help='The yaml config file to load' |
|
|
|
|
# ) |
|
|
|
|
argParser.add_argument("--port", type=int, default=7890, help="Port") |
|
|
|
|
argParser.add_argument( |
|
|
|
|
'--port', |
|
|
|
|
type=int, |
|
|
|
|
default=7890, |
|
|
|
|
help='Port' |
|
|
|
|
) |
|
|
|
|
argParser.add_argument( |
|
|
|
|
'--storage', |
|
|
|
|
type=str, |
|
|
|
|
default='files', |
|
|
|
|
help='directory name for output files' |
|
|
|
|
) |
|
|
|
|
argParser.add_argument( |
|
|
|
|
'--verbose', |
|
|
|
|
'-v', |
|
|
|
|
action='count', default=0 |
|
|
|
|
"--storage", type=str, default="files", help="directory name for output files" |
|
|
|
|
) |
|
|
|
|
argParser.add_argument("--verbose", "-v", action="count", default=0) |
|
|
|
|
|
|
|
|
|
args = argParser.parse_args() |
|
|
|
|
|
|
|
|
|
loglevel = logging.NOTSET if args.verbose > 1 else logging.DEBUG if args.verbose > 0 else logging.INFO |
|
|
|
|
loglevel = ( |
|
|
|
|
logging.NOTSET |
|
|
|
|
if args.verbose > 1 |
|
|
|
|
else logging.DEBUG |
|
|
|
|
if args.verbose > 0 |
|
|
|
|
else logging.INFO |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
coloredlogs.install( |
|
|
|
|
level=loglevel, |
|
|
|
|
# default: "%(asctime)s %(hostname)s %(name)s[%(process)d] %(levelname)s %(message)s" |
|
|
|
|
fmt="%(asctime)s %(hostname)s %(name)s[%(process)d,%(threadName)s] %(levelname)s %(message)s" |
|
|
|
|
# default: "%(asctime)s %(hostname)s %(name)s[%(process)d] %(levelname)s %(message)s" |
|
|
|
|
fmt="%(asctime)s %(hostname)s %(name)s[%(process)d,%(threadName)s] %(levelname)s %(message)s", |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
# File logging |
|
|
|
|
formatter = logging.Formatter(fmt='%(asctime)s %(module)s:%(lineno)d %(levelname)8s | %(message)s', |
|
|
|
|
datefmt='%Y/%m/%d %H:%M:%S') # %I:%M:%S %p AM|PM format |
|
|
|
|
formatter = logging.Formatter( |
|
|
|
|
fmt="%(asctime)s %(module)s:%(lineno)d %(levelname)8s | %(message)s", |
|
|
|
|
datefmt="%Y/%m/%d %H:%M:%S", |
|
|
|
|
) # %I:%M:%S %p AM|PM format |
|
|
|
|
logFileHandler = logging.handlers.RotatingFileHandler( |
|
|
|
|
'log/draw_log.log', |
|
|
|
|
maxBytes=1024*512, |
|
|
|
|
backupCount=5 |
|
|
|
|
"log/draw_log.log", maxBytes=1024 * 512, backupCount=5 |
|
|
|
|
) |
|
|
|
|
logFileHandler.setFormatter(formatter) |
|
|
|
|
|
|
|
|
|
logger = logging.getLogger("sorteerhoed") |
|
|
|
|
logger.addHandler( |
|
|
|
|
logFileHandler |
|
|
|
|
) |
|
|
|
|
logger.addHandler(logFileHandler) |
|
|
|
|
logger.info(f"Start server: http://localhost:{args.port}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
server = Server(args, logger) |
|
|
|
|
server.start() |
|
|
|
|
|
|
|
|
|