Skip to content

Commit 80716ae

Browse files
grdownsbobbrow
authored andcommitted
Grdowns/update channel4 (#2576)
* Remove redundant error telemetry * Check rate limit before attempting to download release JSON
1 parent 6d71c6d commit 80716ae

File tree

3 files changed

+96
-38
lines changed

3 files changed

+96
-38
lines changed

Extension/src/LanguageServer/extension.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,6 @@ async function checkAndApplyUpdate(updateChannel: string): Promise<void> {
339339
});
340340
}, (error: Error) => {
341341
// Handle getTargetBuildInfo rejection
342-
logFailure(error);
343342
reject(error);
344343
});
345344
});

Extension/src/common.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,4 +620,37 @@ export function downloadFileToDestination(urlStr: string, destinationPath: strin
620620
request.on('error', (error) => { reject(); });
621621
request.end();
622622
});
623+
}
624+
625+
export function downloadFileToStr(urlStr: string, headers?: OutgoingHttpHeaders): Promise<any> {
626+
return new Promise<string>((resolve, reject) => {
627+
let parsedUrl: url.Url = url.parse(urlStr);
628+
let request: ClientRequest = https.request({
629+
host: parsedUrl.host,
630+
path: parsedUrl.path,
631+
agent: getHttpsProxyAgent(),
632+
rejectUnauthorized: vscode.workspace.getConfiguration().get('http.proxyStrictSSL', true),
633+
headers: headers
634+
}, (response) => {
635+
if (response.statusCode === 301 || response.statusCode === 302) { // If redirected
636+
// Download from new location
637+
let redirectUrl: string;
638+
if (typeof response.headers.location === 'string') {
639+
redirectUrl = response.headers.location;
640+
} else {
641+
redirectUrl = response.headers.location[0];
642+
}
643+
return resolve(downloadFileToStr(redirectUrl, headers));
644+
}
645+
if (response.statusCode !== 200) { // If request is not successful
646+
return reject();
647+
}
648+
let downloadedData: string = '';
649+
response.on('data', (data) => { downloadedData += data; });
650+
response.on('error', (error) => { reject(); });
651+
response.on('end', () => { resolve(downloadedData); });
652+
});
653+
request.on('error', (error) => { reject(); });
654+
request.end();
655+
});
623656
}

Extension/src/githubAPI.ts

Lines changed: 63 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import { PackageVersion } from './packageVersion';
88
import * as util from './common';
9-
import * as tmp from 'tmp';
109
import { PlatformInformation } from './platform';
1110
import { OutgoingHttpHeaders } from 'http';
1211

@@ -177,47 +176,74 @@ function getTargetBuild(builds: Build[], updateChannel: string): Build {
177176
return needsUpdate(userVersion, targetVersion) ? targetBuild : undefined;
178177
}
179178

179+
interface Rate {
180+
remaining: number;
181+
}
182+
183+
interface RateLimit {
184+
rate: Rate;
185+
}
186+
187+
function isRate(input: any): input is Rate {
188+
return input && input.remaining && util.isNumber(input.remaining);
189+
}
190+
191+
function isRateLimit(input: any): input is RateLimit {
192+
return input && isRate(input.rate);
193+
}
194+
195+
async function getRateLimit(): Promise<RateLimit> {
196+
const header: OutgoingHttpHeaders = { 'User-Agent': 'vscode-cpptools' };
197+
const data: string = await util.downloadFileToStr('https://api.github.com/rate_limit', header)
198+
.catch(() => { throw new Error('Failed to download rate limit JSON'); });
199+
200+
let rateLimit: any;
201+
try {
202+
rateLimit = JSON.parse(data);
203+
} catch (error) {
204+
throw new Error('Failed to parse rate limit JSON');
205+
}
206+
207+
if (isRateLimit(rateLimit)) {
208+
return Promise.resolve(rateLimit);
209+
} else {
210+
throw new Error('Rate limit JSON is not of type RateLimit');
211+
}
212+
}
213+
214+
async function rateLimitExceeded(): Promise<boolean> {
215+
const rateLimit: RateLimit = await getRateLimit();
216+
return rateLimit.rate.remaining <= 0;
217+
}
218+
180219
/**
181220
* Download and parse the release list JSON from the GitHub API into a Build[].
182221
* @return Information about the released builds of the C/C++ extension.
183222
*/
184223
async function getReleaseJson(): Promise<Build[]> {
185-
return new Promise<Build[]>((resolve, reject) => {
186-
// Create temp file to hold JSON
187-
tmp.file(async (err, releaseJsonPath, fd, cleanupCallback) => {
188-
if (err) {
189-
reject(new Error('Failed to create release json file'));
190-
return;
191-
}
224+
if (await rateLimitExceeded()) {
225+
throw new Error('Failed to stay within GitHub API rate limit');
226+
}
192227

193-
try {
194-
// Download release JSON
195-
const releaseUrl: string = 'https://api.github.com/repos/Microsoft/vscode-cpptools/releases';
196-
const header: OutgoingHttpHeaders = { 'User-Agent': 'vscode-cpptools' };
197-
await util.downloadFileToDestination(releaseUrl, releaseJsonPath, header)
198-
.catch(() => { throw new Error('Failed to download release JSON'); });
199-
200-
// Read the release JSON file
201-
const fileContent: string = await util.readFileText(releaseJsonPath)
202-
.catch(() => { throw new Error('Failed to read release JSON file'); } );
203-
204-
// Parse the file
205-
let releaseJson: any;
206-
try {
207-
releaseJson = JSON.parse(fileContent);
208-
} catch (error) {
209-
throw new Error('Failed to parse release JSON');
210-
}
228+
// Download release JSON
229+
const releaseUrl: string = 'https://api.github.com/repos/Microsoft/vscode-cpptools/releases';
230+
const header: OutgoingHttpHeaders = { 'User-Agent': 'vscode-cpptools' };
211231

212-
// Type check
213-
if (isArrayOfBuilds(releaseJson)) {
214-
resolve(releaseJson);
215-
} else {
216-
reject(releaseJson);
217-
}
218-
} catch (error) {
219-
reject(error);
220-
}
221-
});
222-
});
232+
const data: string = await util.downloadFileToStr(releaseUrl, header)
233+
.catch(() => { throw new Error('Failed to download release JSON'); });
234+
235+
// Parse the file
236+
let releaseJson: any;
237+
try {
238+
releaseJson = JSON.parse(data);
239+
} catch (error) {
240+
throw new Error('Failed to parse release JSON');
241+
}
242+
243+
// Type check
244+
if (isArrayOfBuilds(releaseJson)) {
245+
return releaseJson;
246+
} else {
247+
throw new Error('Release JSON is not of type Build[]');
248+
}
223249
}

0 commit comments

Comments
 (0)