Esempio n. 1
0
 def _get_self_reference(self):
     self_reference = self._self_reference
     if (self_reference is None):
         self_reference = WeakReferer(self)
         self._self_reference = self_reference
     
     return self_reference
Esempio n. 2
0
 def keep_alive(self, value):
     if value:
         while True:
             handler = self._handler
             if handler is None:
                 break
             
             handler = handler()
             if handler is None:
                 break
             
             if (self._key is not handler):
                 self._key = handler
             
             return
         
         key = self._key
         handler = self.client.http.handlers.set(key)
         if (handler is not key):
             self._key = handler
         self._handler = WeakReferer(handler)
         return
     else:
         handler = self._handler
         if handler is None:
             return
         
         handler = handler()
         if handler is None:
             return
         
         if self._key is handler:
             self._key = handler.copy()
         return
Esempio n. 3
0
    def __new__(cls, client):
        """
        Creates and binds a lavalink manager client.
        
        Parameters
        ----------
        client : ``Client``
            Hata client instance to extend.
        """
        if not isinstance(client, Client):
            raise TypeError(
                f'`client` parameter can be `{Client.__name__}`, got {client.__class__.__name__}; {client!r}.'
            )

        event_plugin = SolarLinkEventManager()
        client.events.register_plugin(event_plugin)

        client_reference = WeakReferer(client)

        self = object.__new__(cls)
        self._client_reference = client_reference
        self.nodes = set()
        self.players = {}
        self._player_queue = None
        self._events = event_plugin
        return self
Esempio n. 4
0
 def __new__(cls, channel, when):
     """
     Creates a new ``MessageHistoryCollector
     """
     self = object.__new__(cls)
     self.channel_reference = WeakReferer(channel)
     self.delay = 0.0
     self.handle = KOKORO.call_at(when, self)
     return self
Esempio n. 5
0
 def __new__(cls, client):
     """
     Creates a new ready state instance from the given parameters.
     
     Parameters
     ----------
     client : ``Client``
         The respective client instance.
     """
     self = object.__new__(cls)
     self.shard_count = client.shard_count
     self.shard_user_requesters = {}
     self.task = Task(self._runner(), KOKORO)
     self.shard_ready_waiter = None
     self.client_reference = WeakReferer(client)
     
     return self
Esempio n. 6
0
 def handler(self):
     """
     Returns the client's represented active handler if applicable.
     
     Returns
     -------
     handler : `None`, ``RateLimitHandler``
     """
     handler = self._handler
     if (handler is not None):
         handler = handler()
         if (handler is not None):
             return handler
     
     handler = self.client.http.handlers.get(self._key)
     if (handler is not None):
         self._handler = WeakReferer(handler)
     
     return handler
Esempio n. 7
0
    def start_auto_posting(self):
        """
        Starts auto posting bot stats.
        """
        if not self._auto_post_running:
            self._auto_post_running = True

            # We can only start it, if our client is running.
            client = self.client_reference()
            if (client is not None) and client.running:

                # Check edge case
                auto_post_handler = self._auto_post_handler
                if (auto_post_handler is None):

                    self._auto_post_handler = KOKORO.call_later(
                        AUTO_POST_INTERVAL,
                        _trigger_auto_post,
                        WeakReferer(self),
                    )
Esempio n. 8
0
async def _start_auto_post(client):
    """
    Client launch event handler starting auto post.
    
    This method is a coroutine.
    
    Parameters
    ----------
    client : ``Client``
    """
    top_gg_client = client.top_gg

    # update client is if required
    top_gg_client.client_id = client.id

    # Do not post initially, we might not have all the guilds loaded yet.
    if top_gg_client._auto_post_running:
        top_gg_client._auto_post_handler = KOKORO.call_later(
            AUTO_POST_INTERVAL,
            _trigger_auto_post,
            WeakReferer(top_gg_client),
        )
