|
6 | 6 |
|
7 | 7 | import { PackageVersion } from './packageVersion'; |
8 | 8 | import * as util from './common'; |
9 | | -import * as tmp from 'tmp'; |
10 | 9 | import { PlatformInformation } from './platform'; |
11 | 10 | import { OutgoingHttpHeaders } from 'http'; |
12 | 11 |
|
@@ -177,47 +176,74 @@ function getTargetBuild(builds: Build[], updateChannel: string): Build { |
177 | 176 | return needsUpdate(userVersion, targetVersion) ? targetBuild : undefined; |
178 | 177 | } |
179 | 178 |
|
| 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 | + |
180 | 219 | /** |
181 | 220 | * Download and parse the release list JSON from the GitHub API into a Build[]. |
182 | 221 | * @return Information about the released builds of the C/C++ extension. |
183 | 222 | */ |
184 | 223 | 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 | + } |
192 | 227 |
|
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' }; |
211 | 231 |
|
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 | + } |
223 | 249 | } |
0 commit comments