temporary session are now available

This commit is contained in:
Jonas Weinz 2019-04-04 13:44:48 +02:00
parent ef5696f61d
commit 0c342eff7b
8 changed files with 125 additions and 81 deletions

View File

@ -39,6 +39,7 @@ communication with the web client is done by a (far from any standard and almost
"data": {
"id": "...",
"revoke_time": <revoke_time>,
"ranked": "<true | false">,
"match_state": <null| <match_state>>
}
}
@ -101,12 +102,18 @@ server response:
**login or register**:
keep pw null for requesting a temporary session (will be deleted after one hour of inactivity and matches are not ranked)
```json
{
"type": "login",
"data": {
"name": "<player_name>",
"pw": "<password>"
"pw": "<password> | null"
}
}
```
@ -119,6 +126,7 @@ response:
"data": {
"success": <true|false>,
"id": "<session-id>",
"registered": <true | false>,
"msg": "..."
}
}

View File

@ -141,10 +141,13 @@ class ConnectionHandler(object):
"success": True,
"id": conn.id,
"user": conn.user_name,
"registered": conn.is_registered_user,
"msg": ""
}
}))
await self.send_elo(conn)
if conn.is_registered_user:
await self.send_friends(conn)
await self._on_match_state_req(conn, None)
return conn
@ -154,45 +157,12 @@ class ConnectionHandler(object):
"success": False,
"id": None,
"user": None,
"registered": False,
"msg": "session not available"
}
}))
return None
elif msg['type'] == 'temp_session':
name = msg['data']['name'].lower()
if valid_name(name) and len(self.session_manager.get_session_by_temp_user(name)) == 0:
if len(self.user_manager.get_user(name)) == 0:
if len(msg['data']['name']) < 16 and ';' not in name and '\'' not in name and '\"' not in name:
id = self.session_manager.create_session_for_temp_user(
name)
conn = Connection(
id=id, user_name=name, registered=False, websocket=socket)
self._add_connection(conn)
await socket.send(json.dumps({
"type": "login_response",
"data": {
"success": True,
"id": id,
"msg": "logged in as temporary user " + name
}
}))
return conn
await socket.send(json.dumps({
"type": "login_response",
"data": {
"success": False,
"id": None,
"msg": "user name not available"
}
}))
return None
elif msg['type'] == 'login':
response_msg = ""
success = False
@ -200,6 +170,7 @@ class ConnectionHandler(object):
name = None
pw = None
conn = None
registered_user = True
try:
@ -225,15 +196,32 @@ class ConnectionHandler(object):
else:
response_msg = "invalid password for user " + name
elif valid_name(name) and len(name) <= 16 and len(pw) == 0:
# no password -> temporary account
registered_user = False
# check whether already a temporary session exists for that user:
if (len(self.session_manager.get_session_by_temp_user(name)) > 0) or (len(self.user_manager.get_user(name)) > 0):
response_msg = f"user '{name}' already exists"
success = False
else:
session_id = self.session_manager.create_session_for_temp_user(
name)
response_msg = f"created a temporary session for user {name}"
success = True
else:
response_msg = "invalid username or pw. Only usernames containing alphanumerical symbols (including '_','-') between 3 and 16 characters are allowed!"
except Exception as e:
print("error: " + str(e))
response_msg = "invalid username or pw. Only usernames containing alphanumerical symbols (including '_','-') between 3 and 16 characters are allowed!"
if success:
conn = Connection(id=session_id, user_name=name,
registered=True, websocket=socket)
registered=registered_user, websocket=socket)
self._add_connection(conn)
await socket.send(json.dumps({
@ -241,6 +229,7 @@ class ConnectionHandler(object):
"data": {
"success": success,
"id": session_id,
"registered": registered_user,
"msg": response_msg
}
}))
@ -265,6 +254,7 @@ class ConnectionHandler(object):
"data": {
"id": m.id,
"revoke_time": m.get_sql_revoke_time(),
"ranked": m.ranked,
"match_state": state
}
}
@ -278,6 +268,7 @@ class ConnectionHandler(object):
"data": {
"id": m.id,
"revoke_time": m.get_sql_revoke_time(),
"ranked": m.ranked,
"match_state": state
}
}
@ -355,7 +346,7 @@ class ConnectionHandler(object):
return
try:
if valid_name(opponent):
if len(self.user_manager.get_user(opponent)) > 0:
if len(self.user_manager.get_user(opponent)) > 0 or len(self.session_manager.get_session_by_temp_user(opponent)) > 0:
if len(self.match_manager.get_matches_for_user(opponent)) >= 5:
await conn.websocket.send(
@ -435,6 +426,7 @@ class ConnectionHandler(object):
"data": {
"id": db_match['id'],
"revoke_time": match.get_sql_revoke_time(),
"ranked": match.ranked,
"match_state": json.loads(match.to_json_state())
}
}))
@ -469,6 +461,7 @@ class ConnectionHandler(object):
'data': {
'id': match.id,
'revoke_time': match.get_sql_revoke_time(),
'ranked': match.ranked,
'match_state': json.loads(match_state)
}
}))
@ -487,6 +480,7 @@ class ConnectionHandler(object):
'data': {
'id': match.id,
'revoke_time': match.get_sql_revoke_time(),
'ranked': match.ranked,
'match_state': json.loads(match_state)
}
}))
@ -507,6 +501,7 @@ class ConnectionHandler(object):
return
if not match.game_over:
if match.ranked:
# check whether both player made a move. If so, the match is ranked as lost for the player who aborted the match
if match.complete_field.__contains__(Match.FIELD_USER_A) and match.complete_field.__contains__(Match.FIELD_USER_B):
@ -524,8 +519,10 @@ class ConnectionHandler(object):
new_elo_won = elo_update(elo_won, 1, p_won)
new_elo_lost = elo_update(elo_lost, 0, p_lost)
self.user_manager.update_elo(player_won, new_elo_won)
self.user_manager.update_elo(player_lost, new_elo_lost)
self.user_manager.update_elo(
player_won, new_elo_won)
self.user_manager.update_elo(
player_lost, new_elo_lost)
await self.send_elo(conn)
@ -547,6 +544,7 @@ class ConnectionHandler(object):
'data': {
'id': match_id,
'revoke_time': match.get_sql_revoke_time(),
'ranked': match.ranked,
'match_state': json.loads(match_state)
}
})
@ -570,6 +568,7 @@ class ConnectionHandler(object):
'data': {
'id': match.id,
'revoke_time': match.get_sql_revoke_time(),
'ranked': match.ranked,
'match_state': json.loads(match_state)
}
}))
@ -656,6 +655,18 @@ class ConnectionHandler(object):
top_names, top_elos = self.user_manager.get_highscores(100, 0)
if not conn.is_registered_user:
await conn.send(json.dumps({
'type': 'elo_update',
'data': {
'elo': None,
'rank': None,
'top_names': top_names,
'top_elos': top_elos
}
}))
return
await conn.send(json.dumps({
'type': 'elo_update',
'data': {
@ -687,6 +698,7 @@ class ConnectionHandler(object):
t = msg['type']
if conn.is_registered_user:
self.user_manager.touch_user(conn.user_name)
self.session_manager.touch_session(conn.id)
if t == "match_request":

View File

@ -17,10 +17,10 @@ def create_tables():
queries = [
"DROP TABLE IF EXISTS matches",
"DROP TABLE IF EXISTS sessions",
"DROP TABLE IF EXISTS users",
"DROP TABLE IF EXISTS friends",
"DROP TABLE IF EXISTS users",
"CREATE TABLE users (name varchar(16) NOT NULL, pw_hash varchar(128) NOT NULL, pw_salt varchar(32) NOT NULL, last_seen datetime NOT NULL, elo int NOT NULL, PRIMARY KEY (name)) CHARACTER SET " + settings.db_charset,
"CREATE TABLE matches (id varchar(32) NOT NULL, user_a varchar(16) NOT NULL, user_b varchar(16) NOT NULL, match_state varchar(4096) NOT NULL, active_user varchar(16), last_active datetime NOT NULL, FOREIGN KEY (user_a) REFERENCES users(name), FOREIGN KEY (user_b) REFERENCES users(name), FOREIGN KEY (active_user) REFERENCES users(name)) CHARACTER SET " + settings.db_charset,
"CREATE TABLE matches (id varchar(32) NOT NULL, user_a varchar(16) NOT NULL, user_b varchar(16) NOT NULL, match_state varchar(4096) NOT NULL, active_user varchar(16), last_active datetime NOT NULL, ranked BOOLEAN NOT NULL) CHARACTER SET " + settings.db_charset,
"CREATE TABLE sessions (id varchar(32) NOT NULL, registered_user varchar(16), temp_user varchar(16), last_seen datetime NOT NULL, PRIMARY KEY (id), FOREIGN KEY(registered_user) REFERENCES users(name)) CHARACTER SET " + settings.db_charset,
"CREATE TABLE friends (user varchar(16) NOT NULL, friend varchar(16) NOT NULL, FOREIGN KEY(user) REFERENCES users(name), FOREIGN KEY(friend) REFERENCES users(name)) CHARACTER SET " + settings.db_charset
]

View File

@ -15,7 +15,7 @@ import datetime
from tools import debug
um = UserManager(account_revoke_time)
sm = SessionManager(session_revove_time)
sm = SessionManager(session_revove_time, temporary_session_revoke_time)
mm = MatchManager(um, match_revoke_time)
ch = ConnectionHandler(sm, um, mm, revoke_check_interval)

View File

@ -38,7 +38,7 @@ class Match(object):
FIELD_USER_B = 2
FIELD_DRAW = 3
def __init__(self, n, match_id, revoke_time, player_a_name, player_b_name, json_state=None):
def __init__(self, n, match_id, revoke_time, player_a_name, player_b_name, json_state=None, ranked=False):
self.n = n
self.id = match_id
self.complete_field = np.zeros(shape=(n*n, n*n), dtype=int)
@ -51,6 +51,7 @@ class Match(object):
self.player_a_name = player_a_name
self.player_b_name = player_b_name
self.revoke_time = revoke_time
self.ranked = ranked
if json_state is not None:
self.from_json_state(json_state)

View File

@ -22,7 +22,7 @@ class MatchManager(object):
revoke_time = result[0]['last_active'] + self.match_lifespan_timedelta
match = Match(n=settings.n, match_id=id, revoke_time=revoke_time, player_a_name=result[0]['user_a'],
player_b_name=result[0]['user_b'], json_state=result[0]['match_state'])
player_b_name=result[0]['user_b'], json_state=result[0]['match_state'], ranked=result[0]['ranked'])
return match
def get_matches_for_user(self, user_name: str) -> list:
@ -35,13 +35,16 @@ class MatchManager(object):
if len(DatabaseConnection.global_single_query("SELECT id FROM matches WHERE id=%s", (match_id))) > 0:
return self.create_new_match(user_a, user_b)
ranked = len(self.user_manager.get_user(user_a)) > 0 and len(
self.user_manager.get_user(user_b)) > 0
now = datetime.datetime.now()
match = Match(n=settings.n, match_id=match_id, revoke_time=now + self.match_lifespan_timedelta,
player_a_name=user_a, player_b_name=user_b)
player_a_name=user_a, player_b_name=user_b, ranked=ranked)
query = "INSERT INTO matches (id, user_a, user_b, match_state, active_user, last_active) VALUES (%s, %s, %s, %s, %s,%s)"
query = "INSERT INTO matches (id, user_a, user_b, match_state, active_user, last_active, ranked) VALUES (%s, %s, %s, %s, %s,%s, %s)"
DatabaseConnection.global_single_execution(
query, (match_id, user_a, user_b, match.to_json_state(), match.get_current_player(), get_sql_time(now)))
query, (match_id, user_a, user_b, match.to_json_state(), match.get_current_player(), get_sql_time(now), ranked))
return match
def update_match(self, match_id: str, match: Match, update_in_db=True) -> None:
@ -53,7 +56,7 @@ class MatchManager(object):
query, (match.to_json_state(), match.get_current_player(), now, match_id))
# check whether we have to update the elo values (game over triggered by the last move)
if match.game_over:
if match.game_over and match.ranked:
if match.player_won is not None:
player_won = match.player_won

