<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { getWorkerBootstrapUrl } from 'vs/base/worker/defaultWorkerFactory';
import { Emitter, Event } from 'vs/base/common/event';
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { VSBuffer } from 'vs/base/common/buffer';
import { createMessageOfType, MessageType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { ILabelService } from 'vs/platform/label/common/label';
import { ILogService } from 'vs/platform/log/common/log';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import * as platform from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions';
import { IProductService } from 'vs/platform/product/common/product';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';

export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {

	private _toDispose = new DisposableStore();
	private _isTerminating: boolean = false;
	private _protocol?: IMessagePassingProtocol;

	private readonly _onDidExit = new Emitter<[number, string | null]>();
	readonly onExit: Event<[number, string | null]> = this._onDidExit.event;

	constructor(
		private readonly _autoStart: boolean,
		private readonly _extensions: Promise<IExtensionDescription[]>,
		private readonly _extensionHostLogsLocation: URI,
		@ITelemetryService private readonly _telemetryService: ITelemetryService,
		@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
		@ILabelService private readonly _labelService: ILabelService,
		@ILogService private readonly _logService: ILogService,
		@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
		@IProductService private readonly _productService: IProductService,
	) {

	}

	async start(): Promise<IMessagePassingProtocol> {

		if (!this._protocol) {

			const emitter = new Emitter<VSBuffer>();

			const url = getWorkerBootstrapUrl(require.toUrl('../worker/extensionHostWorkerMain.js'), 'WorkerExtensionHost');
			const worker = new Worker(url);

			worker.onmessage = (event) => {
				const { data } = event;
				if (!(data instanceof ArrayBuffer)) {
					console.warn('UNKNOWN data received', data);
					this._onDidExit.fire([77, 'UNKNOWN data received']);
					return;
				}

				emitter.fire(VSBuffer.wrap(new Uint8Array(data, 0, data.byteLength)));
			};

			worker.onerror = (event) => {
				console.error(event.error);
				this._onDidExit.fire([81, event.error]);
			};

			// keep for cleanup
			this._toDispose.add(emitter);
			this._toDispose.add(toDisposable(() => worker.terminate()));

			const protocol: IMessagePassingProtocol = {
				onMessage: emitter.event,
				send: vsbuf => {
					const data = vsbuf.buffer.buffer.slice(vsbuf.buffer.byteOffset, vsbuf.buffer.byteOffset + vsbuf.buffer.byteLength);
					worker.postMessage(data, [data]);
				}
			};

			// extension host handshake happens below
			// (1) <== wait for: Ready
			// (2) ==> send: init data
			// (3) <== wait for: Initialized

			await Event.toPromise(Event.filter(protocol.onMessage, msg => isMessageOfType(msg, MessageType.Ready)));
			protocol.send(VSBuffer.fromString(JSON.stringify(await this._createExtHostInitData())));
			await Event.toPromise(Event.filter(protocol.onMessage, msg => isMessageOfType(msg, MessageType.Initialized)));

			this._protocol = protocol;
		}
		return this._protocol;
<commit_msg>better worker error logging<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { getWorkerBootstrapUrl } from 'vs/base/worker/defaultWorkerFactory';
import { Emitter, Event } from 'vs/base/common/event';
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { VSBuffer } from 'vs/base/common/buffer';
import { createMessageOfType, MessageType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { ILabelService } from 'vs/platform/label/common/label';
import { ILogService } from 'vs/platform/log/common/log';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import * as platform from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions';
import { IProductService } from 'vs/platform/product/common/product';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';

export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {

	private _toDispose = new DisposableStore();
	private _isTerminating: boolean = false;
	private _protocol?: IMessagePassingProtocol;

	private readonly _onDidExit = new Emitter<[number, string | null]>();
	readonly onExit: Event<[number, string | null]> = this._onDidExit.event;

	constructor(
		private readonly _autoStart: boolean,
		private readonly _extensions: Promise<IExtensionDescription[]>,
		private readonly _extensionHostLogsLocation: URI,
		@ITelemetryService private readonly _telemetryService: ITelemetryService,
		@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
		@ILabelService private readonly _labelService: ILabelService,
		@ILogService private readonly _logService: ILogService,
		@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
		@IProductService private readonly _productService: IProductService,
	) {

	}

	async start(): Promise<IMessagePassingProtocol> {

		if (!this._protocol) {

			const emitter = new Emitter<VSBuffer>();

			const url = getWorkerBootstrapUrl(require.toUrl('../worker/extensionHostWorkerMain.js'), 'WorkerExtensionHost');
			const worker = new Worker(url);

			worker.onmessage = (event) => {
				const { data } = event;
				if (!(data instanceof ArrayBuffer)) {
					console.warn('UNKNOWN data received', data);
					this._onDidExit.fire([77, 'UNKNOWN data received']);
					return;
				}

				emitter.fire(VSBuffer.wrap(new Uint8Array(data, 0, data.byteLength)));
			};

			worker.onerror = (event) => {
				console.error(event.message, event.error);
				this._onDidExit.fire([81, event.message || event.error]);
			};

			// keep for cleanup
			this._toDispose.add(emitter);
			this._toDispose.add(toDisposable(() => worker.terminate()));

			const protocol: IMessagePassingProtocol = {
				onMessage: emitter.event,
				send: vsbuf => {
					const data = vsbuf.buffer.buffer.slice(vsbuf.buffer.byteOffset, vsbuf.buffer.byteOffset + vsbuf.buffer.byteLength);
					worker.postMessage(data, [data]);
				}
			};

			// extension host handshake happens below
			// (1) <== wait for: Ready
			// (2) ==> send: init data
			// (3) <== wait for: Initialized

			await Event.toPromise(Event.filter(protocol.onMessage, msg => isMessageOfType(msg, MessageType.Ready)));
			protocol.send(VSBuffer.fromString(JSON.stringify(await this._createExtHostInitData())));
			await Event.toPromise(Event.filter(protocol.onMessage, msg => isMessageOfType(msg, MessageType.Initialized)));

			this._protocol = protocol;
		}
		return this._protocol;

{'fraction_non_alphanumeric': 0.15539752856143624, 'fraction_numerical': 0.002098391233387736, 'mean_word_length': 4.031671554252199, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4630041', 'n_tokens_mistral': 2581, 'n_tokens_neox': 2337, 'n_words': 535}