Overhaul Model, Start Rendering of Lobby view

This commit is contained in:
Dominic Zimmer 2020-04-19 16:01:00 +02:00
parent cc35dec294
commit af2ef29585
5 changed files with 164 additions and 92 deletions

15
main.py
View File

@ -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()

190
model.py
View File

@ -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

View File

@ -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");
}
};

1
tehsession.json Normal file
View File

@ -0,0 +1 @@
{"sessions": {"2b7jrklcn6eulwbw": {"id": "2b7jrklcn6eulwbw", "name": "die neue session", "clients": ["bkrqopf5j6q3tpta"], "owner": "bkrqopf5j6q3tpta"}}, "clients": {"bkrqopf5j6q3tpta": {"id": "bkrqopf5j6q3tpta", "name": "dominic", "session": ""}}}

View File

@ -33,7 +33,7 @@ div {
<br>
<span>Available sessions</span><br>
<div id="all_sessions"></div><br>
<div id="sessions"></div><br>
<br>
<br>