Esempio n. 9
0
 def __new__(cls, name, help_):
     """
     Creates a new command line command.
     
     Parameters
     ----------
     name : `str`
         The command's name.
     help : `str`
         The command's help message.
     """
     name = normalize_command_name(name)
     
     self = object.__new__(cls)
     self._command_category = None
     self.name = name
     self.help = None
     self._self_reference = None
     
     self._self_reference = WeakReferer(self)
     self._command_category = CommandLineCommandCategory(self, '')
     
     return self
Esempio n. 10
0
 def __new__(cls, parent, name):
     """
     Creates a new command line command category.
     
     Parameters
     ----------
     parent : ``CommandLineCommand``, ``CommandLineCommandCategory``
         The parent command or command category.
     name : `None`, `str`
         The command category's name.
     """
     if (name is not None):
         name = normalize_command_name(name)
     
     self = object.__new__(cls)
     self.name = name
     self._command_function = None
     self._command_categories = None
     self._self_reference = None
     self._parent_reference = parent._self_reference
     
     self._self_reference = WeakReferer(self)
     
     return self
Esempio n. 11
0
 async def wait_till_limits_expire(self):
     """
     Waits till the represented rate limits expire.
     
     This method is a coroutine.
     
     Raises
     ------
     RuntimeError
         If the method is called meanwhile `keep_alive` is `True`.
     
     Notes
     -----
     The waiting is implemented with weakreference callback, so the coroutine returns when the source callback is
     garbage collected. This also means waiting on the exact same limit multiple times causes misbehaviour.
     """
     handler = self._handler
     
     while True:
         if (handler is not None):
             handler = handler()
             if (handler is not None):
                 break
         
         handler = self.client.http.handlers.get(self._key)
         if handler is None:
             return
         
         break
     
     if handler is self._key:
         raise RuntimeError('Cannot use `.wait_till_limits_expire` meanwhile `keep_alive` is `True`.')
     
     future = Future(current_thread())
     self._handler = WeakReferer(handler, self._wait_till_limits_expire_callback(future))
     await future
Esempio n. 12
0
    def __new__(cls,
                name,
                *,
                checks=None,
                description=None,
                hidden=False,
                hidden_if_checks_fail=True):
        """
        Creates a new category with the given parameters.
        
        Parameters
        ----------
        name : `str`
            The category's name.
        checks : `None`, ``CheckBase``, ``CommandCheckWrapper`` or (`list`, `tuple`, `set`) of \
                (``CheckBase``, ``CommandCheckWrapper``) = `None`, Optional (Keyword only)
            The checks of the category.
        description : `Any` = `None`, Optional (Keyword only)
            Description of the category.
        hidden : `bool` = `False`, Optional (Keyword only)
            Whether the category should be hidden from help commands.
        hidden_if_checks_fail : `bool` = `True`, Optional (Keyword only)
            Whether the category should be hidden from help commands if it's checks fail. Defaults to `True`.
        
        Raises
        ------
        TypeError
            - If `name` is not `str`.
            - If `checks`'s type is incorrect.
            - If a `check`'s type is incorrect.
            - If `hidden` was not given as `bool`.
            - If `hidden_if_checks_fail` was not given as `bool`.
        """
        name_type = type(name)
        if name_type is str:
            pass
        elif issubclass(name_type, str):
            name = str(name)
        else:
            raise TypeError(
                f'`name` can be `str`, got {name_type.__name__}; {name!r}.')

        if not isinstance(hidden, bool):
            raise TypeError(
                f'`hidden` can be `bool`, got {hidden.__class__.__name__}; {hidden!r}.'
            )

        if not isinstance(hidden_if_checks_fail, bool):
            raise TypeError(
                f'`hidden_if_checks_fail` can be `bool`, got '
                f'{hidden_if_checks_fail.__class__.__name__}; {hidden_if_checks_fail!r}.'
            )

        name = raw_name_to_display(name)

        checks = validate_checks(checks)
        description = normalize_description(description)

        self = object.__new__(cls)
        self._checks = checks
        self._command_processor_reference = None
        self._error_handlers = None
        self._self_reference = None
        self.command_instances = set()
        self.display_name = name
        self.description = description
        self.name = name
        self.hidden = hidden
        self.hidden_if_checks_fail = hidden_if_checks_fail

        self._self_reference = WeakReferer(self)

        return self
