Exemple #1
0
    def update_rate_limits(
        self,
        compiled_route: routes.CompiledRoute,
        bucket_header: str,
        remaining_header: int,
        limit_header: int,
        date_header: datetime.datetime,
        reset_at_header: datetime.datetime,
    ) -> None:
        """Update the rate limits for a bucket using info from a response.

        Parameters
        ----------
        compiled_route : hikari.internal.routes.CompiledRoute
            The compiled _route to get the bucket for.
        bucket_header : typing.Optional[builtins.str]
            The `X-RateLimit-Bucket` header that was provided in the response.
        remaining_header : builtins.int
            The `X-RateLimit-Remaining` header cast to an `builtins.int`.
        limit_header : builtins.int
            The `X-RateLimit-Limit`header cast to an `builtins.int`.
        date_header : datetime.datetime
            The `Date` header value as a `datetime.datetime`.
        reset_at_header : datetime.datetime
            The `X-RateLimit-Reset` header value as a `datetime.datetime`.
        """
        self.routes_to_hashes[compiled_route.route] = bucket_header

        real_bucket_hash = compiled_route.create_real_bucket_hash(
            bucket_header)

        reset_after = (reset_at_header - date_header).total_seconds()
        reset_at_monotonic = time.monotonic() + reset_after

        if real_bucket_hash in self.real_hashes_to_buckets:
            bucket = self.real_hashes_to_buckets[real_bucket_hash]
            _LOGGER.debug(
                "updating %s with bucket %s [reset-after:%ss, limit:%s, remaining:%s]",
                compiled_route,
                real_bucket_hash,
                reset_after,
                limit_header,
                remaining_header,
            )
        else:
            bucket = RESTBucket(real_bucket_hash, compiled_route)
            self.real_hashes_to_buckets[real_bucket_hash] = bucket
            _LOGGER.debug(
                "remapping %s with bucket %s [reset-after:%ss, limit:%s, remaining:%s]",
                compiled_route,
                real_bucket_hash,
                reset_after,
                limit_header,
                remaining_header,
            )

        bucket.update_rate_limit(remaining_header, limit_header,
                                 reset_at_monotonic)
Exemple #2
0
    def acquire(self,
                compiled_route: routes.CompiledRoute) -> asyncio.Future[None]:
        """Acquire a bucket for the given route.

        Parameters
        ----------
        compiled_route : hikari.internal.routes.CompiledRoute
            The route to get the bucket for.

        Returns
        -------
        asyncio.Future[builtins.None]
            A future to await that completes when you are allowed to run
            your request logic.

        !!! note
            The returned future MUST be awaited, and will complete when your
            turn to make a call comes along. You are expected to await this and
            then immediately make your HTTP call. The returned future may
            already be completed if you can make the call immediately.
        """
        # Returns a future to await on to wait to be allowed to send the request, and a
        # bucket hash to use to update rate limits later.
        template = compiled_route.route

        if template in self.routes_to_hashes:
            bucket_hash = self.routes_to_hashes[template]
        else:
            bucket_hash = UNKNOWN_HASH
            self.routes_to_hashes[template] = bucket_hash

        real_bucket_hash = compiled_route.create_real_bucket_hash(bucket_hash)

        try:
            bucket = self.real_hashes_to_buckets[real_bucket_hash]
            _LOGGER.debug("%s is being mapped to existing bucket %s",
                          compiled_route, real_bucket_hash)
        except KeyError:
            _LOGGER.debug("%s is being mapped to new bucket %s",
                          compiled_route, real_bucket_hash)
            bucket = RESTBucket(real_bucket_hash, compiled_route)
            self.real_hashes_to_buckets[real_bucket_hash] = bucket

        now = time.monotonic()
        retry_after = bucket.reset_at - now

        if bucket.is_rate_limited(now) and retry_after > self.max_rate_limit:
            raise errors.RateLimitTooLongError(
                route=compiled_route,
                retry_after=retry_after,
                max_retry_after=self.max_rate_limit,
                reset_at=bucket.reset_at,
                limit=bucket.limit,
                period=bucket.period,
            )

        return bucket.acquire()
