aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editors/code/src/main.ts55
-rw-r--r--editors/code/src/net.ts10
-rw-r--r--editors/code/src/persistent_state.ts11
3 files changed, 72 insertions, 4 deletions
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index bd99d696a..8c1610570 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -173,7 +173,9 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
173 if (!shouldCheckForNewNightly) return; 173 if (!shouldCheckForNewNightly) return;
174 } 174 }
175 175
176 const release = await fetchRelease("nightly").catch((e) => { 176 const release = await performDownloadWithRetryDialog(async () => {
177 return await fetchRelease("nightly", state.githubToken);
178 }, state).catch((e) => {
177 log.error(e); 179 log.error(e);
178 if (state.releaseId === undefined) { // Show error only for the initial download 180 if (state.releaseId === undefined) { // Show error only for the initial download
179 vscode.window.showErrorMessage(`Failed to download rust-analyzer nightly ${e}`); 181 vscode.window.showErrorMessage(`Failed to download rust-analyzer nightly ${e}`);
@@ -308,7 +310,10 @@ async function getServer(config: Config, state: PersistentState): Promise<string
308 if (userResponse !== "Download now") return dest; 310 if (userResponse !== "Download now") return dest;
309 } 311 }
310 312
311 const release = await fetchRelease(config.package.releaseTag); 313 const releaseTag = config.package.releaseTag;
314 const release = await performDownloadWithRetryDialog(async () => {
315 return await fetchRelease(releaseTag, state.githubToken);
316 }, state);
312 const artifact = release.assets.find(artifact => artifact.name === `rust-analyzer-${platform}.gz`); 317 const artifact = release.assets.find(artifact => artifact.name === `rust-analyzer-${platform}.gz`);
313 assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); 318 assert(!!artifact, `Bad release: ${JSON.stringify(release)}`);
314 319
@@ -333,3 +338,49 @@ async function getServer(config: Config, state: PersistentState): Promise<string
333 await state.updateServerVersion(config.package.version); 338 await state.updateServerVersion(config.package.version);
334 return dest; 339 return dest;
335} 340}
341
342async function performDownloadWithRetryDialog<T>(downloadFunc: () => Promise<T>, state: PersistentState): Promise<T> {
343 while (true) {
344 try {
345 return await downloadFunc();
346 } catch (e) {
347 let selected = await vscode.window.showErrorMessage("Failed perform download: " + e.message, {}, {
348 title: "Update Github Auth Token",
349 updateToken: true,
350 }, {
351 title: "Retry download",
352 retry: true,
353 }, {
354 title: "Dismiss",
355 });
356
357 if (selected?.updateToken) {
358 await queryForGithubToken(state);
359 continue;
360 } else if (selected?.retry) {
361 continue;
362 }
363 throw e;
364 };
365 }
366
367}
368
369async function queryForGithubToken(state: PersistentState): Promise<void> {
370 const githubTokenOptions: vscode.InputBoxOptions = {
371 value: state.githubToken,
372 password: true,
373 prompt: `
374 This dialog allows to store a Github authorization token.
375 The usage of an authorization token allows will increase the rate
376 limit on the use of Github APIs and can thereby prevent getting
377 throttled.
378 Auth tokens can be obtained at https://github.com/settings/tokens`,
379 };
380
381 const newToken = await vscode.window.showInputBox(githubTokenOptions);
382 if (newToken) {
383 log.info("Storing new github token");
384 await state.updateGithubToken(newToken);
385 }
386} \ No newline at end of file
diff --git a/editors/code/src/net.ts b/editors/code/src/net.ts
index 5eba2728d..d6194b63e 100644
--- a/editors/code/src/net.ts
+++ b/editors/code/src/net.ts
@@ -18,7 +18,8 @@ const OWNER = "rust-analyzer";
18const REPO = "rust-analyzer"; 18const REPO = "rust-analyzer";
19 19
20export async function fetchRelease( 20export async function fetchRelease(
21 releaseTag: string 21 releaseTag: string,
22 githubToken: string | null | undefined,
22): Promise<GithubRelease> { 23): Promise<GithubRelease> {
23 24
24 const apiEndpointPath = `/repos/${OWNER}/${REPO}/releases/tags/${releaseTag}`; 25 const apiEndpointPath = `/repos/${OWNER}/${REPO}/releases/tags/${releaseTag}`;
@@ -27,7 +28,12 @@ export async function fetchRelease(
27 28
28 log.debug("Issuing request for released artifacts metadata to", requestUrl); 29 log.debug("Issuing request for released artifacts metadata to", requestUrl);
29 30
30 const response = await fetch(requestUrl, { headers: { Accept: "application/vnd.github.v3+json" } }); 31 var headers: any = { Accept: "application/vnd.github.v3+json" };
32 if (githubToken != null) {
33 headers.Authorization = "token " + githubToken;
34 }
35
36 const response = await fetch(requestUrl, { headers: headers });
31 37
32 if (!response.ok) { 38 if (!response.ok) {
33 log.error("Error fetching artifact release info", { 39 log.error("Error fetching artifact release info", {
diff --git a/editors/code/src/persistent_state.ts b/editors/code/src/persistent_state.ts
index 5705eed81..afb652589 100644
--- a/editors/code/src/persistent_state.ts
+++ b/editors/code/src/persistent_state.ts
@@ -38,4 +38,15 @@ export class PersistentState {
38 async updateServerVersion(value: string | undefined) { 38 async updateServerVersion(value: string | undefined) {
39 await this.globalState.update("serverVersion", value); 39 await this.globalState.update("serverVersion", value);
40 } 40 }
41
42 /**
43 * Github authorization token.
44 * This is used for API requests against the Github API.
45 */
46 get githubToken(): string | undefined {
47 return this.globalState.get("githubToken");
48 }
49 async updateGithubToken(value: string | undefined) {
50 await this.globalState.update("githubToken", value);
51 }
41} 52}