Esempio n. 13
0
 def __new__(cls, client, group, limiter=None, keep_alive=False):
     """
     Creates a new rate limit proxy.
     
     Parameters
     ----------
     client : ``Client``
         Who's rate limits will be looked up.
     group : ``RateLimitGroup``
         The proxy's rate limit group to pull additional information.
     limiter : `None`, ``DiscordEntity`` = `None`, Optional
         What's rate limits will be looked up.
         
         The accepted types depend on the group's limiter:
         +-----------------------+-----------------------------------------------------------------------+
         | Respective limiter    |   Accepted values                                                     |
         +=======================+=======================================================================+
         | LIMITER_CHANNEL       | ``ChannelBase``, ``Message``                                          |
         +-----------------------+-----------------------------------------------------------------------+
         | LIMITER_GUILD         | ``Guild``, ``ChannelGuildBase``, ``Message``, ``Role``, ``Webhook``,  |
         |                       | ``WebhookRepr``                                                       |
         +-----------------------+-----------------------------------------------------------------------+
         | LIMITER_WEBHOOK       | ``Webhook``, ``WebhookRepr``                                          |
         +-----------------------+-----------------------------------------------------------------------+
         | LIMITER_INTERACTION   | ``InteractionEvent``                                                  |
         +-----------------------+-----------------------------------------------------------------------+
         | LIMITER_GLOBAL        | `Any`                                                                 |
         +-----------------------+-----------------------------------------------------------------------+
         | LIMITER_UNLIMITED     | `Any`                                                                 |
         +-----------------------+-----------------------------------------------------------------------+
         
         Note that at the case of `LIMITER_GUILD` partial objects will yield `.guild` as `None` so `ValueError`
         will still be raised.
     keep_alive : `bool` = `False`, Optional
         Whether the rate limit proxy should keep alive the respective rate limit handler. Defaults to `False`.
     
     Raises
     ------
     RuntimeError
         If the given `group`'s limiter is not any of the predefined ones. Note that limiters are compared by memory
         address and not by value.
     TypeError
         If `group` was not given as ``RateLimitGroup``.
     ValueError
         If the given `limiter` cannot be casted to `limiter_id` with the specified `group` .
     """
     if (type(group) is not RateLimitGroup):
         raise TypeError(
             f'`group` can be `{RateLimitGroup.__name__}`, got {group.__class__.__name__}; {group!r}.'
         )
     
     while True:
         group_limiter = group.limiter
         if group_limiter is LIMITER_GLOBAL:
             limiter_id = 0
             break
         
         elif group_limiter is LIMITER_UNLIMITED:
             limiter_id = 0
             break
         
         elif group_limiter is LIMITER_CHANNEL:
             if (limiter is not None):
                 if isinstance(limiter, ChannelBase):
                     limiter_id = limiter.id
                     break
                 
                 if isinstance(limiter, Message):
                     limiter_id = limiter.channel_id
                     break
         
         elif group_limiter is LIMITER_GUILD:
             if (limiter is not None):
                 if isinstance(limiter, Guild):
                     limiter_id = limiter.id
                     break
                 
                 if isinstance(limiter, (ChannelGuildBase, Message, Role, Webhook, WebhookRepr)):
                     
                     guild = limiter.guild
                     if (guild is not None):
                         limiter_id = limiter.id
                         break
         
         elif group_limiter is LIMITER_WEBHOOK:
             if (limiter is not None):
                 if isinstance(limiter, (Webhook, WebhookRepr)):
                     limiter_id = limiter.id
                     break
         
         elif group_limiter is LIMITER_INTERACTION:
             if (limiter is not None):
                 if isinstance(limiter, InteractionEvent):
                     limiter_id = limiter.id
                     break
         else:
             raise RuntimeError(
                 f'`{group!r}.limiter` is not any of the defined limit groups.'
             )
         
         raise ValueError(
             f'Cannot cast rate limit `{group!r}` group\'s rate `limit_id` from {limiter!r}.'
         )
     
     key = RateLimitHandler(group, limiter_id)
     
     if keep_alive:
         key = client.http.handlers.set(key)
         handler = WeakReferer(key)
     else:
         handler = None
     
     self = object.__new__(cls)
     self.client = client
     self.group = group
     self._handler = handler
     self._key = key
     return self