View File

@ -7,8 +7,9 @@ from tools import debug
class SessionManager(object):
def __init__(self, session_lifespan_timedelta):
def __init__(self, session_lifespan_timedelta, temp_session_lifespan_timedelta):
self.session_lifespan_timedelta = session_lifespan_timedelta
self.temp_session_lifespan_timedelta = temp_session_lifespan_timedelta
def get_session_by_id(self, session_id):
query = "SELECT * FROM sessions WHERE id=%s"
@ -16,7 +17,8 @@ class SessionManager(object):
def touch_session(self, session_id):
query = "UPDATE sessions SET last_seen=%s WHERE id=%s"
DatabaseConnection.global_single_execution(query, (datetime.datetime.now(), session_id))
DatabaseConnection.global_single_execution(
query, (datetime.datetime.now(), session_id))
def get_session_by_registered_user(self, user_name):
query = "SELECT * FROM sessions WHERE registered_user=%s"
@ -38,7 +40,8 @@ class SessionManager(object):
DatabaseConnection.global_single_execution(query, (user_name))
query = "INSERT INTO sessions (id, registered_user, temp_user, last_seen) VALUES ( %s, %s, NULL, %s)"
DatabaseConnection.global_single_execution(query, (new_id, user_name, datetime.datetime.now()))
DatabaseConnection.global_single_execution(
query, (new_id, user_name, datetime.datetime.now()))
return new_id
@ -54,19 +57,38 @@ class SessionManager(object):
DatabaseConnection.global_single_execution(query, (user_name))
query = "INSERT INTO sessions (id, registered_user, temp_user, last_seen) VALUES ( %s, NULL, %s, %s)"
DatabaseConnection.global_single_execution(query, (new_id, user_name, datetime.datetime.now()))
DatabaseConnection.global_single_execution(
query, (new_id, user_name, datetime.datetime.now()))
return new_id
def delete_session(self, session_id):
query = "DELETE FROM sessions WHERE id=%s"
DatabaseConnection.global_single_execution(query, (session_id))
def revoke_inactive_temporary_sessions(self):
revoke_time = datetime.datetime.now() - self.temp_session_lifespan_timedelta
query = "SELECT * from sessions WHERE last_seen < %s AND temp_user IS NOT NULL"
revoked_temp_sessions = DatabaseConnection.global_single_query(
query, (get_sql_time(revoke_time)))
query = "DELETE FROM sessions WHERE last_seen < %s AND temp_user IS NOT NULL"
DatabaseConnection.global_single_execution(
query, (get_sql_time(revoke_time)))
for session in revoked_temp_sessions:
# remove from matches:
query = "DELETE FROM matches WHERE user_a=%s OR user_b=%s"
DatabaseConnection.global_single_execution(
query, (session['temp_user'], session['temp_user']))
debug("delete revoked sessions: " + str(revoked_temp_sessions))
def revoke_inactive_sessions(self):
revoke_time = datetime.datetime.now() - self.session_lifespan_timedelta
query = "SELECT * from sessions WHERE last_seen < %s"
revoked_sessions = DatabaseConnection.global_single_query(query, (get_sql_time(revoke_time)))
revoked_sessions = DatabaseConnection.global_single_query(
query, (get_sql_time(revoke_time)))
query = "DELETE FROM sessions WHERE last_seen < %s"
DatabaseConnection.global_single_execution(query, (get_sql_time(revoke_time)))
DatabaseConnection.global_single_execution(
query, (get_sql_time(revoke_time)))
debug("delete revoked sessions: " + str(revoked_sessions))

View File

@ -61,8 +61,6 @@ class UserManager(object):
query, (user_name, pw_hash, pw_salt, datetime.datetime.now(), elo_start_value))
def touch_user(self, user_name):
matches = self.get_user(user_name)
assert len(matches) == 1
query = "UPDATE users SET last_seen=%s WHERE name=%s"
DatabaseConnection.global_single_execution(
query, (datetime.datetime.now(), user_name))