adjusted redit session manager to use bottleneck
parent
5f6d0671cf
commit
de4da43242
|
@ -1,18 +1,33 @@
|
||||||
import axios, { AxiosInstance, AxiosError } from 'axios';
|
import axios, { AxiosInstance, AxiosError, AxiosResponse, AxiosRequestConfig } from 'axios';
|
||||||
const qs = require('qs');
|
const qs = require('qs');
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import axiosRetry from 'axios-retry';
|
import axiosRetry from 'axios-retry';
|
||||||
import axiosThrottle from 'axios-request-throttle';
|
import Bottleneck from 'bottleneck';
|
||||||
import { DatabaseService } from '../../db/services/Database';
|
import { DatabaseService } from '../../db/services/Database';
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
class RedditSessionManager {
|
class RedditSessionManager {
|
||||||
private static instance: RedditSessionManager;
|
private static instance: RedditSessionManager;
|
||||||
public axiosInstance: AxiosInstance;
|
public readonly axiosInstance: AxiosInstance;
|
||||||
|
private limiter: Bottleneck;
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
axiosThrottle.use(axios, { requestsPerSecond: 1 }); // Throttle setup
|
|
||||||
|
// Initialize the Bottleneck limiter
|
||||||
|
this.limiter = new Bottleneck({
|
||||||
|
id: "reddit-limiter",
|
||||||
|
datastore: "ioredis",
|
||||||
|
clearDatastore: false,
|
||||||
|
clientOptions: {
|
||||||
|
host: process.env.REDIS_HOST,
|
||||||
|
port: Number(process.env.REDIS_PORT),
|
||||||
|
password: process.env.REDIS_PASSWORD || undefined, // Use undefined if no password is set
|
||||||
|
enableOfflineQueue: true
|
||||||
|
},
|
||||||
|
maxConcurrent: 1, // Maximum number of concurrent requests
|
||||||
|
minTime: 1000 // Minimum time between dispatches of requests in milliseconds
|
||||||
|
});
|
||||||
|
|
||||||
this.axiosInstance = axios.create({
|
this.axiosInstance = axios.create({
|
||||||
baseURL: 'https://oauth.reddit.com/', // Base URL for OAuth2 Reddit API
|
baseURL: 'https://oauth.reddit.com/', // Base URL for OAuth2 Reddit API
|
||||||
|
@ -20,6 +35,10 @@ class RedditSessionManager {
|
||||||
'User-Agent': 'CrossTalk PM/0.1 by Whitneywisconson'
|
'User-Agent': 'CrossTalk PM/0.1 by Whitneywisconson'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Wrap axios requests with the limiter
|
||||||
|
this.wrapAxiosInstance(this.axiosInstance);
|
||||||
|
|
||||||
axiosRetry(this.axiosInstance, {
|
axiosRetry(this.axiosInstance, {
|
||||||
retries: 3,
|
retries: 3,
|
||||||
retryDelay: this.retryDelayStrategy,
|
retryDelay: this.retryDelayStrategy,
|
||||||
|
@ -35,6 +54,10 @@ class RedditSessionManager {
|
||||||
return RedditSessionManager.instance;
|
return RedditSessionManager.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async shutdown(): Promise<void> {
|
||||||
|
await this.limiter.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
private async initializeAuthentication() {
|
private async initializeAuthentication() {
|
||||||
// Check the database for an existing token
|
// Check the database for an existing token
|
||||||
const currentToken = await DatabaseService.getCurrentOAuthToken(this.axiosInstance.defaults.baseURL as string);
|
const currentToken = await DatabaseService.getCurrentOAuthToken(this.axiosInstance.defaults.baseURL as string);
|
||||||
|
@ -103,6 +126,32 @@ class RedditSessionManager {
|
||||||
const status = error.response?.status ?? 0;
|
const status = error.response?.status ?? 0;
|
||||||
return status === 429 || status >= 400;
|
return status === 429 || status >= 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private wrapAxiosInstance(instance: AxiosInstance): void {
|
||||||
|
// Wrap the get method
|
||||||
|
const originalGet = instance.get;
|
||||||
|
instance.get = <T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R> => {
|
||||||
|
return this.limiter.schedule(() => originalGet.apply(instance, [url, config])) as Promise<R>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wrap the post method
|
||||||
|
const originalPost = instance.post;
|
||||||
|
instance.post = <T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R> => {
|
||||||
|
return this.limiter.schedule(() => originalPost.apply(instance, [url, data, config])) as Promise<R>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wrap the put method
|
||||||
|
const originalPut = instance.put;
|
||||||
|
instance.put = <T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R> => {
|
||||||
|
return this.limiter.schedule(() => originalPut.apply(instance, [url, data, config])) as Promise<R>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wrap the delete method
|
||||||
|
const originalDelete = instance.delete;
|
||||||
|
instance.delete = <T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R> => {
|
||||||
|
return this.limiter.schedule(() => originalDelete.apply(instance, [url, config])) as Promise<R>;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RedditSessionManager;
|
export default RedditSessionManager;
|
||||||
|
|
Loading…
Reference in New Issue