Esempio n. 14
0
    def __new__(cls,
                client,
                top_gg_token,
                auto_post_bot_stats=True,
                raise_on_top_gg_global_rate_limit=False):
        """
        Creates a new top.gg client instance.
        
        Parameters
        ----------
        client : ``Client``
            The discord client.
        top_gg_token : `str`
            Top.gg api token.
        auto_post_bot_stats : `bool` = `True`, Optional
            Whether auto post should be started as the client launches up.
        raise_on_top_gg_global_rate_limit : `bool` = `False`, Optional
            Whether ``TopGGGloballyRateLimited`` should be raised when the client gets globally rate limited.
        
        Raises
        ------
        TypeError
            - If `client` is not ``Client``.
            - If `top_gg_token` is not `str`.
            - If `auto_post_bot_stats` is not `bool`.
            - If `raise_on_top_gg_global_rate_limit` is not `bool` isinstance.
        """
        if not isinstance(client, Client):
            raise TypeError(
                f'`client` can be `{Client.__name__}`, got {client.__class__.__name__}; {client!r}.'
            )

        if not isinstance(top_gg_token, str):
            raise TypeError(
                f'`top_gg_token` can be `str`, got {top_gg_token.__class__.__name__}; {top_gg_token!r}.'
            )

        if not isinstance(auto_post_bot_stats, bool):
            raise TypeError(
                f'`auto_post_bot_stats` can be `bool`, got '
                f'{auto_post_bot_stats.__class__.__name__}; {auto_post_bot_stats!r}.'
            )

        if not isinstance(raise_on_top_gg_global_rate_limit, bool):
            raise TypeError(
                f'`raise_on_top_gg_global_rate_limit` can be `bool`, got '
                f'{raise_on_top_gg_global_rate_limit.__class__.__name__}; {raise_on_top_gg_global_rate_limit!r}.'
            )

        client_reference = WeakReferer(client)

        headers = IgnoreCaseMultiValueDictionary()
        headers[USER_AGENT] = LIBRARY_USER_AGENT
        headers[AUTHORIZATION] = top_gg_token

        self = object.__new__(cls)
        self.client_reference = client_reference
        self._auto_post_handler = None
        self._auto_post_running = auto_post_bot_stats
        self._raise_on_top_gg_global_rate_limit = raise_on_top_gg_global_rate_limit
        self._headers = headers

        self.client_id = client.id
        self.http = client.http
        self.top_gg_token = top_gg_token

        self._global_rate_limit_expires_at = 0.0
        self._rate_limit_handler_global = RateLimitGroup(
            RATE_LIMIT_GLOBAL_SIZE, RATE_LIMIT_GLOBAL_RESET_AFTER)
        self._rate_limit_handler_bots = RateLimitGroup(
            RATE_LIMIT_BOTS_SIZE, RATE_LIMIT_BOTS_RESET_AFTER)

        self._weekend_status_cache_time = 0.0
        self._weekend_status_cache_value = False
        self._weekend_status_request_task = None

        return self
