Exemple #1
0
    def __init__(self, client, max_messages: int = 500):
        #: The current user of this bot.
        #: This is automatically set after login.
        self._user = None  # type: BotUser

        #: The client associated with this connection.
        self.client = client

        #: The private channel cache.
        self._private_channels = {}

        #: The guilds the bot can see.
        self._guilds = {}  # type: Dict[int, Guild]

        #: The current user cache.
        self._users = {}

        #: The deque of messages.
        #: This is bounded to prevent the message cache from growing infinitely.
        self.messages = collections.deque(maxlen=max_messages)

        self.__shards_is_ready = collections.defaultdict(lambda: False)
        self.__voice_state_crap = collections.defaultdict(
            lambda *args, **kwargs: ((multio.Event(), multio.Event()), {})
        )
Exemple #2
0
    def __init__(self, session_id: str, token: str, endpoint: str,
                 user_id: str, guild_id: str):
        #: The current websocket object.
        self.websocket = None  # type: Websocket

        self._open = False

        self.session_id = session_id
        self.token = token
        self.user_id = user_id
        self.guild_id = guild_id
        self.sequence = 0
        self.ssrc_mapping = {}

        #: The main gateway object.
        self.main_gateway = None  # type: Gateway

        #: The current threading event used to signal if we need to stop heartbeating.
        self._stop_heartbeating = multio.Event()

        #: Voice server stuff
        self.endpoint = endpoint
        self.port = None  # type: int
        self.ssrc = None  # type: int
        self.secret_key = b""

        self._ready = multio.Event()
        self._got_secret_key = multio.Event()
Exemple #3
0
    async def typing(self) -> _typing.AsyncContextManager[None]:
        """
        :return: A context manager that sends typing repeatedly.

        Usage:

        .. code-block:: python3

            async with channel.typing:
                res = await do_long_action()

            await channel.messages.send("Long action:", res)
        """
        running = multio.Event()

        async def runner():
            await self.send_typing()
            while True:
                try:
                    async with multio.timeout_after(5):
                        await running.wait()
                except multio.asynclib.TaskTimeout:
                    await self.send_typing()
                else:
                    return

        async with multio.asynclib.task_manager() as tg:
            await multio.asynclib.spawn(tg, runner)
            try:
                yield
            finally:
                await multio.asynclib.cancel_task_group(tg)
Exemple #4
0
    def __init__(self, token: str, connection_state, *,
                 large_threshold: int = 250):
        """
        :param token: The bot token to connect with.
        """
        #: The token used to identify with.
        self.token = token

        #: The current websocket connection.
        self.websocket = None  # type: Websocket

        #: The current sequence number.
        self.sequence_num = 0

        #: The connection state used for this connection.
        self.state = connection_state

        #: The shard ID this gateway is representing.
        self.shard_id = 0
        #: The number of shards the client is connected to.
        self.shard_count = 1

        #: The current session ID for this gateway.
        self.session_id = None

        #: The current heartbeat statistic counter for this gateway.
        self.hb_stats = HeartbeatStats()

        #: The current game for this gateway.
        #: Only set when sending a change status packet.
        self.game = None
        #: The current status for this gateway.
        self.status = None

        #: The "large threshold" for this Gateway.
        #: For guilds with members above this number, offline members will not be sent.
        self.large_threshold = min(250, large_threshold)  # bound to 250

        #: The data format for this gateway.
        self.format = _fmt

        self._prev_seq = 0
        self._dispatches_handled = collections.Counter()
        self._enqueued_guilds = []
        self._stop_heartbeating = multio.Event()
        self._logger = None
        self._cached_gateway_url = None  # type: str
        self._open = False
        self._close_code = None
        self._close_reason = None
