Move Presence class to its own python file

It's not a ModelItem
This commit is contained in:
miruka
2020-07-18 18:33:57 -04:00
parent 692c78f398
commit 1b5a09c052
5 changed files with 124 additions and 107 deletions

View File

@@ -10,8 +10,10 @@ from typing import Any, Dict, List, Optional, Tuple, Type, Union
from uuid import UUID
import lxml # nosec
import nio
from ..presence import Presence
from ..utils import AutoStrEnum, auto
from .model_item import ModelItem
@@ -19,12 +21,6 @@ OptionalExceptionType = Union[Type[None], Type[Exception]]
ZERO_DATE = datetime.fromtimestamp(0)
PRESENCE_ORDER: Dict[str, int] = {
"online": 0,
"unavailable": 1,
"offline": 2,
}
class TypeSpecifier(AutoStrEnum):
"""Enum providing clarification of purpose for some matrix events."""
@@ -34,104 +30,6 @@ class TypeSpecifier(AutoStrEnum):
MembershipChange = auto()
@dataclass
class Presence:
"""Represents a single matrix user's presence fields.
These objects are stored in `Backend.presences`, indexed by user ID.
It must only be instanced when receiving a `PresenceEvent` or
registering an `Account` model item.
When receiving a `PresenceEvent`, we get or create a `Presence` object in
`Backend.presences` for the targeted user. If the user is registered in any
room, add its `Member` model item to `members`. Finally, update every
`Member` presence fields inside `members`.
When a room member is registered, we try to find a `Presence` in
`Backend.presences` for that user ID. If found, the `Member` item is added
to `members`.
When an Account model is registered, we create a `Presence` in
`Backend.presences` for the accountu's user ID whether the server supports
presence or not (we cannot know yet at this point),
and assign that `Account` to the `Presence.account` field.
Special attributes:
members: A `{room_id: Member}` dict for storing room members related to
this `Presence`. As each room has its own `Member`s objects, we
have to keep track of their presence fields. `Member`s are indexed
by room ID.
account: `Account` related to this `Presence`, if any. Should be
assigned when client starts (`MatrixClient._start()`) and
cleared when client stops (`MatrixClient._start()`).
"""
class State(AutoStrEnum):
offline = auto() # can mean offline, invisible or unknwon
unavailable = auto()
online = auto()
invisible = auto()
echo_unavailable = auto()
echo_online = auto()
echo_invisible = auto()
def __lt__(self, other: "Presence.State") -> bool:
return PRESENCE_ORDER[self.value] < PRESENCE_ORDER[other.value]
presence: State = State.offline
currently_active: bool = False
last_active_at: datetime = ZERO_DATE
status_msg: str = ""
members: Dict[str, "Member"] = field(default_factory=dict)
account: Optional["Account"] = None
def update_members(self) -> None:
"""Update presence fields of every `M̀ember` in `members`.
Currently it is only called when receiving a `PresenceEvent` and when
registering room members.
"""
for member in self.members.values():
member.set_fields(
presence = self.presence,
status_msg = self.status_msg,
last_active_at = self.last_active_at,
currently_active = self.currently_active,
)
def update_account(self) -> None:
"""Update presence fields of `Account` related to this `Presence`."""
# Do not update if account is changing to invisible.
# When setting presence to invisible, the server will give us a
# presence event telling us we are offline, but we do not want to set
# account presence to offline.
if (
not self.account or
self.presence == self.State.offline and
self.account.presence != self.State.echo_invisible
):
return
fields: Dict[str, Any] = {}
if self.account.presence == self.State.echo_invisible:
fields["presence"] = self.State.invisible
else:
fields["presence"] = self.presence
fields["status_msg"] = self.status_msg
fields["last_active_at"] = self.last_active_at
fields["currently_active"] = self.currently_active
self.account.set_fields(**fields)
@dataclass
class Account(ModelItem):
"""A logged in matrix account."""