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)
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()
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
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
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, )