Skip to content

Commit

Permalink
partition API rate limiters by user
Browse files Browse the repository at this point in the history
  • Loading branch information
d-fischer committed Dec 29, 2022
1 parent 4d4b191 commit 1c314d6
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 13 deletions.
2 changes: 1 addition & 1 deletion packages/api/package.json
Expand Up @@ -36,7 +36,7 @@
"@d-fischer/cache-decorators": "^3.0.0",
"@d-fischer/detect-node": "^3.0.1",
"@d-fischer/logger": "^4.0.0",
"@d-fischer/rate-limiter": "^0.6.1",
"@d-fischer/rate-limiter": "^0.6.2",
"@d-fischer/shared-utils": "^3.4.0",
"@twurple/api-call": "6.0.0-pre.0",
"@twurple/common": "6.0.0-pre.0",
Expand Down
26 changes: 19 additions & 7 deletions packages/api/src/client/ApiClient.ts
@@ -1,12 +1,13 @@
import { isNode } from '@d-fischer/detect-node';
import { createLogger, type LoggerOptions } from '@d-fischer/logger';
import { TimeBasedRateLimiter } from '@d-fischer/rate-limiter';
import { callTwitchApiRaw, type TwitchApiCallFetchOptions, type TwitchApiCallOptions } from '@twurple/api-call';
import { PartitionedRateLimiter, PartitionedTimeBasedRateLimiter } from '@d-fischer/rate-limiter';
import { callTwitchApiRaw, type TwitchApiCallFetchOptions } from '@twurple/api-call';
import { type AuthProvider } from '@twurple/auth';
import { extractUserId, rtfm, type UserIdResolvable } from '@twurple/common';
import { HelixRateLimiter } from '../api/helix/HelixRateLimiter';
import { ConfigError } from '../errors/ConfigError';
import { BaseApiClient } from './BaseApiClient';
import { type ContextApiCallOptions } from './ContextApiCallOptions';
import { UserContextApiClient } from './UserContextApiClient';

/**
Expand Down Expand Up @@ -35,8 +36,9 @@ export interface ApiConfig {
* @private
*/
export interface TwitchApiCallOptionsInternal {
options: TwitchApiCallOptions;
options: ContextApiCallOptions;
clientId?: string;
userId?: string;
accessToken?: string;
authorizationType?: string;
fetchOptions?: TwitchApiCallFetchOptions;
Expand Down Expand Up @@ -65,13 +67,23 @@ export class ApiClient extends BaseApiClient {
config,
createLogger({ name: 'twurple:api:client', ...config.logger }),
isNode
? new HelixRateLimiter({ logger: rateLimitLoggerOptions })
: new TimeBasedRateLimiter({
? new PartitionedRateLimiter<TwitchApiCallOptionsInternal, Response>({
getPartitionKey: req => req.userId ?? null,
createChild: () => new HelixRateLimiter({ logger: rateLimitLoggerOptions })
})
: new PartitionedTimeBasedRateLimiter({
logger: rateLimitLoggerOptions,
bucketSize: 800,
timeFrame: 64000,
doRequest: async ({ options, clientId, accessToken, authorizationType, fetchOptions }) =>
await callTwitchApiRaw(options, clientId, accessToken, authorizationType, fetchOptions)
doRequest: async ({
options,
clientId,
accessToken,
authorizationType,
fetchOptions
}: TwitchApiCallOptionsInternal) =>
await callTwitchApiRaw(options, clientId, accessToken, authorizationType, fetchOptions),
getPartitionKey: req => req.userId ?? null
})
);
}
Expand Down
3 changes: 1 addition & 2 deletions packages/api/src/client/BaseApiClient.ts
Expand Up @@ -2,7 +2,6 @@ import { Cacheable, CachedGetter } from '@d-fischer/cache-decorators';
import type { Logger } from '@d-fischer/logger';
import type { RateLimiter } from '@d-fischer/rate-limiter';
import { mapOptional } from '@d-fischer/shared-utils';
import type { TwitchApiCallOptions } from '@twurple/api-call';
import {
callTwitchApi,
callTwitchApiRaw,
Expand Down Expand Up @@ -446,7 +445,7 @@ export class BaseApiClient {
}

private async _callApiInternal(
options: TwitchApiCallOptions,
options: ContextApiCallOptions,
clientId?: string,
accessToken?: string,
authorizationType?: string
Expand Down
2 changes: 0 additions & 2 deletions packages/auth/src/AccessToken.ts
Expand Up @@ -92,8 +92,6 @@ export function getExpiryDateOfAccessToken(token: ExpireableAccessToken): Date |
* A one-minute grace period is applied for smooth handling of API latency.
*
* @param token The access token.
*
* Defaults to a minute.
*/
export function accessTokenIsExpired(token: ExpireableAccessToken): boolean {
return mapNullable(getExpiryMillis(token), _ => Date.now() > _) ?? false;
Expand Down
2 changes: 1 addition & 1 deletion packages/chat/package.json
Expand Up @@ -36,7 +36,7 @@
"@d-fischer/cache-decorators": "^3.0.0",
"@d-fischer/deprecate": "^2.0.2",
"@d-fischer/logger": "^4.0.0",
"@d-fischer/rate-limiter": "^0.6.1",
"@d-fischer/rate-limiter": "^0.6.2",
"@d-fischer/shared-utils": "^3.4.0",
"@d-fischer/typed-event-emitter": "^3.3.0",
"@twurple/common": "6.0.0-pre.0",
Expand Down

0 comments on commit 1c314d6

Please sign in to comment.