Fix presence loop with unavailable/offline
Yes, again. Also removes echo presence states to simplify things.
This commit is contained in:
		| @@ -388,9 +388,7 @@ class Backend: | ||||
|                 await client.update_account_unread_counts() | ||||
|  | ||||
|                 if account.presence not in [ | ||||
|                     Presence.State.echo_invisible, | ||||
|                     Presence.State.invisible, | ||||
|                     Presence.State.offline, | ||||
|                     Presence.State.invisible, Presence.State.offline, | ||||
|                 ]: | ||||
|                     await client.update_receipt_marker(room_id, event_id) | ||||
|  | ||||
|   | ||||
| @@ -307,7 +307,7 @@ class MatrixClient(nio.AsyncClient): | ||||
|         ) | ||||
|  | ||||
|         # TODO: be able to set presence before logging in | ||||
|         item.set_fields(presence=Presence.State.echo_online, connecting=True) | ||||
|         item.set_fields(presence=Presence.State.online, connecting=True) | ||||
|         self._presence  = "online" | ||||
|         self.start_task = asyncio.ensure_future(self._start()) | ||||
|  | ||||
| @@ -327,9 +327,6 @@ class MatrixClient(nio.AsyncClient): | ||||
|         account        = self.models["accounts"][user_id] | ||||
|         self._presence = "offline" if state == "invisible" else state | ||||
|  | ||||
|         if state in ("online", "unavailable"): | ||||
|             state = f"echo_{state}" | ||||
|  | ||||
|         account.set_fields( | ||||
|             presence=Presence.State(state), status_msg=status_msg, | ||||
|         ) | ||||
| @@ -1386,7 +1383,6 @@ class MatrixClient(nio.AsyncClient): | ||||
|             return | ||||
|  | ||||
|         if self.models["accounts"][self.user_id].presence not in [ | ||||
|             Presence.State.echo_invisible, | ||||
|             Presence.State.invisible, | ||||
|             Presence.State.offline, | ||||
|         ]: | ||||
| @@ -1596,15 +1592,14 @@ class MatrixClient(nio.AsyncClient): | ||||
|  | ||||
|         account           = self.models["accounts"][self.user_id] | ||||
|         call_presence_api = True | ||||
|         new_presence      = presence | ||||
|         for_server        = "offline" if presence == "invisible" else presence | ||||
|         self._presence    = "offline" if presence == "invisible" else presence | ||||
|  | ||||
|         if status_msg is None: | ||||
|             status_msg = account.status_msg | ||||
|  | ||||
|         # Starting/stopping client if current/new presence is offline | ||||
|  | ||||
|         if new_presence == "offline": | ||||
|         if presence == "offline": | ||||
|             if account.presence == Presence.State.offline: | ||||
|                 return | ||||
|  | ||||
| @@ -1620,7 +1615,6 @@ class MatrixClient(nio.AsyncClient): | ||||
|             # We might receive a recent status_msg set from another client on | ||||
|             # startup, so don't try to set a new one immediatly. | ||||
|             # Presence though will be sent on first sync. | ||||
|             self._presence     = for_server | ||||
|             call_presence_api  = False | ||||
|             account.connecting = True | ||||
|             self.start_task    = asyncio.ensure_future(self._start()) | ||||
| @@ -1629,9 +1623,9 @@ class MatrixClient(nio.AsyncClient): | ||||
|  | ||||
|         if ( | ||||
|             Presence.State(presence) != account.presence and | ||||
|             new_presence             != "offline" | ||||
|             presence != "offline" | ||||
|         ): | ||||
|             account.presence = Presence.State("echo_" + new_presence) | ||||
|             account.presence = Presence.State(presence) | ||||
|  | ||||
|         # Saving new details in accounts.json | ||||
|  | ||||
| @@ -1639,7 +1633,7 @@ class MatrixClient(nio.AsyncClient): | ||||
|             account.save_presence = True | ||||
|  | ||||
|             await self.backend.saved_accounts.set( | ||||
|                 self.user_id, presence=new_presence, status_msg=status_msg, | ||||
|                 self.user_id, presence=presence, status_msg=status_msg, | ||||
|             ) | ||||
|         else: | ||||
|             account.save_presence = False | ||||
| @@ -1648,7 +1642,7 @@ class MatrixClient(nio.AsyncClient): | ||||
|  | ||||
|         if call_presence_api: | ||||
|             account.status_msg = status_msg | ||||
|             await super().set_presence(for_server, status_msg) | ||||
|             await super().set_presence(self._presence, status_msg) | ||||
|  | ||||
|  | ||||
|     async def import_keys(self, infile: str, passphrase: str) -> None: | ||||
|   | ||||
| @@ -870,20 +870,29 @@ class NioCallbacks: | ||||
|     async def onPresenceEvent( | ||||
|         self, ev: Union[nio.PresenceEvent, nio.PresenceGetResponse], | ||||
|     ) -> None: | ||||
|  | ||||
|         # Servers that send presence events support presence | ||||
|         self.models["accounts"][self.client.user_id].presence_support = True | ||||
|  | ||||
|         account  = self.models["accounts"].get(ev.user_id) | ||||
|         presence = self.client.backend.presences.get(ev.user_id, Presence()) | ||||
|         invisible = False | ||||
|  | ||||
|         if account: | ||||
|             client = self.client.backend.clients[ev.user_id] | ||||
|             invisible = account.presence == Presence.State.invisible | ||||
|             client    = self.client.backend.clients[ev.user_id] | ||||
|  | ||||
|             # Synapse is stupid enough to return an older presence state on | ||||
|             # sync, which then causes a never-ending loop of presence cycling. | ||||
|             # Let's hope they didn't screw up the get_presence API too: | ||||
|             ev = await client.get_presence(ev.user_id) | ||||
|  | ||||
|         invisible = account and "invisible" in account.presence.value | ||||
|             if ev.presence == "offline" and not invisible: | ||||
|                 to_set = account.presence.value | ||||
|                 await client.set_presence(to_set, account.status_msg) | ||||
|                 return | ||||
|             elif not (invisible and ev.presence != "offline"): | ||||
|                 client._presence = ev.presence | ||||
|  | ||||
|         if invisible and ev.presence == "offline": | ||||
|             presence.presence = Presence.State.invisible | ||||
| @@ -891,7 +900,15 @@ class NioCallbacks: | ||||
|             presence.presence = Presence.State(ev.presence) | ||||
|  | ||||
|         presence.currently_active = ev.currently_active or False | ||||
|         presence.status_msg       = ev.status_msg or "" | ||||
|  | ||||
|         # Restore status msg lost from server due to e.g. getting offline | ||||
|         if account and account.status_msg and not ev.status_msg: | ||||
|             if invisible: | ||||
|                 presence.status_msg = account.status_msg | ||||
|             else: | ||||
|                 await client.set_presence(ev.presence, account.status_msg) | ||||
|         else: | ||||
|             presence.status_msg = ev.status_msg or "" | ||||
|  | ||||
|         if ev.last_active_ago: | ||||
|             presence.last_active_at = datetime.now() - timedelta( | ||||
| @@ -909,58 +926,21 @@ class NioCallbacks: | ||||
|  | ||||
|         presence.update_members() | ||||
|  | ||||
|         # If presence event represents a change for one of our account | ||||
|         if account and account.presence != Presence.State.offline: | ||||
|             client = self.client.backend.clients[ev.user_id] | ||||
|  | ||||
|             # Ignore cases where we send a new presence to the server, but it | ||||
|             # returns an older state that doesn't match due to lag: | ||||
|             if ( | ||||
|                 account.presence == Presence.State.echo_invisible and | ||||
|                 ev.presence != Presence.State.offline.value | ||||
|             ) or ( | ||||
|                 account.presence == Presence.State.echo_unavailable and | ||||
|                 ev.presence != Presence.State.unavailable.value | ||||
|             ) or ( | ||||
|                 account.presence == Presence.State.echo_online and | ||||
|                 ev.presence != Presence.State.online.value | ||||
|             ): | ||||
|                 return | ||||
|  | ||||
|             # Do not fight back presence from other clients, unless server says | ||||
|             # we're offline, which happens if another client disconnected or we | ||||
|             # had a long connection issue. Note that this makes invisibility | ||||
|             # only possible if we're the only client using the account, or the | ||||
|             # other clients are invisible/offline themselves. | ||||
|             if ev.presence != Presence.State.offline.value: | ||||
|                 client._presence = ev.presence | ||||
|  | ||||
|             # Restore status msg lost from server due to e.g. getting offline | ||||
|             if not ev.status_msg and account.status_msg: | ||||
|                 if invisible: | ||||
|                     presence.status_msg = account.status_msg | ||||
|                 else: | ||||
|                     await client.set_presence(ev.presence, account.status_msg) | ||||
|  | ||||
|             # Save the presence to be restored next time we restart application | ||||
|             if account.save_presence: | ||||
|                 status_msg = presence.status_msg | ||||
|                 state      = presence.presence | ||||
|  | ||||
|                 if account.presence == Presence.State.echo_invisible: | ||||
|                     status_msg = account.status_msg | ||||
|                     state      = Presence.State.invisible | ||||
|                 elif state == Presence.State.echo_online: | ||||
|                     state = Presence.State.online | ||||
|                 elif state == Presence.State.echo_unavailable: | ||||
|                     state = Presence.State.unavailable | ||||
|  | ||||
|                 await self.client.backend.saved_accounts.set( | ||||
|                     user_id    = ev.user_id, | ||||
|                     status_msg = status_msg, | ||||
|                     presence   = state.value, | ||||
|                 ) | ||||
|  | ||||
|             presence.update_account() | ||||
|         else: | ||||
|         if not account: | ||||
|             self.client.backend.presences[ev.user_id] = presence | ||||
|             return | ||||
|  | ||||
|         client = self.client.backend.clients[ev.user_id] | ||||
|  | ||||
|         # Save the presence to be restored next time we restart application | ||||
|         if account.save_presence: | ||||
|             status_msg = presence.status_msg | ||||
|             state      = presence.presence | ||||
|  | ||||
|             await self.client.backend.saved_accounts.set( | ||||
|                 user_id    = ev.user_id, | ||||
|                 status_msg = status_msg, | ||||
|                 presence   = state.value, | ||||
|             ) | ||||
|  | ||||
|         presence.update_account() | ||||
|   | ||||
| @@ -12,12 +12,9 @@ if TYPE_CHECKING: | ||||
|  | ||||
| ORDER: Dict[str, int] = { | ||||
|     "online":           0, | ||||
|     "echo_online":      1, | ||||
|     "unavailable":      2, | ||||
|     "echo_unavailable": 3, | ||||
|     "invisible":        4, | ||||
|     "echo_invisible":   5, | ||||
|     "offline":          6, | ||||
|     "unavailable":      1, | ||||
|     "invisible":        2, | ||||
|     "offline":          3, | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -60,10 +57,6 @@ class Presence: | ||||
|         online      = auto() | ||||
|         invisible   = auto() | ||||
|  | ||||
|         echo_unavailable = auto() | ||||
|         echo_online      = auto() | ||||
|         echo_invisible   = auto() | ||||
|  | ||||
|         def __lt__(self, other: "Presence.State") -> bool: | ||||
|             return ORDER[self.value] < ORDER[other.value] | ||||
|  | ||||
|   | ||||
| @@ -13,8 +13,7 @@ Rectangle { | ||||
|  | ||||
|     implicitHeight: width | ||||
|     radius: width / 2 | ||||
|     opacity: | ||||
|         theme.controls.presence.opacity * (presence.includes("echo") ? 0.5 : 1) | ||||
|     opacity: theme.controls.presence.opacity | ||||
|  | ||||
|     color: | ||||
|         presence.includes("online") ? | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	