@@ -151,7 +151,7 @@ def __init__(self, hs: "HomeServer"):
151151
152152 @abc .abstractmethod
153153 async def user_syncing (
154- self , user_id : str , affect_presence : bool
154+ self , user_id : str , affect_presence : bool , presence_state : str
155155 ) -> ContextManager [None ]:
156156 """Returns a context manager that should surround any stream requests
157157 from the user.
@@ -165,6 +165,7 @@ async def user_syncing(
165165 affect_presence: If false this function will be a no-op.
166166 Useful for streams that are not associated with an actual
167167 client that is being used by a user.
168+ presence_state: The presence state indicated in the sync request
168169 """
169170
170171 @abc .abstractmethod
@@ -228,6 +229,11 @@ async def current_state_for_users(
228229
229230 return states
230231
232+ async def current_state_for_user (self , user_id : str ) -> UserPresenceState :
233+ """Get the current presence state for a user."""
234+ res = await self .current_state_for_users ([user_id ])
235+ return res [user_id ]
236+
231237 @abc .abstractmethod
232238 async def set_state (
233239 self ,
@@ -461,7 +467,7 @@ def send_stop_syncing(self) -> None:
461467 self .send_user_sync (user_id , False , last_sync_ms )
462468
463469 async def user_syncing (
464- self , user_id : str , affect_presence : bool
470+ self , user_id : str , affect_presence : bool , presence_state : str
465471 ) -> ContextManager [None ]:
466472 """Record that a user is syncing.
467473
@@ -471,6 +477,17 @@ async def user_syncing(
471477 if not affect_presence or not self ._presence_enabled :
472478 return _NullContextManager ()
473479
480+ prev_state = await self .current_state_for_user (user_id )
481+ if prev_state != PresenceState .BUSY :
482+ # We set state here but pass ignore_status_msg = True as we don't want to
483+ # cause the status message to be cleared.
484+ # Note that this causes last_active_ts to be incremented which is not
485+ # what the spec wants: see comment in the BasePresenceHandler version
486+ # of this function.
487+ await self .set_state (
488+ UserID .from_string (user_id ), {"presence" : presence_state }, True
489+ )
490+
474491 curr_sync = self ._user_to_num_current_syncs .get (user_id , 0 )
475492 self ._user_to_num_current_syncs [user_id ] = curr_sync + 1
476493
@@ -942,7 +959,10 @@ async def bump_presence_active_time(self, user: UserID) -> None:
942959 await self ._update_states ([prev_state .copy_and_replace (** new_fields )])
943960
944961 async def user_syncing (
945- self , user_id : str , affect_presence : bool = True
962+ self ,
963+ user_id : str ,
964+ affect_presence : bool = True ,
965+ presence_state : str = PresenceState .ONLINE ,
946966 ) -> ContextManager [None ]:
947967 """Returns a context manager that should surround any stream requests
948968 from the user.
@@ -956,6 +976,7 @@ async def user_syncing(
956976 affect_presence: If false this function will be a no-op.
957977 Useful for streams that are not associated with an actual
958978 client that is being used by a user.
979+ presence_state: The presence state indicated in the sync request
959980 """
960981 # Override if it should affect the user's presence, if presence is
961982 # disabled.
@@ -967,9 +988,25 @@ async def user_syncing(
967988 self .user_to_num_current_syncs [user_id ] = curr_sync + 1
968989
969990 prev_state = await self .current_state_for_user (user_id )
991+
992+ # If they're busy then they don't stop being busy just by syncing,
993+ # so just update the last sync time.
994+ if prev_state .state != PresenceState .BUSY :
995+ # XXX: We set_state separately here and just update the last_active_ts above
996+ # This keeps the logic as similar as possible between the worker and single
997+ # process modes. Using set_state will actually cause last_active_ts to be
998+ # updated always, which is not what the spec calls for, but synapse has done
999+ # this for... forever, I think.
1000+ await self .set_state (
1001+ UserID .from_string (user_id ), {"presence" : presence_state }, True
1002+ )
1003+ # Retrieve the new state for the logic below. This should come from the
1004+ # in-memory cache.
1005+ prev_state = await self .current_state_for_user (user_id )
1006+
1007+ # To keep the single process behaviour consistent with worker mode, run the
1008+ # same logic as `update_external_syncs_row`, even though it looks weird.
9701009 if prev_state .state == PresenceState .OFFLINE :
971- # If they're currently offline then bring them online, otherwise
972- # just update the last sync times.
9731010 await self ._update_states (
9741011 [
9751012 prev_state .copy_and_replace (
@@ -979,6 +1016,10 @@ async def user_syncing(
9791016 )
9801017 ]
9811018 )
1019+ # otherwise, set the new presence state & update the last sync time,
1020+ # but don't update last_active_ts as this isn't an indication that
1021+ # they've been active (even though it's probably been updated by
1022+ # set_state above)
9821023 else :
9831024 await self ._update_states (
9841025 [
@@ -1086,11 +1127,6 @@ async def update_external_syncs_clear(self, process_id: str) -> None:
10861127 )
10871128 self .external_process_last_updated_ms .pop (process_id , None )
10881129
1089- async def current_state_for_user (self , user_id : str ) -> UserPresenceState :
1090- """Get the current presence state for a user."""
1091- res = await self .current_state_for_users ([user_id ])
1092- return res [user_id ]
1093-
10941130 async def _persist_and_notify (self , states : List [UserPresenceState ]) -> None :
10951131 """Persist states in the database, poke the notifier and send to
10961132 interested remote servers
0 commit comments