From ab7dd39028f27962c4dd2db1ecfca74bb2c79744 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Fri, 19 Feb 2021 02:44:33 -0600 Subject: [PATCH] Add endpoint to get an event at a given timestamp --- synapse/rest/client/v1/room.py | 25 ++++++++++++ .../storage/databases/main/events_worker.py | 40 +++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/synapse/rest/client/v1/room.py b/synapse/rest/client/v1/room.py index 9a1df30c2999..b5384bd6c929 100644 --- a/synapse/rest/client/v1/room.py +++ b/synapse/rest/client/v1/room.py @@ -980,6 +980,30 @@ def register_txn_path(servlet, regex_string, http_server, with_get=False): servlet.__class__.__name__, ) +class TimestampLookupRestServlet(ClientV1RestServlet): + PATTERNS = client_path_patterns("/rooms/(?P[^/]*)/timestamp_to_event$") + + def __init__(self, hs): + super(TimestampLookupRestServlet, self).__init__(hs) + self.store = hs.get_datastore() + + @defer.inlineCallbacks + def on_GET(self, request, room_id): + requester = yield self.auth.get_user_by_req(request) + yield self.auth.check_joined_room(room_id, requester..to_string()) + + timestamp = parse_integer(request, "ts") + thread_id = parse_integer(request, "thread_id", 0) + + event_id = yield self.store.get_event_for_timestamp( + room_id, thread_id, timestamp, + ) + + .returnValue((200, { + "event_id": event_id, + })) + + def register_servlets(hs, http_server, is_worker=False): RoomStateEventRestServlet(hs).register(http_server) @@ -994,6 +1018,7 @@ def register_servlets(hs, http_server, is_worker=False): RoomRedactEventRestServlet(hs).register(http_server) RoomTypingRestServlet(hs).register(http_server) RoomEventContextServlet(hs).register(http_server) + TimestampLookupRestServlet(hs).register(http_server) # Some servlets only get registered for the main process. if not is_worker: diff --git a/synapse/storage/databases/main/events_worker.py b/synapse/storage/databases/main/events_worker.py index c8850a4707f6..65b3670c4769 100644 --- a/synapse/storage/databases/main/events_worker.py +++ b/synapse/storage/databases/main/events_worker.py @@ -1444,3 +1444,43 @@ def _cleanup_old_transaction_ids_txn(txn): "_cleanup_old_transaction_ids", _cleanup_old_transaction_ids_txn, ) + + def get_event_for_timestamp(self, room_id, thread_id, timestamp): + sql_template = """ + SELECT event_id, origin_server_ts FROM + WHERE + origin_server_ts %s ? + AND room_id = ? + AND thread_id = ? + ORDER BY origin_server_ts + LIMIT 1; + """ + + def f(txn): + txn.execute(sql_template % ("<=",), (timestamp, room_id, thread_id)) + row = txn.fetchone() + if row: + event_id_before, ts_before = row + else: + event_id_before, ts_before = None, None + + txn.execute(sql_template % (">=",), (timestamp, room_id, thread_id)) + row = txn.fetchone() + if row: + event_id_after, ts_after = row + else: + event_id_after, ts_after = None, None + + if event_id_before and event_id_after: + # Return the closest + if (timestamp - ts_before) < (ts_after - timestamp): + return event_id_before + else: + return event_id_after + + if event_id_before: + return event_id_before + + return event_id_after + + return self.runInteraction("get_event_for_timestamp", f)