@@ -264,6 +264,7 @@ async def set_state(
264
264
state : JsonDict ,
265
265
ignore_status_msg : bool = False ,
266
266
force_notify : bool = False ,
267
+ is_sync : bool = False ,
267
268
) -> None :
268
269
"""Set the presence state of the user.
269
270
@@ -273,6 +274,7 @@ async def set_state(
273
274
ignore_status_msg: True to ignore the "status_msg" field of the `state` dict.
274
275
If False, the user's current status will be updated.
275
276
force_notify: Whether to force notification of the update to clients.
277
+ is_sync: True if this update was from a sync
276
278
"""
277
279
278
280
@abc .abstractmethod
@@ -516,6 +518,7 @@ async def user_syncing(
516
518
device_id ,
517
519
state = {"presence" : presence_state },
518
520
ignore_status_msg = True ,
521
+ is_sync = True ,
519
522
)
520
523
521
524
curr_sync = self ._user_to_num_current_syncs .get (user_id , 0 )
@@ -615,6 +618,7 @@ async def set_state(
615
618
state : JsonDict ,
616
619
ignore_status_msg : bool = False ,
617
620
force_notify : bool = False ,
621
+ is_sync : bool = False ,
618
622
) -> None :
619
623
"""Set the presence state of the user.
620
624
@@ -624,6 +628,7 @@ async def set_state(
624
628
ignore_status_msg: True to ignore the "status_msg" field of the `state` dict.
625
629
If False, the user's current status will be updated.
626
630
force_notify: Whether to force notification of the update to clients.
631
+ is_sync: True if this update was from a sync
627
632
"""
628
633
presence = state ["presence" ]
629
634
@@ -644,6 +649,7 @@ async def set_state(
644
649
state = state ,
645
650
ignore_status_msg = ignore_status_msg ,
646
651
force_notify = force_notify ,
652
+ is_sync = is_sync ,
647
653
)
648
654
649
655
async def bump_presence_active_time (self , user : UserID ) -> None :
@@ -1035,6 +1041,7 @@ async def user_syncing(
1035
1041
device_id ,
1036
1042
state = {"presence" : presence_state },
1037
1043
ignore_status_msg = True ,
1044
+ is_sync = True ,
1038
1045
)
1039
1046
# Retrieve the new state for the logic below. This should come from the
1040
1047
# in-memory cache.
@@ -1236,6 +1243,7 @@ async def set_state(
1236
1243
state : JsonDict ,
1237
1244
ignore_status_msg : bool = False ,
1238
1245
force_notify : bool = False ,
1246
+ is_sync : bool = False ,
1239
1247
) -> None :
1240
1248
"""Set the presence state of the user.
1241
1249
@@ -1246,6 +1254,7 @@ async def set_state(
1246
1254
ignore_status_msg: True to ignore the "status_msg" field of the `state` dict.
1247
1255
If False, the user's current status will be updated.
1248
1256
force_notify: Whether to force notification of the update to clients.
1257
+ is_sync: True if this update was from a sync
1249
1258
"""
1250
1259
status_msg = state .get ("status_msg" , None )
1251
1260
presence = state ["presence" ]
@@ -1258,6 +1267,7 @@ async def set_state(
1258
1267
return
1259
1268
1260
1269
user_id = target_user .to_string ()
1270
+ now = self .clock .time_msec ()
1261
1271
1262
1272
prev_state = await self .current_state_for_user (user_id )
1263
1273
@@ -1271,10 +1281,13 @@ async def set_state(
1271
1281
device_id ,
1272
1282
presence ,
1273
1283
last_active_ts = self .clock .time_msec (),
1284
+ last_sync_ts = 0 ,
1274
1285
),
1275
1286
)
1276
1287
device_state .state = presence
1277
- device_state .last_active_ts = self .clock .time_msec ()
1288
+ device_state .last_active_ts = now
1289
+ if is_sync :
1290
+ device_state .last_sync_ts = now
1278
1291
1279
1292
# Based on (all) the user's devices calculate the new presence state.
1280
1293
presence = _combine_device_states (
@@ -1290,7 +1303,7 @@ async def set_state(
1290
1303
if presence == PresenceState .ONLINE or (
1291
1304
presence == PresenceState .BUSY and self ._busy_presence_enabled
1292
1305
):
1293
- new_fields ["last_active_ts" ] = self . clock . time_msec ()
1306
+ new_fields ["last_active_ts" ] = now
1294
1307
1295
1308
await self ._update_states (
1296
1309
[prev_state .copy_and_replace (** new_fields )], force_notify = force_notify
@@ -1887,7 +1900,7 @@ def handle_timeouts(
1887
1900
Args:
1888
1901
user_states: List of UserPresenceState's to check.
1889
1902
is_mine_fn: Function that returns if a user_id is ours
1890
- syncing_user_devices: Set of user_ids with active syncs.
1903
+ syncing_user_devices: A map of user ID to device_ids with active syncs.
1891
1904
user_to_devices: A map of user ID to device ID to UserDevicePresenceState.
1892
1905
now: Current time in ms.
1893
1906
@@ -1955,15 +1968,16 @@ def handle_timeout(
1955
1968
if device_id not in syncing_device_ids :
1956
1969
# If the user has done something recently but hasn't synced,
1957
1970
# don't set them as offline.
1958
- #
1959
- # XXX last_user_sync_ts needs to be per-device.
1960
1971
sync_or_active = max (
1961
- state . last_user_sync_ts , device_state .last_active_ts
1972
+ device_state . last_sync_ts , device_state .last_active_ts
1962
1973
)
1963
1974
if now - sync_or_active > SYNC_ONLINE_TIMEOUT :
1964
1975
device_state .state = PresenceState .OFFLINE
1965
1976
device_changed = True
1966
1977
1978
+ # XXX How will this work when restoring from the database if device information
1979
+ # is not kept?
1980
+
1967
1981
# If the presence state of any of the devices changed, then (maybe) update
1968
1982
# the user's overall presence state.
1969
1983
if device_changed :
0 commit comments