* Fix offline detection

8.8.8.8 blocks our requests. We can use microsoft.com instead, if our app is checking using microsoft, well, if microsoft is down we've learned that the app will have problems anyways , so if that is down it doesnt matter as much.

* fix variable name

* respond to linter

* respond to PR feedback, fix whitespace and ??
This commit is contained in:
Noah Gilson 2024-08-06 14:57:15 -07:00 коммит произвёл GitHub
Родитель ddac92e166
Коммит b1e85ced25
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
5 изменённых файлов: 60 добавлений и 35 удалений

4
vscode-dotnet-runtime-extension/package-lock.json сгенерированный
Просмотреть файл

@ -68,7 +68,7 @@
"run-script-os": "^1.1.6",
"semver": "^7.6.2",
"shelljs": "^0.8.5",
"typescript": "4.4.4",
"typescript": "^5.5.4",
"vscode-extension-telemetry": "^0.4.3",
"vscode-test": "^1.6.1"
},
@ -5553,7 +5553,7 @@
"run-script-os": "^1.1.6",
"semver": "^7.6.2",
"shelljs": "^0.8.5",
"typescript": "4.4.4",
"typescript": "^5.5.4",
"vscode-extension-telemetry": "^0.4.3",
"vscode-test": "^1.6.1"
}

Просмотреть файл

@ -1882,7 +1882,7 @@ util-deprecate@~1.0.1:
run-script-os "^1.1.6"
semver "^7.6.2"
shelljs "^0.8.5"
typescript "4.4.4"
typescript "^5.5.4"
vscode-extension-telemetry "^0.4.3"
vscode-test "^1.6.1"
optionalDependencies:

Просмотреть файл

@ -3,7 +3,6 @@
* The .NET Foundation licenses this file to you under the MIT license.
*--------------------------------------------------------------------------------------------*/
import * as cp from 'child_process';
import * as dns from 'dns';
import * as os from 'os';
import path = require('path');
@ -14,8 +13,10 @@ import {
DotnetAcquisitionScriptOutput,
DotnetAcquisitionTimeoutError,
DotnetAcquisitionUnexpectedError,
OffilneDetectionLogicTriggered,
DotnetOfflineFailure,
EventBasedError,
EventCancellationError,
} from '../EventStream/EventStreamEvents';
import { timeoutConstants } from '../Utils/ErrorHandler'
@ -31,6 +32,7 @@ import { IDotnetInstallationContext } from './IDotnetInstallationContext';
import { IInstallScriptAcquisitionWorker } from './IInstallScriptAcquisitionWorker';
import { DotnetInstall } from './DotnetInstall';
import { DotnetInstallMode } from './DotnetInstallMode';
import { WebRequestWorker } from '../Utils/WebRequestWorker';
/* tslint:disable:no-any */
/* tslint:disable:only-arrow-functions */
@ -47,28 +49,6 @@ You will need to restart VS Code after these changes. If PowerShell is still not
this.fileUtilities = new FileUtilities();
}
private async isOnline(installContext : IDotnetInstallationContext) : Promise<boolean>
{
const googleDNS = '8.8.8.8';
const expectedDNSResolutionTime = Math.max(installContext.timeoutSeconds * 10, 100); // Assumption: DNS resolution should take less than 1/100 of the time it'd take to download .NET.
// ... 100 ms is there as a default to prevent the dns resolver from throwing a runtime error if the user sets timeoutSeconds to 0.
const dnsResolver = new dns.Resolver({ timeout: expectedDNSResolutionTime });
await Promise.resolve(dnsResolver.resolve(googleDNS, function(error : any)
{
if (error)
{
return false;
}
return true;
})).then(function(dnsRes)
{
return dnsRes;
});
return false;
}
public async installDotnet(installContext: IDotnetInstallationContext, install : DotnetInstall): Promise<void>
{
const winOS = os.platform() === 'win32';
@ -99,7 +79,7 @@ You will need to restart VS Code after these changes. If PowerShell is still not
}
if (error)
{
if (!(await this.isOnline(installContext)))
if (!(await WebRequestWorker.isOnline(installContext.timeoutSeconds, this.eventStream)))
{
const offlineError = new EventBasedError('DotnetOfflineFailure', 'No internet connection detected: Cannot install .NET');
this.eventStream.post(new DotnetOfflineFailure(offlineError, install));

Просмотреть файл

@ -388,6 +388,10 @@ export class UserManualInstallFailure extends SuppressedAcquisitionError {
eventName = 'UserManualInstallFailure';
}
export class OffilneDetectionLogicTriggered extends SuppressedAcquisitionError {
eventName = 'OffilneDetectionLogicTriggered';
}
export class DotnetInstallationValidationMissed extends SuppressedAcquisitionError {
eventName = 'DotnetInstallationValidationMissed';
}
@ -496,11 +500,16 @@ export abstract class DotnetAcquisitionVersionError extends DotnetAcquisitionErr
}
public getProperties(telemetry = false): { [id: string]: string } | undefined {
return {ErrorMessage : this.error.message,
AcquisitionErrorInstallId : this.install?.installId ?? 'null',
...InstallToStrings(this.install!),
return this.install ? {ErrorMessage : this.error.message,
AcquisitionErrorInstallId : this.install.installId ?? 'null',
...InstallToStrings(this.install),
ErrorName : this.error.name,
StackTrace : this.error.stack ? this.error.stack : ''};
StackTrace : this.error.stack ?? ''}
:
{ErrorMessage : this.error.message,
AcquisitionErrorInstallId : 'null',
ErrorName : this.error.name,
StackTrace : this.error.stack ?? ''};
}
}