Exemple #5
0
    def __init__(self, gw_state: _GatewayState):
        #: The current state being used for this gateway.
        self.gw_state = gw_state

        #: The current heartbeat stats being used for this gateway.
        self.heartbeat_stats = HeartbeatStats()

        #: The current :class:`.BasicWebsocketWrapper` connected to Discord.
        self.websocket: BasicWebsocketWrapper = None

        #: The current task group for this gateway.
        self.task_group = None

        self._logger = None
        self._stop_heartbeating = multio.Event()
        self._dispatches_handled = Counter()
Exemple #6
0
    async def _start_heartbeating(self, heartbeat_interval: float) -> threading.Thread:
        """
        Starts the heartbeat thread.
        :param heartbeat_interval: The number of seconds between each heartbeat.
        """
        if not self._stop_heartbeating.is_set():
            # cancel some poor thread elsewhere
            await self._stop_heartbeating.set()
            del self._stop_heartbeating

        self._stop_heartbeating = multio.Event()

        # dont reference the task - it'll die by itself
        task = await curio.spawn(_heartbeat_loop(self, heartbeat_interval), daemon=True)

        return task
Exemple #7
0
    def __init__(self, bot, **kwargs) -> None:
        super().__init__(kwargs.get("id"), bot)

        #: If the guild is unavailable or not.
        #: If this is True, many fields return `None`.
        self.unavailable = kwargs.get("unavailable", False)

        # Placeholder values.
        #: The name of this guild.
        self.name = None  # type: str

        #: The icon hash of this guild.
        #: Used to construct the icon URL later.
        self.icon_hash = None  # type: str

        #: The splash hash of this guild.
        #: Used to construct the splash URL later.
        self.splash_hash = None  # type: str

        #: The AFK channel ID of this guild.
        self.afk_channel_id = None  # type: int

        #: The ID of the system channel for this guild.
        #: This is where welcome messages and the likes are sent.
        #: Effective replacement for default channel for bots.
        self.system_channel_id = None  # type: int

        #: The widget channel ID for this guild.
        self.widget_channel_id = None  # type: int

        #: The owner ID of this guild.
        self.owner_id = None  # type: int

        #: The AFK timeout for this guild. None if there's no AFK timeout.
        self.afk_timeout = None  # type: int

        #: The voice region of this guild.
        self.region = None  # type: str

        #: The features this guild has.
        self.features = None  # type: typing.List[str]

        #: The MFA level of this guild.
        self.mfa_level = MFALevel.DISABLED
        #: The verification level of this guild.
        self.verification_level = VerificationLevel.NONE
        #: The notification level of this guild.
        self.notification_level = NotificationLevel.ALL_MESSAGES
        #: The content filter level of this guild.
        self.content_filter_level = ContentFilterLevel.SCAN_NONE

        #: The shard ID this guild is associated with.
        self.shard_id = None  # type: int

        #: The roles that this guild has.
        self._roles = {}
        #: The members of this guild.
        self._members = {}
        #: The channels of this guild.
        self._channels = {}
        #: The emojis that this guild has.
        self._emojis = {}
        #: The voice states that this guild has.
        self._voice_states = {}

        #: The number of numbers this guild has.
        #: This is automatically updated.
        self.member_count = 0  # type: int

        #: Is this guild a large guild according to Discord?
        self._large = None  # type: bool

        #: Has this guild finished chunking?
        self._finished_chunking = multio.Event()
        self._chunks_left = 0

        #: The current voice client associated with this guild.
        self.voice_client = None

        #: The :class:`.GuildChannelWrapper` that wraps the channels in this Guild.
        self.channels = GuildChannelWrapper(self, self._channels)
        #: The :class:`.GuildRoleWrapper` that wraps the roles in this Guild.
        self.roles = GuildRoleWrapper(self, self._roles)
        #: The :class:`.GuildEmojiWrapper` that wraps the emojis in this Guild.
        self.emojis = GuildEmojiWrapper(self, self._emojis)
        #: The :class:`.GuildBanContainer` for this Guild.
        self.bans = GuildBanContainer(self)

        if kwargs:
            self.from_guild_create(**kwargs)