Esempio n. 15
0
 def __new__(cls, prefix, *, precheck=None, mention_prefix_enabled=True, category_name_rule=None,
         command_name_rule=None, default_category_name=None, prefix_ignore_case=True):
     """
     Creates a new command processor instance.
     
     Parameters
     ----------
     prefix :  `str`, `tuple` of `str`, `callable`
         Prefix of the command processor.
         
         Can be given as a normal `callable` or as an `async-callable` as well, which should accept `1` parameter:
         
         +-------------------+---------------+
         | Name              | Type          |
         +===================+===============+
         | message           | ``Message``   |
         +-------------------+---------------+
         
         And return the following value:
         
         +-------------------+---------------------------+
         | Name              | Type                      |
         +===================+===========================+
         | prefix            | `str`, `tuple` of `str`   |
         +-------------------+---------------------------+
         
     precheck : `None`, `callable` = `None`, Optional (Keyword only)
         A function used to detect whether a message should be handled.
     mention_prefix_enabled : `bool` = `True`, Optional (Keyword only)
         Whether mentioning the client at the start of a message counts as prefix. Defaults to `True`.
     category_name_rule : `None`, `FunctionType` = `None`, Optional (Keyword only)
         Function to generate category display names. Defaults to `None`.
     command_name_rule : `None`, `FunctionType` = `None`, Optional (Keyword only)
         Function to generate command display names. Defaults to `None`.
     default_category_name : `None`, `str` = `None`, Optional (Keyword only)
         The command processor's default category's name. Defaults to `None`.
     prefix_ignore_case : `bool` = `True`
         Whether the prefix's case should be ignored.
     
     Raises
     ------
     TypeError
         - If `precheck` accepts bad amount of parameters.
         - If `precheck` is async.
         - If `mention_prefix_enabled` was not given as a `bool`.
         - If `category_name_rule` is not `None` nor `function`.
         - If `category_name_rule` is `async-function`.
         - If `category_name_rule` accepts bad amount of parameters.
         - If `category_name_rule` raises exception when `str` is passed to it.
         - If `category_name_rule` not returns `str`, when passing `str` to it.
         - If `command_name_rule` is not `None` nor `function`.
         - If `command_name_rule` is `async-function`.
         - If `command_name_rule` accepts bad amount of parameters.
         - If `command_name_rule` raises exception when `str` is passed to it.
         - If `command_name_rule` not returns `str`, when `str` is passed to it.
         - If `default_category_name` was not given neither as `None` nor as `str`.
         - If `prefix_ignore_case` was not given as `bool`.
         - Prefix's type is incorrect.
         - Prefix is a callable but accepts bad amount of parameters.
     ValueError
         - If `default_category_name`'s length is out of range [1:128].
     """
     if (category_name_rule is not None):
         test_name_rule(category_name_rule, 'category_name_rule')
     
     if (command_name_rule is not None):
         test_name_rule(command_name_rule, 'command_name_rule')
     
     if default_category_name is None:
         default_category_name = DEFAULT_CATEGORY_NAME
     else:
         default_category_name = validate_category_or_command_name(default_category_name)
     
     default_category = Category(default_category_name)
     
     if precheck is None:
         precheck = default_precheck
     else:
         test_precheck(precheck)
     
     mention_prefix_enabled = preconvert_bool(mention_prefix_enabled, 'mention_prefix_enabled')
     prefix_ignore_case = preconvert_bool(prefix_ignore_case, 'prefix_ignore_case')
     
     prefix_parser, prefix_getter = get_prefix_parser(prefix, prefix_ignore_case)
     
     self = object.__new__(cls)
     self._self_reference = None
     self._precheck = precheck
     self._error_handlers = None
     self._mention_prefix_enabled = mention_prefix_enabled
     self._category_name_rule = category_name_rule
     # Assign it later, exception may occur
     self._self_reference = WeakReferer(self)
     self._prefix_ignore_case = prefix_ignore_case
     self._prefix_parser = prefix_parser
     self._prefix_raw = prefix
     self._prefix_getter = prefix_getter
     self._default_category = default_category
     self._command_name_rule = command_name_rule
     self._category_name_rule = category_name_rule
     self.command_name_to_command = {}
     self.category_name_to_category = {}
     self.commands = set()
     self.categories = set()
     self._unknown_command = None
     
     self._self_reference = WeakReferer(self)
     
     default_category.set_command_processor(self)
     
     return self