mirror of
https://mau.dev/maunium/synapse.git
synced 2024-12-14 22:43:52 +01:00
Merge pull request #9644 from matrix-org/babolivier/msc3026
Implement MSC3026: busy presence state
This commit is contained in:
commit
e09838c78f
7 changed files with 43 additions and 4 deletions
1
changelog.d/9644.feature
Normal file
1
changelog.d/9644.feature
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Implement the busy presence state as described in [MSC3026](https://github.com/matrix-org/matrix-doc/pull/3026).
|
|
@ -51,6 +51,7 @@ class PresenceState:
|
||||||
OFFLINE = "offline"
|
OFFLINE = "offline"
|
||||||
UNAVAILABLE = "unavailable"
|
UNAVAILABLE = "unavailable"
|
||||||
ONLINE = "online"
|
ONLINE = "online"
|
||||||
|
BUSY = "org.matrix.msc3026.busy"
|
||||||
|
|
||||||
|
|
||||||
class JoinRules:
|
class JoinRules:
|
||||||
|
|
|
@ -302,6 +302,8 @@ class GenericWorkerPresence(BasePresenceHandler):
|
||||||
self.send_stop_syncing, UPDATE_SYNCING_USERS_MS
|
self.send_stop_syncing, UPDATE_SYNCING_USERS_MS
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self._busy_presence_enabled = hs.config.experimental.msc3026_enabled
|
||||||
|
|
||||||
hs.get_reactor().addSystemEventTrigger(
|
hs.get_reactor().addSystemEventTrigger(
|
||||||
"before",
|
"before",
|
||||||
"shutdown",
|
"shutdown",
|
||||||
|
@ -439,8 +441,12 @@ class GenericWorkerPresence(BasePresenceHandler):
|
||||||
PresenceState.ONLINE,
|
PresenceState.ONLINE,
|
||||||
PresenceState.UNAVAILABLE,
|
PresenceState.UNAVAILABLE,
|
||||||
PresenceState.OFFLINE,
|
PresenceState.OFFLINE,
|
||||||
|
PresenceState.BUSY,
|
||||||
)
|
)
|
||||||
if presence not in valid_presence:
|
|
||||||
|
if presence not in valid_presence or (
|
||||||
|
presence == PresenceState.BUSY and not self._busy_presence_enabled
|
||||||
|
):
|
||||||
raise SynapseError(400, "Invalid presence state")
|
raise SynapseError(400, "Invalid presence state")
|
||||||
|
|
||||||
user_id = target_user.to_string()
|
user_id = target_user.to_string()
|
||||||
|
|
|
@ -27,6 +27,7 @@ class ExperimentalConfig(Config):
|
||||||
|
|
||||||
# MSC2858 (multiple SSO identity providers)
|
# MSC2858 (multiple SSO identity providers)
|
||||||
self.msc2858_enabled = experimental.get("msc2858_enabled", False) # type: bool
|
self.msc2858_enabled = experimental.get("msc2858_enabled", False) # type: bool
|
||||||
|
|
||||||
# Spaces (MSC1772, MSC2946, etc)
|
# Spaces (MSC1772, MSC2946, etc)
|
||||||
self.spaces_enabled = experimental.get("spaces_enabled", False) # type: bool
|
self.spaces_enabled = experimental.get("spaces_enabled", False) # type: bool
|
||||||
|
# MSC3026 (busy presence state)
|
||||||
|
self.msc3026_enabled = experimental.get("msc3026_enabled", False) # type: bool
|
||||||
|
|
|
@ -104,6 +104,8 @@ class BasePresenceHandler(abc.ABC):
|
||||||
self.clock = hs.get_clock()
|
self.clock = hs.get_clock()
|
||||||
self.store = hs.get_datastore()
|
self.store = hs.get_datastore()
|
||||||
|
|
||||||
|
self._busy_presence_enabled = hs.config.experimental.msc3026_enabled
|
||||||
|
|
||||||
active_presence = self.store.take_presence_startup_info()
|
active_presence = self.store.take_presence_startup_info()
|
||||||
self.user_to_current_state = {state.user_id: state for state in active_presence}
|
self.user_to_current_state = {state.user_id: state for state in active_presence}
|
||||||
|
|
||||||
|
@ -730,8 +732,12 @@ class PresenceHandler(BasePresenceHandler):
|
||||||
PresenceState.ONLINE,
|
PresenceState.ONLINE,
|
||||||
PresenceState.UNAVAILABLE,
|
PresenceState.UNAVAILABLE,
|
||||||
PresenceState.OFFLINE,
|
PresenceState.OFFLINE,
|
||||||
|
PresenceState.BUSY,
|
||||||
)
|
)
|
||||||
if presence not in valid_presence:
|
|
||||||
|
if presence not in valid_presence or (
|
||||||
|
presence == PresenceState.BUSY and not self._busy_presence_enabled
|
||||||
|
):
|
||||||
raise SynapseError(400, "Invalid presence state")
|
raise SynapseError(400, "Invalid presence state")
|
||||||
|
|
||||||
user_id = target_user.to_string()
|
user_id = target_user.to_string()
|
||||||
|
@ -744,7 +750,9 @@ class PresenceHandler(BasePresenceHandler):
|
||||||
msg = status_msg if presence != PresenceState.OFFLINE else None
|
msg = status_msg if presence != PresenceState.OFFLINE else None
|
||||||
new_fields["status_msg"] = msg
|
new_fields["status_msg"] = msg
|
||||||
|
|
||||||
if presence == PresenceState.ONLINE:
|
if presence == PresenceState.ONLINE or (
|
||||||
|
presence == PresenceState.BUSY and self._busy_presence_enabled
|
||||||
|
):
|
||||||
new_fields["last_active_ts"] = self.clock.time_msec()
|
new_fields["last_active_ts"] = self.clock.time_msec()
|
||||||
|
|
||||||
await self._update_states([prev_state.copy_and_replace(**new_fields)])
|
await self._update_states([prev_state.copy_and_replace(**new_fields)])
|
||||||
|
|
|
@ -81,6 +81,8 @@ class VersionsRestServlet(RestServlet):
|
||||||
"io.element.e2ee_forced.public": self.e2ee_forced_public,
|
"io.element.e2ee_forced.public": self.e2ee_forced_public,
|
||||||
"io.element.e2ee_forced.private": self.e2ee_forced_private,
|
"io.element.e2ee_forced.private": self.e2ee_forced_private,
|
||||||
"io.element.e2ee_forced.trusted_private": self.e2ee_forced_trusted_private,
|
"io.element.e2ee_forced.trusted_private": self.e2ee_forced_trusted_private,
|
||||||
|
# Supports the busy presence state described in MSC3026.
|
||||||
|
"org.matrix.msc3026.busy_presence": self.config.experimental.msc3026_enabled,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -310,6 +310,26 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||||
self.assertIsNotNone(new_state)
|
self.assertIsNotNone(new_state)
|
||||||
self.assertEquals(new_state.state, PresenceState.UNAVAILABLE)
|
self.assertEquals(new_state.state, PresenceState.UNAVAILABLE)
|
||||||
|
|
||||||
|
def test_busy_no_idle(self):
|
||||||
|
"""
|
||||||
|
Tests that a user setting their presence to busy but idling doesn't turn their
|
||||||
|
presence state into unavailable.
|
||||||
|
"""
|
||||||
|
user_id = "@foo:bar"
|
||||||
|
now = 5000000
|
||||||
|
|
||||||
|
state = UserPresenceState.default(user_id)
|
||||||
|
state = state.copy_and_replace(
|
||||||
|
state=PresenceState.BUSY,
|
||||||
|
last_active_ts=now - IDLE_TIMER - 1,
|
||||||
|
last_user_sync_ts=now,
|
||||||
|
)
|
||||||
|
|
||||||
|
new_state = handle_timeout(state, is_mine=True, syncing_user_ids=set(), now=now)
|
||||||
|
|
||||||
|
self.assertIsNotNone(new_state)
|
||||||
|
self.assertEquals(new_state.state, PresenceState.BUSY)
|
||||||
|
|
||||||
def test_sync_timeout(self):
|
def test_sync_timeout(self):
|
||||||
user_id = "@foo:bar"
|
user_id = "@foo:bar"
|
||||||
now = 5000000
|
now = 5000000
|
||||||
|
|
Loading…
Reference in a new issue