diff --git a/config.json b/config.json index ccb8089..ce20acf 100644 --- a/config.json +++ b/config.json @@ -4,5 +4,12 @@ "use_reloader": true, "host": "0.0.0.0", "port": 5101 + }, + "socket": { + "ping_timeout": 8, + "ping_interval": 2 + }, + "display": { + "timeout": 86400 } } \ No newline at end of file diff --git a/helpers/__init__.py b/helpers/__init__.py new file mode 100644 index 0000000..abdfa92 --- /dev/null +++ b/helpers/__init__.py @@ -0,0 +1,2 @@ +from . import uuid +from . import connection \ No newline at end of file diff --git a/helpers/connection.py b/helpers/connection.py new file mode 100644 index 0000000..58662c3 --- /dev/null +++ b/helpers/connection.py @@ -0,0 +1,10 @@ +from objects import glob + +def connect(sid): + glob.connections[sid] = set() + +def disconnect(sid): + for display in glob.connections[sid]: + display.detach(sid) + + del glob.connections[sid] diff --git a/helpers/uuid.py b/helpers/uuid.py new file mode 100644 index 0000000..1a27587 --- /dev/null +++ b/helpers/uuid.py @@ -0,0 +1,8 @@ +from random import randint + +UUID_SIZE = (8, 4, 4, 4, 12) +UUID_GLUE = "-" + +def generate(): + #[randint(0, 15) for s in UUID_SIZE for _ in range(s)] + return "-".join("".join(format(randint(0, 15), "x") for _ in range(s)) for s in UUID_SIZE) \ No newline at end of file diff --git a/objects/__init__.py b/objects/__init__.py new file mode 100644 index 0000000..afcffcf --- /dev/null +++ b/objects/__init__.py @@ -0,0 +1,2 @@ +from . import display +from . import glob \ No newline at end of file diff --git a/objects/display.py b/objects/display.py index f5e00d7..3974645 100644 --- a/objects/display.py +++ b/objects/display.py @@ -1,24 +1,64 @@ -displays = {} -windows = {} -tabs = {} +from datetime import datetime + +from . import glob +from helpers.uuid import generate as generate_uuid class Display: def __init__(self, uuid): - self.uuid = uuid - self.connections = [] # maybe set()? - self.windows = [] # maybe set()? - - def attach(self, connection): - self.connections.append(connection) + if uuid in glob.displays.keys(): + raise Exception("Display with this UUID already exists!") + glob.displays[uuid] = self - def detach(self, connection): - self.connections.remove(connection) + self.uuid = uuid + self.connections = set() # maybe set()? + self.windows = [] # maybe set()? + + self.title = None + self.start_time = int( datetime.now().timestamp() ) + self.kill_time = self.start_time + glob.config["display"]["timeout"] + + def attach(self, sid): + self.connections.add(sid) + glob.connections[sid].add(self) + + self.kill_time = None + + def detach(self, sid): + self.connections.remove(sid) + glob.connections[sid].remove(self) + + if len(self.connections) == 0: + self.kill_time = int( datetime.now().timestamp() ) + glob.config["display"]["timeout"] + + def serialize(self): + return { + "uuid": self.uuid, + "connections": len(self.connections), + "title": self.title, + "start_time": self.start_time, + "kill_time": self.kill_time + } + + def __str__(self): + return self.uuid + + @staticmethod + def generate(): + while True: + uuid = generate_uuid() + if uuid not in glob.displays.keys(): + break + return Display(uuid) class Window: def __init__(self, uuid, title = "__unnamed__", grid_column = (0, 0), grid_row = (0, 0)): + if uuid in glob.windows.keys(): + raise Exception("Window with this UUID already exists!") + glob.windows[uuid] = self + self.uuid = uuid self.title = title @@ -53,6 +93,10 @@ class Window: class Tab: def __init__(self, uuid, title = "__unnamed__"): + if uuid in glob.tabs.keys(): + raise Exception("Tab with this UUID already exists!") + glob.tabs[uuid] = self + self.uuid = uuid self.content = "" diff --git a/objects/glob.py b/objects/glob.py index d97fe36..97cd95b 100644 --- a/objects/glob.py +++ b/objects/glob.py @@ -2,8 +2,13 @@ import json from flask import Flask from flask_socketio import SocketIO -app = Flask("__main__") -websocket = SocketIO(app) - with open("config.json", "r") as f: config = json.load(f) + +app = Flask("__main__") +websocket = SocketIO(app, **config["socket"]) + +connections = {} +displays = {} +windows = {} +tabs = {} diff --git a/templates/display.html b/templates/display.html index 145a932..5877dad 100644 --- a/templates/display.html +++ b/templates/display.html @@ -3,6 +3,15 @@ {% block extend_head %} {% endblock %} {% block content %} - + + {% endblock %} \ No newline at end of file diff --git a/websocket.py b/websocket.py index ea2ab4d..5dd192a 100644 --- a/websocket.py +++ b/websocket.py @@ -1,20 +1,49 @@ import json +from flask import request from flask_socketio import emit -from objects import display +from objects.display import Display, Window, Tab from objects import glob +from helpers import uuid, connection + +@glob.websocket.on_error_default # handles all namespaces without an explicit error handler +def default_error_handler(e): + print("ERR:", e) + return 500 + @glob.websocket.on("connect") def ws_connect(): - emit("msg", "hi") + connection.connect(request.sid) + return "hi" + +@glob.websocket.on("disconnect") +def ws_disconnect(): + connection.disconnect(request.sid) @glob.websocket.on("display") def ws_display(data): def handle_list(_): - emit("display", {"action": "list", "value": list( display.displays.keys() )}) + return [ item.serialize() for item in glob.displays.values() ] + + def handle_new(_): + display = Display.generate() + return display.serialize() + + def handle_connect(data): + uuid = data["uuid"] + if uuid not in glob.displays.keys(): + raise Exception("Display not found") + + glob.displays[uuid].attach(request.sid) + #print(dir(request)) + #print(request.sid) + #print("TODO") switch = { - "list": handle_list + "list": handle_list, + "new": handle_new, + "connect": handle_connect } - switch.get(data["action"])(data) \ No newline at end of file + return switch.get(data["action"])(data) \ No newline at end of file