diff sat_pubsub/pgsql_storage.py @ 467:d86e0f8a1405

privilege: store roster cache in database: - rosters are now stored on database and restored on startup. This way, presence map can be restored without the need to wait for all contact to send presence again - roster version are checked, if a new version is received, presence map is updated accordingly - roster are not retrieved if presence are received in a too short delay (see ROSTER_TTL), to avoid using too much resources if a client connect/disconnect a lot The current behaviour works around XEP-0356 limitations. An update of the XEP will be needed to get roster pushes and roster version.
author Goffi <goffi@goffi.org>
date Fri, 15 Oct 2021 15:30:18 +0200
parents 0d38c3529972
children d993e8b0fd60
line wrap: on
line diff
--- a/sat_pubsub/pgsql_storage.py	Fri Oct 15 13:40:59 2021 +0200
+++ b/sat_pubsub/pgsql_storage.py	Fri Oct 15 15:30:18 2021 +0200
@@ -51,12 +51,14 @@
 
 
 import copy, logging
+from datetime import datetime, timezone
 
 from zope.interface import implementer
 
 from twisted.internet import reactor
 from twisted.internet import defer
 from twisted.words.protocols.jabber import jid
+from twisted.words.xish import domish
 from twisted.python import log
 
 from wokkel import generic
@@ -478,6 +480,38 @@
         d.addCallback(self.formatLastItems)
         return d
 
+    def getRosterCache(self):
+        return self.dbpool.runInteraction(self._getRosterCache)
+
+    def _getRosterCache(self, cursor):
+        cursor.execute(
+            "SELECT roster_id, jid, version, updated, roster::text FROM roster"
+        )
+        return [(r.roster_id, jid.JID(r.jid), r.version, r.updated.timestamp(),
+                parseXml(r.roster)) for r in cursor.fetchall()]
+
+    def setRosterCache(
+            self,
+            jid_: jid.JID,
+            version: str,
+            updated: int,
+            roster: domish.Element
+    ):
+        return self.dbpool.runInteraction(self._setRosterCache, jid_, version, updated, roster)
+
+    def _setRosterCache(self, cursor, jid_, version, updated, roster):
+        cursor.execute(
+            "INSERT INTO roster(jid, version, updated, roster) VALUES (%s, %s, %s, %s) "
+            "ON CONFLICT (jid) DO UPDATE SET version=EXCLUDED.version, "
+            "updated=EXCLUDED.updated, roster=EXCLUDED.roster",
+            (
+                jid_.userhost(),
+                version,
+                datetime.fromtimestamp(updated, tz=timezone.utc),
+                roster.toXml()
+            )
+        )
+
 
 @implementer(iidavoll.INode)
 class Node: