Skip to content

Commit 7a5191f

Browse files
committed
Starts handling rate limits (wip)
1 parent 555bd74 commit 7a5191f

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

src/errors.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,15 @@ export class ProviderRequestNotFoundError extends Error {
178178
Error.captureStackTrace?.(this, ProviderRequestNotFoundError);
179179
}
180180
}
181+
182+
export class ProviderRequestRateLimitError extends Error {
183+
constructor(
184+
public readonly original: Error,
185+
public readonly token: string,
186+
public readonly resetAt: number | undefined,
187+
) {
188+
super(original.message);
189+
190+
Error.captureStackTrace?.(this, ProviderRequestRateLimitError);
191+
}
192+
}

src/plus/github/github.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
AuthenticationErrorReason,
1414
ProviderRequestClientError,
1515
ProviderRequestNotFoundError,
16+
ProviderRequestRateLimitError,
1617
} from '../../errors';
1718
import { PagedResult, RepositoryVisibility } from '../../git/gitProvider';
1819
import {
@@ -1748,11 +1749,24 @@ export class GitHubApi implements Disposable {
17481749
throw new ProviderRequestNotFoundError(ex);
17491750
case 'FORBIDDEN':
17501751
throw new AuthenticationError('github', AuthenticationErrorReason.Forbidden, ex);
1752+
case 'RATE_LIMITED': {
1753+
let resetAt: number | undefined;
1754+
1755+
const reset = ex.headers?.['x-ratelimit-reset'];
1756+
if (reset != null) {
1757+
resetAt = parseInt(reset, 10);
1758+
if (Number.isNaN(resetAt)) {
1759+
resetAt = undefined;
1760+
}
1761+
}
1762+
1763+
throw new ProviderRequestRateLimitError(ex, token, resetAt);
1764+
}
17511765
}
17521766

17531767
void window.showErrorMessage(`GitHub request failed: ${ex.errors?.[0]?.message ?? ex.message}`, 'OK');
17541768
} else if (ex instanceof RequestError) {
1755-
this.handleRequestError(ex);
1769+
this.handleRequestError(ex, token);
17561770
} else {
17571771
void window.showErrorMessage(`GitHub request failed: ${ex.message}`, 'OK');
17581772
}
@@ -1770,7 +1784,7 @@ export class GitHubApi implements Disposable {
17701784
return (await this.octokit(token).request<R>(route, options)) as any;
17711785
} catch (ex) {
17721786
if (ex instanceof RequestError) {
1773-
this.handleRequestError(ex);
1787+
this.handleRequestError(ex, token);
17741788
} else {
17751789
void window.showErrorMessage(`GitHub request failed: ${ex.message}`, 'OK');
17761790
}
@@ -1779,7 +1793,7 @@ export class GitHubApi implements Disposable {
17791793
}
17801794
}
17811795

1782-
private handleRequestError(ex: RequestError): void {
1796+
private handleRequestError(ex: RequestError, token: string): void {
17831797
switch (ex.status) {
17841798
case 404: // Not found
17851799
case 410: // Gone
@@ -1789,6 +1803,19 @@ export class GitHubApi implements Disposable {
17891803
case 401: // Unauthorized
17901804
throw new AuthenticationError('github', AuthenticationErrorReason.Unauthorized, ex);
17911805
case 403: // Forbidden
1806+
if (ex.message.includes('rate limit exceeded')) {
1807+
let resetAt: number | undefined;
1808+
1809+
const reset = ex.response?.headers?.['x-ratelimit-reset'];
1810+
if (reset != null) {
1811+
resetAt = parseInt(reset, 10);
1812+
if (Number.isNaN(resetAt)) {
1813+
resetAt = undefined;
1814+
}
1815+
}
1816+
1817+
throw new ProviderRequestRateLimitError(ex, token, resetAt);
1818+
}
17921819
throw new AuthenticationError('github', AuthenticationErrorReason.Forbidden, ex);
17931820
case 500: // Internal Server Error
17941821
if (ex.response != null) {

0 commit comments

Comments
 (0)