Exemple #3
0
    def acquire(
        self, compiled_route: routes.CompiledRoute
    ) -> typing.AsyncContextManager[None]:
        """Acquire a bucket for the given route.

        Parameters
        ----------
        compiled_route : hikari.internal.routes.CompiledRoute
            The route to get the bucket for.

        Returns
        -------
        typing.AsyncContextManager[builtins.None]
            A context manager to enter while doing the request.

        !!! note
            You MUST keep the context manager acquired during the whole of the
            request. From making the request until calling `update_rate_limits`.
        """
        template = compiled_route.route

        try:
            bucket_hash = self.routes_to_hashes[template]
            real_bucket_hash = compiled_route.create_real_bucket_hash(
                bucket_hash)
        except KeyError:
            real_bucket_hash = _create_unknown_hash(compiled_route)

        try:
            bucket = self.real_hashes_to_buckets[real_bucket_hash]
            _LOGGER.debug("%s is being mapped to existing bucket %s",
                          compiled_route, real_bucket_hash)
        except KeyError:
            _LOGGER.debug("%s is being mapped to new bucket %s",
                          compiled_route, real_bucket_hash)
            bucket = RESTBucket(real_bucket_hash, compiled_route,
                                self.max_rate_limit)
            self.real_hashes_to_buckets[real_bucket_hash] = bucket

        return bucket
Exemple #4
0
    def acquire(self, compiled_route: routes.CompiledRoute) -> RESTBucket:
        """Acquire a bucket for the given route.

        Parameters
        ----------
        compiled_route : hikari.internal.routes.CompiledRoute
            The route to get the bucket for.

        Returns
        -------
        hikari.impl.RESTBucket
            The bucket for this route.

        !!! note
            You MUST keep the context manager of the bucket acquired during the
            full duration of the request. From making the request until calling
            `update_rate_limits`.
        """
        try:
            bucket_hash = self.routes_to_hashes[compiled_route.route]
            real_bucket_hash = compiled_route.create_real_bucket_hash(
                bucket_hash)
        except KeyError:
            real_bucket_hash = _create_unknown_hash(compiled_route)

        try:
            bucket = self.real_hashes_to_buckets[real_bucket_hash]
            _LOGGER.debug("%s is being mapped to existing bucket %s",
                          compiled_route, real_bucket_hash)
        except KeyError:
            _LOGGER.debug("%s is being mapped to new bucket %s",
                          compiled_route, real_bucket_hash)
            bucket = RESTBucket(real_bucket_hash, compiled_route,
                                self.max_rate_limit)
            self.real_hashes_to_buckets[real_bucket_hash] = bucket

        return bucket
Exemple #5
0
    def update_rate_limits(
        self,
        compiled_route: routes.CompiledRoute,
        bucket_header: str,
        remaining_header: int,
        limit_header: int,
        reset_after: float,
    ) -> None:
        """Update the rate limits for a bucket using info from a response.

        Parameters
        ----------
        compiled_route : hikari.internal.routes.CompiledRoute
            The compiled route to get the bucket for.
        bucket_header : typing.Optional[builtins.str]
            The `X-RateLimit-Bucket` header that was provided in the response.
        remaining_header : builtins.int
            The `X-RateLimit-Remaining` header cast to an `builtins.int`.
        limit_header : builtins.int
            The `X-RateLimit-Limit` header cast to an `builtins.int`.
        reset_after : builtins.float
            The `X-RateLimit-Reset-After` header cast to a `builtins.float`.
        """
        self.routes_to_hashes[compiled_route.route] = bucket_header
        real_bucket_hash = compiled_route.create_real_bucket_hash(
            bucket_header)

        if bucket := self.real_hashes_to_buckets.get(real_bucket_hash):
            _LOGGER.debug(
                "updating %s with bucket %s [reset-after:%ss, limit:%s, remaining:%s]",
                compiled_route,
                real_bucket_hash,
                reset_after,
                limit_header,
                remaining_header,
            )