Skip to content

Commit

Permalink
Merge pull request #6622 from davidwengier/RazorTelemetryDownloadTimeout
Browse files Browse the repository at this point in the history
Add a timeout for downloading razor telemetry
  • Loading branch information
davidwengier authored Nov 11, 2023
2 parents 3dc4d84 + 3f654aa commit 87bcff0
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 28 deletions.
1 change: 1 addition & 0 deletions l10n/bundle.l10n.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"Replace existing build and debug assets?": "Replace existing build and debug assets?",
"Could not locate .NET Core project in '{0}'. Assets were not generated.": "Could not locate .NET Core project in '{0}'. Assets were not generated.",
"Unable to generate assets to build and debug. {0}.": "Unable to generate assets to build and debug. {0}.",
"Downloading Razor Telemetry Package": "Downloading Razor Telemetry Package",
"Cannot load Razor language server because the directory was not found: '{0}'": "Cannot load Razor language server because the directory was not found: '{0}'",
"Could not find '{0}' in or above '{1}'.": "Could not find '{0}' in or above '{1}'.",
"Invalid trace setting for Razor language server. Defaulting to '{0}'": "Invalid trace setting for Razor language server. Defaulting to '{0}'",
Expand Down
13 changes: 11 additions & 2 deletions src/packageManager/downloadAndInstallPackages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ import { InstallationFailure, IntegrityCheckFailure } from '../omnisharp/logging
import { mkdirpSync } from 'fs-extra';
import { PackageInstallStart } from '../omnisharp/loggingEvents';
import { DownloadValidator } from './isValidDownload';
import { CancellationToken } from 'vscode';

