-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathRestManager.ts
104 lines (81 loc) · 2.8 KB
/
RestManager.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import { fetch } from 'undici';
const SPOTIFY_API_URL = 'https://api.spotify.com/v1';
interface RestManagerOptions {
clientID: string;
clientSecret: string
}
export class RestManager {
private token: string = '';
private authorization: string = '';
public stats: { requests: number; isRateLimited: boolean, nextRenew: number } = { requests: 0, isRateLimited: false, nextRenew: 0 };
public options: RestManagerOptions;
constructor(options: RestManagerOptions) {
this.options = options
this.authorization = `Basic ${Buffer.from(`${options.clientID}:${options.clientSecret}`).toString('base64',)}`;
this.refreshToken();
}
public async request<T>(endpoint: string): Promise<T> {
await this.renew();
const req = await fetch(`${SPOTIFY_API_URL}${endpoint}`,
{
headers: { Authorization: this.token },
})
const data = (await req.json()) as Promise<T>;
if (req.headers.get('x-ratelimit-remaining') === '0') {
this.handleRateLimited(Number(req.headers.get('x-ratelimit-reset')) * 1000);
throw new Error('[Poru Spotify] currently we got rate limited by spotify!')
}
this.stats.requests++;
return data;
}
public async getData<T>(url: string): Promise<T> {
await this.renew();
const req = await fetch(url,
{
headers: { Authorization: this.token },
})
const data = (await req.json()) as Promise<T>;
if (req.headers.get('x-ratelimit-remaining') === '0') {
this.handleRateLimited(Number(req.headers.get('x-ratelimit-reset')) * 1000);
throw new Error('[Poru Spotify] currently we got rate limited by spotify!')
}
this.stats.requests++;
return data;
}
private handleRateLimited(time: number): void {
this.stats.isRateLimited = true;
setTimeout(() => {
this.stats.isRateLimited = false;
}, time);
}
private async refreshToken() {
try {
const req = await fetch(
"https://accounts.spotify.com/api/token?grant_type=client_credentials",
{
method: "POST",
headers: {
Authorization: `${this.authorization}`,
"Content-Type": "application/x-www-form-urlencoded",
},
}
);
const { access_token, expires_in } = (await req.json()) as {
access_token?: string;
expires_in: number;
};
if (!access_token) throw new Error("[Poru Spotify] failed to fetch access token from spotify api")
this.token = `Bearer ${access_token}`;
this.stats.nextRenew = new Date().getTime() + expires_in * 1000;
} catch (e: any) {
if (e.status === 400) {
throw new Error("Spotify Plugin has been rate limited");
}
}
}
private async renew(): Promise<void> {
if (Date.now() >= this.stats.nextRenew) {
await this.refreshToken();
}
}
}