Store a list of the presence serial number at which remote users went offline, so that when we delete them from the cachemap, we can still synthesize OFFLINE events for them (SYN-261)
This commit is contained in:
parent
191f7f09ce
commit
8a785c3006
|
@ -135,6 +135,9 @@ class PresenceHandler(BaseHandler):
|
||||||
self._remote_sendmap = {}
|
self._remote_sendmap = {}
|
||||||
# map remote users to sets of local users who're interested in them
|
# map remote users to sets of local users who're interested in them
|
||||||
self._remote_recvmap = {}
|
self._remote_recvmap = {}
|
||||||
|
# list of (serial, set of(userids)) tuples, ordered by serial, latest
|
||||||
|
# first
|
||||||
|
self._remote_offline_serials = []
|
||||||
|
|
||||||
# map any user to a UserPresenceCache
|
# map any user to a UserPresenceCache
|
||||||
self._user_cachemap = {}
|
self._user_cachemap = {}
|
||||||
|
@ -715,6 +718,10 @@ class PresenceHandler(BaseHandler):
|
||||||
)
|
)
|
||||||
|
|
||||||
if state["presence"] == PresenceState.OFFLINE:
|
if state["presence"] == PresenceState.OFFLINE:
|
||||||
|
self._remote_offline_serials.insert(
|
||||||
|
0,
|
||||||
|
(self._user_cachemap_latest_serial, set([user.to_string()]))
|
||||||
|
)
|
||||||
del self._user_cachemap[user]
|
del self._user_cachemap[user]
|
||||||
|
|
||||||
for poll in content.get("poll", []):
|
for poll in content.get("poll", []):
|
||||||
|
@ -856,6 +863,20 @@ class PresenceEventSource(object):
|
||||||
|
|
||||||
# TODO(paul): limit
|
# TODO(paul): limit
|
||||||
|
|
||||||
|
for serial, user_ids in presence._remote_offline_serials:
|
||||||
|
if serial < from_key:
|
||||||
|
break
|
||||||
|
|
||||||
|
for u in user_ids:
|
||||||
|
updates.append({
|
||||||
|
"type": "m.presence",
|
||||||
|
"content": {"user_id": u, "presence": PresenceState.OFFLINE},
|
||||||
|
})
|
||||||
|
# TODO(paul): For the v2 API we want to tell the client their from_key
|
||||||
|
# is too old if we fell off the end of the _remote_offline_serials
|
||||||
|
# list, and get them to invalidate+resync. In v1 we have no such
|
||||||
|
# concept so this is a best-effort result.
|
||||||
|
|
||||||
if updates:
|
if updates:
|
||||||
defer.returnValue((updates, latest_serial))
|
defer.returnValue((updates, latest_serial))
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -878,6 +878,44 @@ class PresencePushTestCase(MockedDatastorePresenceTestCase):
|
||||||
state
|
state
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def test_recv_remote_offline(self):
|
||||||
|
""" Various tests relating to SYN-261 """
|
||||||
|
potato_set = self.handler._remote_recvmap.setdefault(self.u_potato,
|
||||||
|
set())
|
||||||
|
potato_set.add(self.u_apple)
|
||||||
|
|
||||||
|
self.room_members = [self.u_banana, self.u_potato]
|
||||||
|
|
||||||
|
self.assertEquals(self.event_source.get_current_key(), 0)
|
||||||
|
|
||||||
|
yield self.mock_federation_resource.trigger("PUT",
|
||||||
|
"/_matrix/federation/v1/send/1000000/",
|
||||||
|
_make_edu_json("elsewhere", "m.presence",
|
||||||
|
content={
|
||||||
|
"push": [
|
||||||
|
{"user_id": "@potato:remote",
|
||||||
|
"presence": "offline"},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEquals(self.event_source.get_current_key(), 1)
|
||||||
|
|
||||||
|
(events, _) = yield self.event_source.get_new_events_for_user(
|
||||||
|
self.u_apple, 0, None
|
||||||
|
)
|
||||||
|
self.assertEquals(events,
|
||||||
|
[
|
||||||
|
{"type": "m.presence",
|
||||||
|
"content": {
|
||||||
|
"user_id": "@potato:remote",
|
||||||
|
"presence": OFFLINE,
|
||||||
|
}}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def test_join_room_local(self):
|
def test_join_room_local(self):
|
||||||
self.room_members = [self.u_apple, self.u_banana]
|
self.room_members = [self.u_apple, self.u_banana]
|
||||||
|
|
Loading…
Reference in New Issue