Browse Source

A bit cleaner logic separation

Getty Ritter 4 years ago
parent
commit
73876b8750
4 changed files with 130 additions and 47 deletions
  1. 50 0
      messages.py
  2. 18 46
      parley.py
  3. 6 1
      static/main.js
  4. 56 0
      storage.py

+ 50 - 0
messages.py

@@ -0,0 +1,50 @@
+import json
+
+class Message:
+    MESSAGE_TYPES = {}
+
+    @classmethod
+    def decode(cls, raw):
+        hash = json.loads(raw)
+        tag = hash['tag']
+        return cls.MESSAGE_TYPES[tag].from_hash(hash)
+
+    def json(self):
+        hash = self.to_hash()
+        return json.dumps(self.to_hash())
+
+def message(name):
+    def decorate(class_decl):
+        Message.MESSAGE_TYPES[name] = class_decl
+        return class_decl
+    return decorate
+
+@message('config')
+class InitialConfig(Message):
+    def __init__(self, user, game):
+        self.user = user
+        self.game = game
+
+    @classmethod
+    def from_hash(cls, d):
+        return cls(user=d['user'], game=d['game'])
+
+    def to_hash(self):
+        return {'user': self.user, 'game': self.game}
+
+@message('post')
+class Post(Message):
+    def __init__(self, author, content):
+        self.author = author
+        self.content = content
+
+    @classmethod
+    def from_hash(cls, d):
+        return cls(author=d['author'], content=d['content'])
+
+    def to_hash(self):
+        return {
+            'tag': 'post',
+            'author': self.author,
+            'content': self.content,
+        }

+ 18 - 46
parley.py

@@ -1,38 +1,12 @@
-import asyncio
-import json
-import pysqlite3 as sql
 import sanic
 
-app = sanic.Sanic()
-
-DB = sql.connect('samp.db')
-CONNECTIONS = {}
+import messages
+import storage
 
-def get_backlog(game: str, c=None) -> [(str, str)]:
-    if c is None:
-        c = DB.cursor()
-    c.execute('SELECT c.user, c.content FROM chat c, games g WHERE c.game = g.id AND g.name = ?', [game])
-    return list(c)
-
-def get_game_id(game: str, c=None) -> int:
-    if c is None:
-        c = DB.cursor()
-    c.execute('SELECT id FROM games WHERE name = ?', [game])
-    res = c.fetchone()
-    if res is not None:
-        return res[0]
-    else:
-        c.execute('INSERT INTO games (name) VALUES (?)', [game])
-        DB.commit()
-        c.execute('SELECT id FROM games WHERE name = ?', [game])
-        return c.fetchone()[0]
+app = sanic.Sanic()
 
-def add_msg(user: str, content: str, game: str, c=None):
-    if c is None:
-        c = DB.cursor()
-    game_id = get_game_id(game, c)
-    c.execute('INSERT INTO chat (game, user, content) VALUES (?, ?, ?)', [game_id, user, content])
-    DB.commit()
+cache = storage.Cache()
+db = storage.Storage()
 
 @app.route("/static/<f>")
 async def static(request, f):
@@ -45,29 +19,27 @@ async def index(request):
 @app.websocket("/socket")
 async def socket(request, ws):
     initial = await ws.recv()
-    config = json.loads(initial)
-    user = config['user']
-    game = config['game']
+    config = messages.Message.decode(initial)
+    user = config.user
+    game = config.game
     sanic.log.logger.info(f'connected websocket for {user} in game {game}')
 
-    if game not in CONNECTIONS:
-        CONNECTIONS[game] = set()
-    CONNECTIONS[game].add(ws)
+    cache.add_connection(game, ws)
 
     try:
-        for (author, content) in get_backlog(game):
-            await ws.send(json.dumps({"author": author, "content": content}))
+        for (author, content) in db.get_backlog(game):
+            await ws.send(messages.Post(author, content).json())
         async for payload in ws:
-            msg = json.loads(payload)
-            add_msg(user, msg['content'], game)
-            for w in CONNECTIONS[game]:
-                await w.send(json.dumps({"author": user, "content": msg["content"]}))
+            msg = messages.Message.decode(payload)
+            db.add_msg(user, msg.content, game)
+            for w in cache.get_connections(game):
+                await w.send(messages.Post(user, msg.content).json())
     finally:
-        sanic.log.logger.info('removing websocket for {}'.format(config['game']))
-        CONNECTIONS[config['game']].remove(ws)
+        sanic.log.logger.info('removing websocket for {}'.format(game))
+        cache.remove_connection(game, ws)
 
 if __name__ == '__main__':
     try:
         app.run()
     finally:
-        DB.close()
+        db.close()

+ 6 - 1
static/main.js

@@ -1,5 +1,6 @@
 window.onload = function() {
     const config = {
+        "tag": "config",
         "game": "testing",
         "user": "test_user",
     };
@@ -45,7 +46,11 @@ window.onload = function() {
     $('#chatbox').on('keypress', function (e) {
        if (e.which === 13) {
            $(this).attr("disabled", "disabled");
-           socket.send(JSON.stringify({"content": $('#chatbox').val()}))
+           socket.send(JSON.stringify({
+               "tag": "post",
+               "author": config.user,
+               "content": $('#chatbox').val()
+           }))
            $('#chatbox').val('');
            $(this).removeAttr("disabled");
        }

+ 56 - 0
storage.py

@@ -0,0 +1,56 @@
+import sqlite3 as sql
+
+class Cache:
+    def __init__(self):
+        self.connections = {}
+
+    def add_connection(self, game: str, ws):
+        if game not in self.connections:
+            self.connections[game] = set()
+        self.connections[game].add(ws)
+
+    def remove_connection(self, game: str, ws):
+        if game in self.connections:
+            self.connections[game].remove(ws)
+
+    def get_connections(self, game: str):
+        return self.connections.get(game, [])
+
+class Storage:
+    def __init__(self):
+        self.db = sql.connect('samp.db')
+
+    def get_backlog(self, game: str, c=None) -> [(str, str)]:
+        if c is None:
+            c = self.db.cursor()
+
+        c.execute('SELECT c.user, c.content '
+                  'FROM chat c, games g '
+                  'WHERE c.game = g.id AND g.name = ?', [game])
+        return list(c)
+
+    def get_game_id(self, game: str, c=None) -> int:
+        if c is None:
+            c = self.db.cursor()
+
+        c.execute('SELECT id FROM games WHERE name = ?', [game])
+        res = c.fetchone()
+        if res is not None:
+            return res[0]
+        else:
+            c.execute('INSERT INTO games (name) VALUES (?)', [game])
+            self.db.commit()
+            c.execute('SELECT id FROM games WHERE name = ?', [game])
+            return c.fetchone()[0]
+
+    def add_msg(self, user: str, content: str, game: str, c=None):
+        if c is None:
+            c = self.db.cursor()
+
+        game_id = self.get_game_id(game, c)
+        c.execute('INSERT INTO chat (game, user, content) '
+                  'VALUES (?, ?, ?)', [game_id, user, content])
+        self.db.commit()
+
+    def close(self):
+        self.db.close()