mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-14 01:25:37 -05:00
* Merge from vscode e3b9b8eefc062d68ba8a4b6a817162d132f3b533 * skip failing test * add comment
292 lines
12 KiB
TypeScript
292 lines
12 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { mark } from 'vs/base/common/performance';
|
|
import { domContentLoaded, addDisposableListener, EventType, addClass } from 'vs/base/browser/dom';
|
|
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
|
import { ILogService, ConsoleLogService, MultiplexLogService } from 'vs/platform/log/common/log';
|
|
import { Disposable } from 'vs/base/common/lifecycle';
|
|
import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
|
import { Workbench } from 'vs/workbench/browser/workbench';
|
|
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
|
import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel';
|
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
|
import { IProductService, IProductConfiguration } from 'vs/platform/product/common/product';
|
|
import { RemoteAgentService } from 'vs/workbench/services/remote/browser/remoteAgentServiceImpl';
|
|
import { RemoteAuthorityResolverService } from 'vs/platform/remote/browser/remoteAuthorityResolverService';
|
|
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
|
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
|
import { IFileService, IFileSystemProvider } from 'vs/platform/files/common/files';
|
|
import { FileService } from 'vs/platform/files/common/fileService';
|
|
import { Schemas } from 'vs/base/common/network';
|
|
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
|
import { URI } from 'vs/base/common/uri';
|
|
import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces';
|
|
import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService';
|
|
import { ConfigurationCache } from 'vs/workbench/services/configuration/browser/configurationCache';
|
|
import { ISignService } from 'vs/platform/sign/common/sign';
|
|
import { SignService } from 'vs/platform/sign/browser/signService';
|
|
import { hash } from 'vs/base/common/hash';
|
|
import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api';
|
|
import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider';
|
|
import { BACKUPS } from 'vs/platform/environment/common/environment';
|
|
import { joinPath } from 'vs/base/common/resources';
|
|
import { BrowserStorageService } from 'vs/platform/storage/browser/storageService';
|
|
import { IStorageService } from 'vs/platform/storage/common/storage';
|
|
import { getThemeTypeSelector, DARK, HIGH_CONTRAST, LIGHT } from 'vs/platform/theme/common/themeService';
|
|
import { InMemoryUserDataProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider';
|
|
import { registerWindowDriver } from 'vs/platform/driver/browser/driver';
|
|
import { BufferLogService } from 'vs/platform/log/common/bufferLog';
|
|
import { FileLogService } from 'vs/platform/log/common/fileLogService';
|
|
import { toLocalISOString } from 'vs/base/common/date';
|
|
import { IndexedDBLogProvider } from 'vs/workbench/services/log/browser/indexedDBLogProvider';
|
|
import { InMemoryLogProvider } from 'vs/workbench/services/log/common/inMemoryLogProvider';
|
|
|
|
class CodeRendererMain extends Disposable {
|
|
|
|
constructor(
|
|
private readonly domElement: HTMLElement,
|
|
private readonly configuration: IWorkbenchConstructionOptions
|
|
) {
|
|
super();
|
|
}
|
|
|
|
async open(): Promise<void> {
|
|
const services = await this.initServices();
|
|
|
|
await domContentLoaded();
|
|
mark('willStartWorkbench');
|
|
|
|
// Base Theme
|
|
this.restoreBaseTheme();
|
|
|
|
// Create Workbench
|
|
const workbench = new Workbench(
|
|
this.domElement,
|
|
services.serviceCollection,
|
|
services.logService
|
|
);
|
|
|
|
// Layout
|
|
this._register(addDisposableListener(window, EventType.RESIZE, () => workbench.layout()));
|
|
|
|
// Workbench Lifecycle
|
|
this._register(workbench.onBeforeShutdown(event => {
|
|
if (services.storageService.hasPendingUpdate) {
|
|
console.warn('Unload prevented: pending storage update');
|
|
event.veto(true); // prevent data loss from pending storage update
|
|
}
|
|
}));
|
|
this._register(workbench.onWillShutdown(() => {
|
|
services.storageService.close();
|
|
this.saveBaseTheme();
|
|
}));
|
|
this._register(workbench.onShutdown(() => this.dispose()));
|
|
|
|
// Driver
|
|
if (this.configuration.driver) {
|
|
(async () => this._register(await registerWindowDriver()))();
|
|
}
|
|
|
|
// Startup
|
|
workbench.startup();
|
|
}
|
|
|
|
private restoreBaseTheme(): void {
|
|
addClass(this.domElement, window.localStorage.getItem('baseTheme') || getThemeTypeSelector(DARK));
|
|
}
|
|
|
|
private saveBaseTheme(): void {
|
|
const classes = this.domElement.className;
|
|
const baseThemes = [DARK, LIGHT, HIGH_CONTRAST].map(baseTheme => getThemeTypeSelector(baseTheme));
|
|
for (const baseTheme of baseThemes) {
|
|
if (classes.indexOf(baseTheme) >= 0) {
|
|
window.localStorage.setItem('baseTheme', baseTheme);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: BrowserStorageService }> {
|
|
const serviceCollection = new ServiceCollection();
|
|
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// NOTE: DO NOT ADD ANY OTHER SERVICE INTO THE COLLECTION HERE.
|
|
// CONTRIBUTE IT VIA WORKBENCH.WEB.MAIN.TS AND registerSingleton().
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
// Log
|
|
const logsPath = URI.file(toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')).with({ scheme: 'vscode-log' });
|
|
const logService = new BufferLogService();
|
|
serviceCollection.set(ILogService, logService);
|
|
|
|
const payload = await this.resolveWorkspaceInitializationPayload();
|
|
|
|
// Environment
|
|
const environmentService = new BrowserWorkbenchEnvironmentService({ workspaceId: payload.id, logsPath, ...this.configuration });
|
|
serviceCollection.set(IWorkbenchEnvironmentService, environmentService);
|
|
|
|
// Product
|
|
const productService = this.createProductService();
|
|
serviceCollection.set(IProductService, productService);
|
|
|
|
// Remote
|
|
const remoteAuthorityResolverService = new RemoteAuthorityResolverService();
|
|
serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService);
|
|
|
|
// Signing
|
|
const signService = new SignService(environmentService.configuration.connectionToken);
|
|
serviceCollection.set(ISignService, signService);
|
|
|
|
// Remote Agent
|
|
const remoteAgentService = this._register(new RemoteAgentService(this.configuration.webSocketFactory, environmentService, productService, remoteAuthorityResolverService, signService, logService));
|
|
serviceCollection.set(IRemoteAgentService, remoteAgentService);
|
|
|
|
// Files
|
|
const fileService = this._register(new FileService(logService));
|
|
serviceCollection.set(IFileService, fileService);
|
|
|
|
// Logger
|
|
const indexedDBLogProvider = new IndexedDBLogProvider(logsPath.scheme);
|
|
(async () => {
|
|
try {
|
|
await indexedDBLogProvider.database;
|
|
|
|
fileService.registerProvider(logsPath.scheme, indexedDBLogProvider);
|
|
} catch (error) {
|
|
(<ILogService>logService).info('Error while creating indexedDB log provider. Falling back to in-memory log provider.');
|
|
(<ILogService>logService).error(error);
|
|
|
|
fileService.registerProvider(logsPath.scheme, new InMemoryLogProvider(logsPath.scheme));
|
|
}
|
|
|
|
const consoleLogService = new ConsoleLogService(logService.getLevel());
|
|
const fileLogService = new FileLogService('window', environmentService.logFile, logService.getLevel(), fileService);
|
|
logService.logger = new MultiplexLogService([consoleLogService, fileLogService]);
|
|
})();
|
|
|
|
// User Data Provider
|
|
let userDataProvider: IFileSystemProvider | undefined = this.configuration.userDataProvider;
|
|
const connection = remoteAgentService.getConnection();
|
|
if (connection) {
|
|
const channel = connection.getChannel<IChannel>(REMOTE_FILE_SYSTEM_CHANNEL_NAME);
|
|
const remoteFileSystemProvider = this._register(new RemoteExtensionsFileSystemProvider(channel, remoteAgentService.getEnvironment()));
|
|
|
|
fileService.registerProvider(Schemas.vscodeRemote, remoteFileSystemProvider);
|
|
|
|
if (!userDataProvider) {
|
|
const remoteUserDataUri = this.getRemoteUserDataUri();
|
|
if (remoteUserDataUri) {
|
|
userDataProvider = this._register(new FileUserDataProvider(remoteUserDataUri, joinPath(remoteUserDataUri, BACKUPS), remoteFileSystemProvider, environmentService));
|
|
}
|
|
}
|
|
}
|
|
if (!userDataProvider) {
|
|
userDataProvider = this._register(new InMemoryUserDataProvider());
|
|
}
|
|
fileService.registerProvider(Schemas.userData, userDataProvider);
|
|
|
|
// Long running services (workspace, config, storage)
|
|
const services = await Promise.all([
|
|
this.createWorkspaceService(payload, environmentService, fileService, remoteAgentService, logService).then(service => {
|
|
|
|
// Workspace
|
|
serviceCollection.set(IWorkspaceContextService, service);
|
|
|
|
// Configuration
|
|
serviceCollection.set(IConfigurationService, service);
|
|
|
|
return service;
|
|
}),
|
|
|
|
this.createStorageService(payload, environmentService, fileService, logService).then(service => {
|
|
|
|
// Storage
|
|
serviceCollection.set(IStorageService, service);
|
|
|
|
return service;
|
|
})
|
|
]);
|
|
|
|
return { serviceCollection, logService, storageService: services[1] };
|
|
}
|
|
|
|
private createProductService(): IProductService {
|
|
const element = document.getElementById('vscode-remote-product-configuration');
|
|
const productConfiguration: IProductConfiguration = {
|
|
...element ? JSON.parse(element.getAttribute('data-settings')!) : {
|
|
version: '1.38.0-unknown',
|
|
nameLong: 'Unknown',
|
|
extensionAllowedProposedApi: [],
|
|
}, ...{ urlProtocol: '' }
|
|
};
|
|
return { _serviceBrand: undefined, ...productConfiguration };
|
|
}
|
|
|
|
private async createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: IFileService, logService: ILogService): Promise<BrowserStorageService> {
|
|
const storageService = new BrowserStorageService(environmentService, fileService);
|
|
|
|
try {
|
|
await storageService.initialize(payload);
|
|
|
|
return storageService;
|
|
} catch (error) {
|
|
onUnexpectedError(error);
|
|
logService.error(error);
|
|
|
|
return storageService;
|
|
}
|
|
}
|
|
|
|
private async createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: FileService, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise<WorkspaceService> {
|
|
const workspaceService = new WorkspaceService({ remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache() }, environmentService, fileService, remoteAgentService);
|
|
|
|
try {
|
|
await workspaceService.initialize(payload);
|
|
|
|
return workspaceService;
|
|
} catch (error) {
|
|
onUnexpectedError(error);
|
|
logService.error(error);
|
|
|
|
return workspaceService;
|
|
}
|
|
}
|
|
|
|
private resolveWorkspaceInitializationPayload(): IWorkspaceInitializationPayload {
|
|
|
|
// Multi-root workspace
|
|
if (this.configuration.workspaceUri) {
|
|
return { id: hash(URI.revive(this.configuration.workspaceUri).toString()).toString(16), configPath: URI.revive(this.configuration.workspaceUri) };
|
|
}
|
|
|
|
// Single-folder workspace
|
|
if (this.configuration.folderUri) {
|
|
return { id: hash(URI.revive(this.configuration.folderUri).toString()).toString(16), folder: URI.revive(this.configuration.folderUri) };
|
|
}
|
|
|
|
return { id: 'empty-window' };
|
|
}
|
|
|
|
private getRemoteUserDataUri(): URI | null {
|
|
const element = document.getElementById('vscode-remote-user-data-uri');
|
|
if (element) {
|
|
const remoteUserDataPath = element.getAttribute('data-settings');
|
|
if (remoteUserDataPath) {
|
|
return joinPath(URI.revive(JSON.parse(remoteUserDataPath)), 'User');
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function main(domElement: HTMLElement, options: IWorkbenchConstructionOptions): Promise<void> {
|
|
const renderer = new CodeRendererMain(domElement, options);
|
|
|
|
return renderer.open();
|
|
}
|