class GlobalBridgeState(SerializableAttrs): remote_states: Optional[Dict[str, BridgeState]] = field(json="remoteState", default=None) bridge_state: BridgeState = field(json="bridgeState")
class BridgeState(SerializableAttrs): human_readable_errors: ClassVar[Dict[Optional[str], str]] = {} default_source: ClassVar[str] = "bridge" default_error_ttl: ClassVar[int] = 60 default_ok_ttl: ClassVar[int] = 240 state_event: BridgeStateEvent user_id: Optional[UserID] = None remote_id: Optional[str] = None remote_name: Optional[str] = None timestamp: Optional[int] = None ttl: int = 0 source: Optional[str] = None error: Optional[str] = None message: Optional[str] = None info: Optional[Dict[str, Any]] = None reason: Optional[str] = None send_attempts_: int = field(default=0, hidden=True) def fill(self) -> "BridgeState": self.timestamp = self.timestamp or int(time.time()) self.source = self.source or self.default_source if not self.ttl: self.ttl = (self.default_ok_ttl if self.state_event in ok_ish_states else self.default_error_ttl) if self.error: try: msg = self.human_readable_errors[self.error] except KeyError: pass else: self.message = msg.format( message=self.message) if self.message else msg return self def should_deduplicate(self, prev_state: Optional["BridgeState"]) -> bool: if (not prev_state or prev_state.state_event != self.state_event or prev_state.error != self.error): # If there's no previous state or the state was different, send this one. return False # If there's more than ⅘ of the previous pong's time-to-live left, drop this one return prev_state.timestamp + (prev_state.ttl / 5) > self.timestamp async def send(self, url: str, token: str, log: logging.Logger, log_sent: bool = True) -> bool: if not url: return True self.send_attempts_ += 1 headers = { "Authorization": f"Bearer {token}", "User-Agent": HTTPAPI.default_ua } try: async with aiohttp.ClientSession() as sess, sess.post( url, json=self.serialize(), headers=headers) as resp: if not 200 <= resp.status < 300: text = await resp.text() text = text.replace("\n", "\\n") log.warning(f"Unexpected status code {resp.status} " f"sending bridge state update: {text}") return False elif log_sent: log.debug(f"Sent new bridge state {self}") except Exception as e: log.warning(f"Failed to send updated bridge state: {e}") return False return True
class TypingNotification(SerializableAttrs): action: TypingAction timestamp: int group_id: Optional[GroupID] = field(default=None, json="groupId")
class StickerPackOperations(SerializableAttrs): type: StickerPackOperation pack_id: str = field(json="packID") pack_key: str = field(json="packKey")
class RemoteDelete(SerializableAttrs): target_sent_timestamp: int = field(json="targetSentTimestamp")
class Sticker(SerializableAttrs): attachment: Attachment pack_id: str = field(json="packID") pack_key: str = field(json="packKey") sticker_id: int = field(json="stickerID")
class Reaction(SerializableAttrs): emoji: str remove: bool = False target_author: Address = field(json="targetAuthor") target_sent_timestamp: int = field(json="targetSentTimestamp")
class Capabilities(SerializableAttrs): gv2: bool = False storage: bool = False gv1_migration: bool = field(default=False, json="gv1-migration")
class Contact(SerializableAttrs): address: Address name: Optional[str] = None color: Optional[str] = None profile_key: Optional[str] = field(default=None, json="profileKey") message_expiration_time: int = field(default=0, json="messageExpirationTime")