Esempio n. 1
0
class GlobalBridgeState(SerializableAttrs):
    remote_states: Optional[Dict[str, BridgeState]] = field(json="remoteState",
                                                            default=None)
    bridge_state: BridgeState = field(json="bridgeState")
Esempio n. 2
0
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
Esempio n. 3
0
class TypingNotification(SerializableAttrs):
    action: TypingAction
    timestamp: int
    group_id: Optional[GroupID] = field(default=None, json="groupId")
Esempio n. 4
0
class StickerPackOperations(SerializableAttrs):
    type: StickerPackOperation
    pack_id: str = field(json="packID")
    pack_key: str = field(json="packKey")
Esempio n. 5
0
class RemoteDelete(SerializableAttrs):
    target_sent_timestamp: int = field(json="targetSentTimestamp")
Esempio n. 6
0
class Sticker(SerializableAttrs):
    attachment: Attachment
    pack_id: str = field(json="packID")
    pack_key: str = field(json="packKey")
    sticker_id: int = field(json="stickerID")
Esempio n. 7
0
class Reaction(SerializableAttrs):
    emoji: str
    remove: bool = False
    target_author: Address = field(json="targetAuthor")
    target_sent_timestamp: int = field(json="targetSentTimestamp")
Esempio n. 8
0
class Capabilities(SerializableAttrs):
    gv2: bool = False
    storage: bool = False
    gv1_migration: bool = field(default=False, json="gv1-migration")
Esempio n. 9
0
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")