X-Git-Url: https://git.auder.net/?p=rpsls-web.git;a=blobdiff_plain;f=server.py;h=f63f6e6df3c3258152c99133b08db8b3f5c91efa;hp=94b37880a3a1ef0c1b67ac9885b2191fe1aba0b3;hb=310a5febf1cbb15fce4238f6193e7a3d7286bdc5;hpb=f126a42e8aeb423e81043fdf07bb4a16350b4d37 diff --git a/server.py b/server.py index 94b3788..f63f6e6 100644 --- a/server.py +++ b/server.py @@ -1,20 +1,30 @@ import socketio import eventlet import sqlite3 -import re +from re import match as re_match from datetime import date -import os +from os import getenv +from sys import path as sys_path # Create a Socket.IO server (CORS arg required on server, not locally) -sio = socketio.Server() -#sio = socketio.Server(cors_allowed_origins='URL or *') +MODE = getenv('RPSLS_MODE') +allowed_origin = 'https://rpsls.auder.net' if MODE=='production' else '*' +sio = socketio.Server(cors_allowed_origins=allowed_origin) -RPSLS_PATH = './' #edit if launched from elsewhere -DB_PATH = RPSLS_PATH + 'db/rpsls.sqlite' +RPSLS_PATH = sys_path[0] +DB_PATH = RPSLS_PATH + '/db/rpsls.sqlite' searching = {} #someone seeks a game? (uid + sid) connected = {} #map uid --> sid (seek stage) +# Avoid repeating DB connect/close code +def db_operation(func): + con = sqlite3.connect(DB_PATH) + cur = con.cursor() + func(cur) + con.commit() + con.close() + @sio.event def disconnect(sid): """ Triggered at page reload or tab close """ @@ -31,26 +41,24 @@ def disconnect(sid): @sio.event def login(sid, data): """ When user sends name from /login page """ - if not re.match(r"^[a-zA-Z]{3,}$", data): + if not re_match(r"^[a-zA-Z]{3,}$", data): sio.emit("login", {"err": "Name: letters only"}, room=sid) return - con = sqlite3.connect(DB_PATH) - cur = con.cursor() - uid = 0 - try: - # Always try to insert (new) Users row - cur.execute("insert into Users (name) values (?)", (data,)) - uid = cur.lastrowid - except sqlite3.IntegrityError as err: - # If fails: user already exists, find its ID - if str(err) == "UNIQUE constraint failed: Users.name": - cur.execute("select id from Users where name = ?", (data,)) - uid = cur.fetchone()[0] - else: - raise - con.commit() - con.close() - sio.emit("login", {"name": data, "uid": uid}, room=sid) + def upsert(cur): + uid = 0 + try: + # Always try to insert (new) Users row + cur.execute("insert into Users (name) values (?)", (data,)) + uid = cur.lastrowid + except sqlite3.IntegrityError as err: + # If fails: user already exists, find its ID + if str(err) == "UNIQUE constraint failed: Users.name": + cur.execute("select id from Users where name = ?", (data,)) + uid = cur.fetchone()[0] + else: + raise + sio.emit("login", {"name": data, "uid": uid}, room=sid) + db_operation(upsert) @sio.event def seek(sid, data): @@ -63,54 +71,48 @@ def seek(sid, data): # Active seek pending: create game opponent = searching searching = {} - con = sqlite3.connect(DB_PATH) - cur = con.cursor() - today = (date.today(),) - cur.execute("insert into Games (created) values (?)", today) - gid = cur.lastrowid - # To room == sid, opponent is me. To my room, it's him/her - sio.emit("play", - {"gid":gid, "oppid":opponent["uid"], "oppname":opponent["name"]}, - room=sid) - sio.emit("play", - {"gid":gid, "oppid":data["uid"], "oppname":data["name"]}, - room=opponent["sid"]) - id_list = [(data["uid"],gid), (opponent["uid"],gid)] - cur.executemany("insert into Players (uid,gid) values (?,?)", id_list) - con.commit() - con.close() + def create_game(cur): + today = (date.today(),) + cur.execute("insert into Games (created) values (?)", today) + gid = cur.lastrowid + # To room == sid, opponent is me. To my room, it's him/her + sio.emit("play", + {"gid":gid, "oppid":opponent["uid"], "oppname":opponent["name"]}, + room=sid) + sio.emit("play", + {"gid":gid, "oppid":data["uid"], "oppname":data["name"]}, + room=opponent["sid"]) + id_list = [(data["uid"],gid), (opponent["uid"],gid)] + cur.executemany("insert into Players (uid,gid) values (?,?)", id_list) + db_operation(create_game) @sio.event def move(sid, data): """ New move to DB + transmit to opponent """ sio.emit("move", data, room=connected[data["oppid"]]) - con = sqlite3.connect(DB_PATH) - cur = con.cursor() - cur.execute("insert into Moves (uid,gid,choice,mnum) values (?,?,?,?)", - (data["uid"],data["gid"],data["choice"],data["mnum"])) - con.commit() - con.close() + db_operation(lambda cur: + cur.execute("insert into Moves (uid,gid,choice,mnum) values (?,?,?,?)", + (data["uid"],data["gid"],data["choice"],data["mnum"])) + ) @sio.event def inc_pts(sid, data): """ Add a point to the player (who won last round) """ - con = sqlite3.connect(DB_PATH) - cur = con.cursor() - cur.execute("update Players set points=points+1 where uid=? and gid=?", - (data["uid"],data["gid"])) - con.commit() - con.close() + db_operation(lambda cur: + cur.execute("update Players set points=points+1 where uid=? and gid=?", + (data["uid"],data["gid"])) + ) static_files = { - '/': RPSLS_PATH + 'index.html', - '/rpsls.js': RPSLS_PATH + 'rpsls.js', - '/favicon.ico': RPSLS_PATH + 'favicon.ico', - '/assets': RPSLS_PATH + 'assets' + '/': RPSLS_PATH + '/index.html', + '/rpsls.js': RPSLS_PATH + '/rpsls.js', + '/favicon.ico': RPSLS_PATH + '/favicon.ico', + '/assets': RPSLS_PATH + '/assets' } -PORT = os.getenv('RPSLS_PORT') +PORT = getenv('RPSLS_PORT') if PORT is None: - PORT = "8000" + PORT = "8000" #8001 PORT = int(PORT) # Wrap with a WSGI application