From 786509547060d7ab338311a80c48fcbf40ca749d Mon Sep 17 00:00:00 2001
From: Nils G <nils.gondermann@ruhr-uni-bochum.de>
Date: Thu, 7 May 2020 13:22:24 +0200
Subject: [PATCH] Periodically close rooms if they havent received an update
 recently

---
 controllers/game.py  |  6 +++++-
 controllers/room.py  |  8 +++-----
 models/c_meta.py     |  3 ++-
 models/z_schedule.py | 14 ++++++++++++++
 modules/room_util.py |  6 ++++++
 5 files changed, 30 insertions(+), 7 deletions(-)
 create mode 100644 models/z_schedule.py

diff --git a/controllers/game.py b/controllers/game.py
index c714564..828b473 100644
--- a/controllers/game.py
+++ b/controllers/game.py
@@ -1,6 +1,6 @@
 from parameter_util import JSON_BODY, JSON_CONTAINS, JSON_TO_B64
 from http_util import FAIL, CODE_JSON, CODE_MISSING, CODE_SEMANTIC, CODE_GONE, CODE_CONFLICT
-from room_util import ROOM_GET, PLAYERS_GET
+from room_util import ROOM_GET, PLAYERS_GET, ROOM_HEARTBEAT
 from websocket_util import WEBSOCKET_SEND
 
 def start():
@@ -28,6 +28,8 @@ def start():
     if room_record.closed:
         return(FAIL(CODE_GONE))
 
+    ROOM_HEARTBEAT(room_record)
+
     rolesB64 = JSON_TO_B64(roles)
 
     db(db.Room.id == room_record.id).update(started=True, roles=rolesB64)
@@ -59,6 +61,8 @@ def roles():
     if room_record.closed:
         return(FAIL(CODE_GONE))
 
+    ROOM_HEARTBEAT(room_record)
+
     players = PLAYERS_GET(room_record, True)
 
 
diff --git a/controllers/room.py b/controllers/room.py
index 6bfad97..9c21f03 100644
--- a/controllers/room.py
+++ b/controllers/room.py
@@ -1,7 +1,6 @@
 from parameter_util import JSON_BODY, JSON_CONTAINS
 from http_util import FAIL, CODE_JSON, CODE_MISSING, CODE_SEMANTIC, CODE_GONE
-from room_util import ROOM_GET, PLAYERS_GET, ROOM_CLOSE
-from websocket_util import WEBSOCKET_SEND
+from room_util import ROOM_GET, PLAYERS_GET, ROOM_CLOSE, ROOM_HEARTBEAT
 
 import random
 
@@ -46,6 +45,8 @@ def status():
     if room_record.closed:
         return(FAIL(CODE_GONE))
 
+    ROOM_HEARTBEAT(room_record)
+
     players = PLAYERS_GET(room_record)
 
     json_response = {"players": players}
@@ -74,7 +75,4 @@ def close():
 
     ROOM_CLOSE(room_record)
 
-    #Force reload on clients
-    WEBSOCKET_SEND(room_record, "reload", "")
-
     return(response.json({"status": "success"}))
diff --git a/models/c_meta.py b/models/c_meta.py
index 2bd3f07..72777ca 100644
--- a/models/c_meta.py
+++ b/models/c_meta.py
@@ -4,7 +4,8 @@ db.define_table(
     'Meta',
     Field('creation', 'datetime', default=request.now),
     Field('git_commit', 'string'),
-    Field('git_date', 'string')
+    Field('git_date', 'string'),
+    Field('schedule', 'datetime', default=request.now)
 )
 
 def getGitCommit(_record):
diff --git a/models/z_schedule.py b/models/z_schedule.py
new file mode 100644
index 0000000..ca3f7be
--- /dev/null
+++ b/models/z_schedule.py
@@ -0,0 +1,14 @@
+from room_util import ROOM_CLOSE
+
+if db(db.Meta).count() > 0:
+    seconds_passed = (request.now - db(db.Meta).select().first().schedule).total_seconds()
+
+    #Periodically clear stale rooms
+    if seconds_passed >= 60:
+        db(db.Meta).update(schedule=request.now)
+
+        td = request.now - timedelta(seconds=60)
+
+        stale_rooms = db((db.Room.closed == False) & (db.Room.heartbeat <= td)).select()
+        for room in stale_rooms:
+            ROOM_CLOSE(room)
diff --git a/modules/room_util.py b/modules/room_util.py
index ac26509..9070017 100644
--- a/modules/room_util.py
+++ b/modules/room_util.py
@@ -1,5 +1,6 @@
 from gluon import *
 from parameter_util import B64_TO_JSON
+from websocket_util import WEBSOCKET_SEND
 
 def ROOM_GET(_id, _password):
     room_record = current.db(current.db.Room.id == _id).select().first()
@@ -18,6 +19,8 @@ def ROOM_GET_CODE(_code):
 
     return(room_record)
 
+def ROOM_HEARTBEAT(_room):
+    current.db(current.db.Room.id == _room.id).update(heartbeat=current.request.now)
 
 def ROOM_CLOSE(_room):
     players = PLAYERS_GET(_room, True)
@@ -27,6 +30,9 @@ def ROOM_CLOSE(_room):
     for player in players:
         current.db(current.db.Player.id == player["uid"]).update(prompts="", inputs="")
 
+    #Force reload on clients
+    WEBSOCKET_SEND(_room, "reload", "")
+
 
 def PLAYERS_GET(_room, _uid=False):
     rows = current.db(current.db.Player.room_id == _room.id).select(orderby=current.db.Player.id)
-- 
GitLab