export async function downloadAndInstallPackages(
packages: AbsolutePathPackage[],
provider: NetworkSettingsProvider,
eventStream: EventStream,
downloadValidator: DownloadValidator
downloadValidator: DownloadValidator,
token?: CancellationToken
): Promise<boolean> {
eventStream.post(new PackageInstallStart());
for (const pkg of packages) {
Expand All @@ -33,7 +35,14 @@ export async function downloadAndInstallPackages(
while (willTryInstallingPackage()) {
count = count + 1;
installationStage = 'downloadPackage';
const buffer = await DownloadFile(pkg.description, eventStream, provider, pkg.url, pkg.fallbackUrl);
const buffer = await DownloadFile(
pkg.description,
eventStream,
provider,
pkg.url,
pkg.fallbackUrl,
token
);
if (downloadValidator(buffer, pkg.integrity, eventStream)) {
installationStage = 'installPackage';
await InstallZip(buffer, pkg.description, pkg.installPath, pkg.binaries, eventStream);
Expand Down
15 changes: 11 additions & 4 deletions src/packageManager/fileDownloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,20 @@ import { NestedError } from '../nestedError';
import { parse as parseUrl } from 'url';
import { getProxyAgent } from './proxy';
import { NetworkSettingsProvider } from '../networkSettings';
import { CancellationToken } from 'vscode';

export async function DownloadFile(
description: string,
eventStream: EventStream,
networkSettingsProvider: NetworkSettingsProvider,
url: string,
fallbackUrl?: string
fallbackUrl?: string,
token?: CancellationToken
): Promise<Buffer> {
eventStream.post(new DownloadStart(description));

try {
const buffer = await downloadFile(description, url, eventStream, networkSettingsProvider);
const buffer = await downloadFile(description, url, eventStream, networkSettingsProvider, token);
eventStream.post(new DownloadSuccess(` Done!`));
return buffer;
} catch (primaryUrlError) {
Expand All @@ -54,7 +56,8 @@ async function downloadFile(
description: string,
urlString: string,
eventStream: EventStream,
networkSettingsProvider: NetworkSettingsProvider
networkSettingsProvider: NetworkSettingsProvider,
token?: CancellationToken
): Promise<Buffer> {
const url = parseUrl(urlString);
const networkSettings = networkSettingsProvider();
Expand All @@ -71,6 +74,10 @@ async function downloadFile(
const buffers: any[] = [];

return new Promise<Buffer>((resolve, reject) => {
token?.onCancellationRequested(() => {
return reject(new NestedError(`Cancelled downloading ${urlString}.`));
});

const request = https.request(options, (response) => {
if (response.statusCode === 301 || response.statusCode === 302) {
// Redirect - download from new location
Expand All @@ -81,7 +88,7 @@ async function downloadFile(
return reject(new NestedError('Missing location'));
}
return resolve(
downloadFile(description, response.headers.location, eventStream, networkSettingsProvider)
downloadFile(description, response.headers.location, eventStream, networkSettingsProvider, token)
);
} else if (response.statusCode !== 200) {
// Download failed - print error message
Expand Down
33 changes: 22 additions & 11 deletions src/razor/razorTelemetryDownloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import { PlatformInformation } from '../shared/platform';
import { PackageInstallation, LogPlatformInfo, InstallationSuccess } from '../omnisharp/loggingEvents';
import { EventStream } from '../eventStream';
Expand Down Expand Up @@ -42,17 +43,27 @@ export class RazorTelemetryDownloader {
if (packagesToInstall.length > 0) {
this.eventStream.post(new PackageInstallation(`Razor Telemetry Version = ${version}`));
this.eventStream.post(new LogPlatformInfo(this.platformInfo));
if (
await downloadAndInstallPackages(
packagesToInstall,
this.networkSettingsProvider,
this.eventStream,
isValidDownload
)
) {
this.eventStream.post(new InstallationSuccess());
return true;
}
await vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
title: vscode.l10n.t('Downloading Razor Telemetry Package'),
cancellable: true,
},
async (_, token) => {
if (
await downloadAndInstallPackages(
packagesToInstall,
this.networkSettingsProvider,
this.eventStream,
isValidDownload,
token
)
) {
this.eventStream.post(new InstallationSuccess());
return true;
}
}
);
}

return false;
Expand Down
13 changes: 12 additions & 1 deletion src/razor/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import * as path from 'path';
import * as vscode from 'vscode';
import * as vscodeapi from 'vscode';
import * as util from '../../common';
import { ExtensionContext } from 'vscode';
import { BlazorDebugConfigurationProvider } from './blazorDebug/blazorDebugConfigurationProvider';
import { CodeActionsHandler } from './codeActions/codeActionsHandler';
Expand Down Expand Up @@ -99,17 +100,27 @@ export async function activate(
// Save user's DOTNET_ROOT env-var value so server can recover the user setting when needed
env.DOTNET_ROOT_USER = process.env.DOTNET_ROOT ?? 'EMPTY';

let telemetryExtensionDllPath = '';
// Set up DevKit environment for telemetry
if (csharpDevkitExtension) {
await setupDevKitEnvironment(env, csharpDevkitExtension, logger);

const telemetryExtensionPath = path.join(
util.getExtensionPath(),
'.razortelemetry',
'Microsoft.VisualStudio.DevKit.Razor.dll'
);
if (await util.fileExists(telemetryExtensionPath)) {
telemetryExtensionDllPath = telemetryExtensionPath;
}
}

const languageServerClient = new RazorLanguageServerClient(
vscodeType,
languageServerDir,
razorTelemetryReporter,
vscodeTelemetryReporter,
csharpDevkitExtension !== undefined,
telemetryExtensionDllPath,
env,
dotnetInfo.path,
logger
Expand Down
11 changes: 3 additions & 8 deletions src/razor/src/razorLanguageServerClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as path from 'path';
import * as cp from 'child_process';
import { EventEmitter } from 'events';
import * as util from '../../common';
import * as vscode from 'vscode';
import { RequestHandler, RequestType } from 'vscode-jsonrpc';
import { GenericNotificationHandler, InitializeResult, LanguageClientOptions, State } from 'vscode-languageclient';
Expand Down Expand Up @@ -40,7 +38,7 @@ export class RazorLanguageServerClient implements vscode.Disposable {
private readonly languageServerDir: string,
private readonly razorTelemetryReporter: RazorTelemetryReporter,
private readonly vscodeTelemetryReporter: TelemetryReporter,
private readonly isCSharpDevKitActivated: boolean,
private readonly telemetryExtensionDllPath: string,
private readonly env: NodeJS.ProcessEnv,
private readonly dotnetExecutablePath: string,
private readonly logger: RazorLogger
Expand Down Expand Up @@ -249,13 +247,10 @@ export class RazorLanguageServerClient implements vscode.Disposable {
args.push('--UpdateBuffersForClosedDocuments');
args.push('true');

if (this.isCSharpDevKitActivated) {
if (this.telemetryExtensionDllPath.length > 0) {
args.push('--telemetryLevel', this.vscodeTelemetryReporter.telemetryLevel);
args.push('--sessionId', getSessionId());
args.push(
'--telemetryExtensionPath',
path.join(util.getExtensionPath(), '.razortelemetry', 'Microsoft.VisualStudio.DevKit.Razor.dll')
);
args.push('--telemetryExtensionPath', this.telemetryExtensionDllPath);
}
}

Expand Down
6 changes: 4 additions & 2 deletions tasks/offlinePackagingTasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { getPackageJSON } from '../tasks/packageJson';
import { createPackageAsync } from '../tasks/vsceTasks';
import { isValidDownload } from '../src/packageManager/isValidDownload';
import path = require('path');
import { CancellationToken } from 'vscode';
// There are no typings for this library.
// eslint-disable-next-line @typescript-eslint/no-var-requires
const argv = require('yargs').argv;
Expand Down Expand Up @@ -188,7 +189,8 @@ async function installDebugger(packageJSON: any, platformInfo: PlatformInformati
async function installPackageJsonDependency(
dependencyName: string,
packageJSON: any,
platformInfo: PlatformInformation
platformInfo: PlatformInformation,
token?: CancellationToken
) {
const eventStream = new EventStream();
const logger = new Logger((message) => process.stdout.write(message));
Expand All @@ -203,7 +205,7 @@ async function installPackageJsonDependency(
codeExtensionPath
);
const provider = () => new NetworkSettings('', true);
if (!(await downloadAndInstallPackages(packagesToInstall, provider, eventStream, isValidDownload))) {
if (!(await downloadAndInstallPackages(packagesToInstall, provider, eventStream, isValidDownload, token))) {
throw Error('Failed to download package.');
}
}
Expand Down

0 comments on commit 87bcff0

Please sign in to comment.