diff --git a/main.py b/main.py
index fcc9573..c7fc51e 100644
--- a/main.py
+++ b/main.py
@@ -1,6 +1,8 @@
import aiohttp.web
import traceback
import urllib.parse
+import os
+import json
from model import Model
@@ -50,7 +52,7 @@ async def handler(request: aiohttp.web.Request):
data = await request.json()
- print(f'{client=} {data=}')
+ print(f'{method=} {client=} {data=}')
try:
assert method in model.ApiMethod.dict
@@ -60,7 +62,8 @@ async def handler(request: aiohttp.web.Request):
del e # unused?
traceback.print_exc()
return aiohttp.web.Response(status=400)
-
+ finally:
+ await model.send_state(client)
@routes.get(CLIENT_REGEX + '/ws')
async def _(request: aiohttp.web.Request):
@@ -110,7 +113,13 @@ if __name__ == '__main__':
app = aiohttp.web.Application()
app.add_routes(routes)
- app['model'] = Model()
+ data = {}
+ filename = "tehsession.json"
+ if os.path.isfile(filename):
+ with open(filename) as f:
+ data = json.load(f)
+
+ app['model'] = Model(model = data)
aiohttp.web.run_app(app, port=42042)
app['model'].save()
diff --git a/model.py b/model.py
index a6c45f8..a836c4e 100644
--- a/model.py
+++ b/model.py
@@ -22,28 +22,22 @@ class Model(object):
def __contains__(self, item):
return item in self.dict
- def __init__(self, filename="tehmodel.json"):
- self.sockets = {} # mapping: client -> socket
- self.filename = filename
- self.model = None
- if os.path.isfile(filename):
- with open(filename) as f:
- try:
- self.model = json.load(f)
- except:
- self.model = {}
- else:
- self.model = {}
- self.assert_model()
+ def __init__(self, model = {}):
+ if "sessions" not in model:
+ model["sessions"] = []
+ if "clients" not in model:
+ model["clients"] = []
+ self.sockets = {} # mapping: clientid -> sockets
+ self.sessions = { session: Session(model = model["sessions"][session]) for session in model["sessions"] }
+ self.clients = { client: Client(model = model["clients"][client]) for client in model["clients"] }
+ self.filename = "tehsession.json"
- def assert_model(self):
- if not "clients" in self.model:
- self.model["clients"] = {}
- if not "sessions" in self.model:
- self.model["sessions"] = {}
- for session in self.model["sessions"]:
- if not "name" in self.model["sessions"][session]:
- self.model["sessions"][session]["name"] = "Defaultname"
+ def to_json(self):
+ model = {
+ "sessions": {session: self.sessions[session].to_json() for session in self.sessions },
+ "clients": {client: self.clients[client].to_json() for client in self.clients },
+ }
+ return model
@ApiMethod
async def test_api(self, clientid):
@@ -55,79 +49,96 @@ class Model(object):
@ApiMethod
async def change_username(self, clientid, username) -> str:
- self.model["clients"][clientid]["username"] = username
- await self.send_state(clientid)
+ self.clients[clientid].name = username
@ApiMethod
async def create_session(self, clientid, sessionname) -> str:
if not sessionname:
- raise Exception("Cant be empty!")
- sessionid = generate_random_id()
- newsession = {"id": sessionid, "owner": clientid, "clients": [], "name": sessionname }
- self.model["sessions"][sessionid] = newsession
- await self.send_state(clientid)
+ raise Exception(f"Sessionname cant be empty!")
+ session = Session(name = sessionname, owner = clientid)
+ self.sessions[session.id] = session
+ print("create_session was called")
@ApiMethod
async def change_sessionname(self, clientid, sessionid, sessionname) -> str:
if not sessionname:
raise Exception("Cant be empty!")
- if self.model["sessions"][sessionid]["owner"] == clientid:
- self.model["sessions"][sessionid]["name"] = sessionname
- await self.send_state(clientid)
+ session = self.sessions[sessionid]
+ if not (session.owner == clientid):
+ raise Exception("Ownly owner can change sessionname")
+ session.name = sessionname
@ApiMethod
async def leave_session(self, clientid):
- sessionid = self.model["clients"][clientid]["session"]
- del self.model["clients"][clientid]["session"]
- self.model["sessions"][sessionid]["clients"].remove(clientid)
- await self.send_state(clientid)
+ client = self.clients[clientid]
+ sessionid = client.session
+ if sessionid:
+ session = self.sessions[sessionid]
+ session.clients.remove(clientid)
+ self.clients[clientid].session = ""
@ApiMethod
async def join_session(self, clientid, sessionid):
- if sessionid in self.model["sessions"]:
- # session exists
- self.model["clients"][clientid]["session"] = sessionid
- if not clientid in self.model["sessions"][sessionid]["clients"]:
- self.model["sessions"][sessionid]["clients"].append(clientid)
- await self.send_state(clientid)
+ client = self.clients[clientid]
+ old_sessionid = client.session
+ # leave old session
+ if old_sessionid:
+ old_session = self.sessions[old_sessionid]
+ old_session.clients.remove(clientid)
+ session = self.sessions[sessionid]
+ client.session = sessionid
+ session.clients.append(client.id)
+
+ async def send_lobby_view(self, clientid):
+ data = {}
+ client = self.clients[clientid]
+
+ data["view"] = "lobby"
+ data["username"] = client.name
+ data["sessions"] = {
+ session.id: {
+ "id": session.id,
+ "name": session.name,
+ "owned": session.owner == client.id,
+ } for session in self.sessions.values()
+ }
+ for socket in self.sockets[clientid]:
+ await socket.send_json(data)
+
+ async def send_session_view(self, clientid):
+ data = {}
+ client = self.clients[clientid]
+
+ data["view"] = "session"
+ data["username"] = client.name
+
+ for socket in self.sockets[clientid]:
+ await socket.send_json(data)
async def send_state(self, clientid):
# TODO: compute state, send to client
data = {}
- if "session" in self.model["clients"][clientid]:
- sessionid = self.model["clients"][clientid]["session"]
- data["session"] = {"id": sessionid, "name": self.model["sessions"][sessionid]["name"] }
- allsessions = { name: { "id": name, "name": self.model["sessions"][name]["name"] } for name in self.model["sessions"] }
- for session in allsessions:
- if self.model["sessions"][session]["owner"] == clientid:
- allsessions[session]["owner"] = True
- data["allsessions"] = allsessions
- data["username"] = self.model["clients"][clientid]["username"] if "username" in self.model["clients"][clientid] else "Joe"
- for socket in self.sockets[clientid]:
- await socket.send_json(data)
+ client = self.clients[clientid]
+ session = self.sessions[client.session] if client.session else None
+ if session:
+ await self.send_session_view(clientid)
+ else:
+ await self.send_lobby_view(clientid)
def save(self):
with open(self.filename, "w") as f:
- json.dump(self.model, f)
- if not os.path.isdir("backups"):
- try:
- os.mkdir("backups")
- except FileExistsError:
- print("backups is a file, no directory. Please delete yourself")
- datestring = datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d-%H%M%S")
- with open(f"backups/{datestring}_{self.filename}", "w") as f:
- json.dump(self.model, f)
+ json.dump(self.to_json(), f)
def exists_client(self, clientid: str) -> bool:
- return clientid in self.model["clients"]
+ return clientid in self.clients
def create_client(self, name="Joe") -> str:
if not name:
raise Exception("Username cannot be empty!")
- clientname = generate_random_id()
- newclient = {"id": clientname, "username": name, "sessions": []}
- self.model["clients"][clientname] = newclient
- return clientname
+ client = Client()
+ client.name = name
+ self.clients[client.id] = client
+ return client.id
async def subscribe(self, clientid, socket):
if not clientid in self.sockets:
@@ -139,3 +150,50 @@ class Model(object):
for client in self.sockets:
if socket in self.sockets[client]:
self.sockets[client].remove(socket)
+
+class Session:
+
+ def __init__(self, model = None, owner = None, name = None):
+ if model:
+ self.id = model["id"]
+ self.name = model["name"]
+ self.clients = model["clients"]
+ self.owner = model["owner"]
+ elif owner and name:
+ self.id = generate_random_id()
+ self.clients = []
+ self.owner = owner
+ self.name = name
+ else:
+ raise Exception("Illegal session constructor")
+
+ def to_json(self):
+ model = {
+ "id": self.id,
+ "name": self.name,
+ "clients": self.clients,
+ "owner": self.owner,
+ }
+ return model
+
+
+
+class Client:
+
+ def __init__(self, model = None):
+ if model:
+ self.id = model["id"]
+ self.name = model["name"]
+ self.session = model["session"]
+ else:
+ self.id = generate_random_id()
+ self.name = "Default Client Name"
+ self.session = ""
+
+ def to_json(self):
+ model = {
+ "id": self.id,
+ "name": self.name,
+ "session": self.session,
+ }
+ return model
diff --git a/static/renderer.js b/static/renderer.js
index bf5a868..0b9e695 100644
--- a/static/renderer.js
+++ b/static/renderer.js
@@ -2,36 +2,23 @@ const ws_url = new URL('ws', window.location.href);
ws_url.protocol = ws_url.protocol.replace('http', 'ws');
const ws = new WebSocket(ws_url.href);
-ws.onmessage = function(event) {
- const msg = JSON.parse(event.data);
-
- console.log(msg);
-
- if (msg.hasOwnProperty('session')) {
- document.getElementById('active-session').innerText = msg.session["name"];
- document.getElementById('btn-leave-session').style.display = "inline-block";
- } else {
- document.getElementById('active-session').innerText = "None";
- document.getElementById('btn-leave-session').style.display = "none";
- }
+function draw_lobby(msg) {
if (msg.hasOwnProperty('username')) {
document.getElementById('label-username').innerText = msg.username;
}
+ if (msg.hasOwnProperty('sessions')) {
+ const sessions = document.getElementById('sessions');
- if (msg.hasOwnProperty('allsessions')) {
- const all_sessions = document.getElementById('all_sessions');
+ while (sessions.children.length) sessions.lastChild.remove();
- while (all_sessions.children.length) all_sessions.lastChild.remove();
+ Object.keys(msg.sessions).forEach( session => {
+ session = msg.sessions[session];
+ var sessionid = session["id"];
+ var sessionname = session["name"];
+ var owned = session["owned"];
- //for (let session in msg.allsessions) {
- Object.keys(msg.allsessions).forEach( session => {
-
- var sessionid = msg.allsessions[session]["id"]
- var sessionname = msg.allsessions[session]["name"]
const tehsession = document.createElement('div');
-
const labelname = document.createElement('span');
- owned = ("owner" in msg.allsessions[session]);
labelname.innerText = sessionname;
tehsession.appendChild(labelname);
@@ -99,5 +86,22 @@ ws.onmessage = function(event) {
all_sessions.appendChild(tehsession);
})
+ }
+ */
+}
+
+ws.onmessage = function(event) {
+ const msg = JSON.parse(event.data);
+
+ console.log(msg);
+
+ var view = "lobby";
+ if (msg.hasOwnProperty('view')) {
+ view = msg.view;
+ }
+ if (view == "lobby") {
+ draw_lobby(msg);
+ } else if (view == "session") {
+ console.log("cant draw session yet");
}
};
diff --git a/tehsession.json b/tehsession.json
new file mode 100644
index 0000000..3f8f43f
--- /dev/null
+++ b/tehsession.json
@@ -0,0 +1 @@
+{"sessions": {"2b7jrklcn6eulwbw": {"id": "2b7jrklcn6eulwbw", "name": "die neue session", "clients": ["bkrqopf5j6q3tpta"], "owner": "bkrqopf5j6q3tpta"}}, "clients": {"bkrqopf5j6q3tpta": {"id": "bkrqopf5j6q3tpta", "name": "dominic", "session": ""}}}
\ No newline at end of file
diff --git a/ui.html b/ui.html
index 6f9e4db..6471659 100644
--- a/ui.html
+++ b/ui.html
@@ -33,7 +33,7 @@ div {
Available sessions
-