Просмотреть файл

@ -7,13 +7,25 @@ import axiosRetry from 'axios-retry';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { getProxySettings } from 'get-proxy-settings';
import { AxiosCacheInstance, buildMemoryStorage, setupCache } from 'axios-cache-interceptor';
import {DiskIsFullError, DotnetDownloadFailure, EventBasedError, SuppressedAcquisitionError, WebRequestError, WebRequestSent } from '../EventStream/EventStreamEvents';
import { getInstallFromContext } from './InstallIdUtilities';
import * as dns from 'dns';
import * as fs from 'fs';
import { promisify } from 'util';
import stream = require('stream');
import { IAcquisitionWorkerContext } from '../Acquisition/IAcquisitionWorkerContext';
import { IEventStream } from '../EventStream/EventStream';
import {
DiskIsFullError,
DotnetDownloadFailure,
DotnetOfflineFailure,
EventBasedError,
EventCancellationError,
OffilneDetectionLogicTriggered,
SuppressedAcquisitionError,
WebRequestError,
WebRequestSent
} from '../EventStream/EventStreamEvents';
import { getInstallFromContext } from './InstallIdUtilities';
/* tslint:disable:no-any */
export class WebRequestWorker
@ -72,9 +84,15 @@ export class WebRequestWorker
throw new EventBasedError('AxiosGetFailedWithInvalidURL', `Request to the url ${this.url} failed, as the URL is invalid.`);
}
const timeoutCancelTokenHook = new AbortController();
const timeout = setTimeout(() =>
const timeout = setTimeout(async () =>
{
timeoutCancelTokenHook.abort();
if(!(await WebRequestWorker.isOnline(this.websiteTimeoutMs / 1000, this.context.eventStream)))
{
const offlineError = new EventBasedError('DotnetOfflineFailure', 'No internet connection detected: Cannot install .NET');
this.context.eventStream.post(new DotnetOfflineFailure(offlineError, null));
throw offlineError;
}
const formattedError = new Error(`TIMEOUT: The request to ${this.url} timed out at ${this.websiteTimeoutMs} ms. This only occurs if your internet
or the url are experiencing connection difficulties; not if the server is being slow to respond. Check your connection, the url, and or increase the timeout value here: https://github.com/dotnet/vscode-dotnet-runtime/blob/main/Documentation/troubleshooting-runtime.md#install-script-timeouts`);
this.context.eventStream.post(new WebRequestError(new EventBasedError('WebRequestError', formattedError.message, formattedError.stack), null));
@ -95,6 +113,24 @@ export class WebRequestWorker
return this.makeWebRequest(true, retriesCount);
}
public static async isOnline(timeoutSec : number, eventStream : IEventStream) : Promise<boolean>
{
const microsoftServer = 'www.microsoft.com';
const expectedDNSResolutionTimeMs = Math.max(timeoutSec * 100, 100); // Assumption: DNS resolution should take less than 1/10 of the time it'd take to download .NET.
// ... 100 ms is there as a default to prevent the dns resolver from throwing a runtime error if the user sets timeoutSeconds to 0.
const dnsResolver = new dns.promises.Resolver({ timeout: expectedDNSResolutionTimeMs });
const couldConnect = await dnsResolver.resolve(microsoftServer).then(() =>
{
return true;
}).catch((error : any) =>
{
eventStream.post(new OffilneDetectionLogicTriggered((error as EventCancellationError), `DNS resolution failed at microsoft.com, ${JSON.stringify(error)}.`));
return false;
});
return couldConnect;
}
/**
*
* @param urlInQuestion