Path: blob/main/src/vs/sessions/electron-browser/sessions.main.ts
13389 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { localize } from '../../nls.js';6import product from '../../platform/product/common/product.js';7import { INativeWindowConfiguration, IWindowsConfiguration, hasNativeMenu } from '../../platform/window/common/window.js';8import { NativeWindow } from '../../workbench/electron-browser/window.js';9import { setFullscreen } from '../../base/browser/browser.js';10import { domContentLoaded } from '../../base/browser/dom.js';11import { onUnexpectedError } from '../../base/common/errors.js';12import { URI } from '../../base/common/uri.js';13import { INativeWorkbenchEnvironmentService, NativeWorkbenchEnvironmentService } from '../../workbench/services/environment/electron-browser/environmentService.js';14import { ServiceCollection } from '../../platform/instantiation/common/serviceCollection.js';15import { ILoggerService, ILogService, LogLevel } from '../../platform/log/common/log.js';16import { NativeWorkbenchStorageService } from '../../workbench/services/storage/electron-browser/storageService.js';17import { IWorkspaceContextService, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IAnyWorkspaceIdentifier, reviveIdentifier } from '../../platform/workspace/common/workspace.js';18import { IWorkbenchConfigurationService } from '../../workbench/services/configuration/common/configuration.js';19import { IStorageService } from '../../platform/storage/common/storage.js';20import { Disposable } from '../../base/common/lifecycle.js';21import { ISharedProcessService } from '../../platform/ipc/electron-browser/services.js';22import { IMainProcessService } from '../../platform/ipc/common/mainProcessService.js';23import { SharedProcessService } from '../../workbench/services/sharedProcess/electron-browser/sharedProcessService.js';24import { RemoteAuthorityResolverService } from '../../platform/remote/electron-browser/remoteAuthorityResolverService.js';25import { IRemoteAuthorityResolverService, RemoteConnectionType } from '../../platform/remote/common/remoteAuthorityResolver.js';26import { RemoteAgentService } from '../../workbench/services/remote/electron-browser/remoteAgentService.js';27import { IRemoteAgentService } from '../../workbench/services/remote/common/remoteAgentService.js';28import { FileService } from '../../platform/files/common/fileService.js';29import { IFileService } from '../../platform/files/common/files.js';30import { RemoteFileSystemProviderClient } from '../../workbench/services/remote/common/remoteFileSystemProviderClient.js';31import { ISignService } from '../../platform/sign/common/sign.js';32import { IProductService } from '../../platform/product/common/productService.js';33import { IUriIdentityService } from '../../platform/uriIdentity/common/uriIdentity.js';34import { UriIdentityService } from '../../platform/uriIdentity/common/uriIdentityService.js';35import { INativeKeyboardLayoutService, NativeKeyboardLayoutService } from '../../workbench/services/keybinding/electron-browser/nativeKeyboardLayoutService.js';36import { ElectronIPCMainProcessService } from '../../platform/ipc/electron-browser/mainProcessService.js';37import { LoggerChannelClient } from '../../platform/log/common/logIpc.js';38import { ProxyChannel } from '../../base/parts/ipc/common/ipc.js';39import { NativeLogService } from '../../workbench/services/log/electron-browser/logService.js';40import { WorkspaceTrustEnablementService, WorkspaceTrustManagementService } from '../../workbench/services/workspaces/common/workspaceTrust.js';41import { IWorkspaceTrustEnablementService, IWorkspaceTrustManagementService } from '../../platform/workspace/common/workspaceTrust.js';42import { safeStringify } from '../../base/common/objects.js';43import { IUtilityProcessWorkerWorkbenchService, UtilityProcessWorkerWorkbenchService } from '../../workbench/services/utilityProcess/electron-browser/utilityProcessWorkerWorkbenchService.js';44import { isCI, isMacintosh, isTahoeOrNewer } from '../../base/common/platform.js';45import { Schemas } from '../../base/common/network.js';46import { DiskFileSystemProvider } from '../../workbench/services/files/electron-browser/diskFileSystemProvider.js';47import { FileUserDataProvider } from '../../platform/userData/common/fileUserDataProvider.js';48import { IUserDataProfilesService, reviveProfile } from '../../platform/userDataProfile/common/userDataProfile.js';49import { UserDataProfilesService } from '../../platform/userDataProfile/common/userDataProfileIpc.js';50import { PolicyChannelClient } from '../../platform/policy/common/policyIpc.js';51import { IPolicyService } from '../../platform/policy/common/policy.js';52import { UserDataProfileService } from '../../workbench/services/userDataProfile/common/userDataProfileService.js';53import { IUserDataProfileService } from '../../workbench/services/userDataProfile/common/userDataProfile.js';54import { BrowserSocketFactory } from '../../platform/remote/browser/browserSocketFactory.js';55import { RemoteSocketFactoryService, IRemoteSocketFactoryService } from '../../platform/remote/common/remoteSocketFactoryService.js';56import { ElectronRemoteResourceLoader } from '../../platform/remote/electron-browser/electronRemoteResourceLoader.js';57import { IConfigurationService } from '../../platform/configuration/common/configuration.js';58import { applyZoom } from '../../platform/window/electron-browser/window.js';59import { mainWindow } from '../../base/browser/window.js';60import { IDefaultAccountService } from '../../platform/defaultAccount/common/defaultAccount.js';61import { DefaultAccountService } from '../../workbench/services/accounts/browser/defaultAccount.js';62import { AccountPolicyService, IAccountPolicyGateService } from '../../workbench/services/policies/common/accountPolicyService.js';63import { MultiplexPolicyService } from '../../workbench/services/policies/common/multiplexPolicyService.js';64import { Workbench as AgenticWorkbench } from '../browser/workbench.js';65import { NativeMenubarControl } from '../../workbench/electron-browser/parts/titlebar/menubarControl.js';66import { IWorkspaceEditingService } from '../../workbench/services/workspaces/common/workspaceEditing.js';67import { ConfigurationService } from '../services/configuration/browser/configurationService.js';68import { SessionsWorkspaceContextService } from '../services/workspace/browser/workspaceContextService.js';69import { getWorkspaceIdentifier } from '../../workbench/services/workspaces/browser/workspaces.js';7071export class SessionsMain extends Disposable {7273constructor(74private readonly configuration: INativeWindowConfiguration75) {76super();7778this.init();79}8081private init(): void {8283// Massage configuration file URIs84this.reviveUris();8586// Apply fullscreen early if configured87setFullscreen(!!this.configuration.fullscreen, mainWindow);88}8990private reviveUris() {9192// Workspace93const workspace = reviveIdentifier(this.configuration.workspace);94if (isWorkspaceIdentifier(workspace) || isSingleFolderWorkspaceIdentifier(workspace)) {95this.configuration.workspace = workspace;96}9798// Files99const filesToWait = this.configuration.filesToWait;100const filesToWaitPaths = filesToWait?.paths;101for (const paths of [filesToWaitPaths, this.configuration.filesToOpenOrCreate, this.configuration.filesToDiff, this.configuration.filesToMerge]) {102if (Array.isArray(paths)) {103for (const path of paths) {104if (path.fileUri) {105path.fileUri = URI.revive(path.fileUri);106}107}108}109}110111if (filesToWait) {112filesToWait.waitMarkerFileUri = URI.revive(filesToWait.waitMarkerFileUri);113}114}115116async open(): Promise<void> {117118// Init services and wait for DOM to be ready in parallel119const [services] = await Promise.all([this.initServices(), domContentLoaded(mainWindow)]);120121// Apply zoom level early122this.applyWindowZoomLevel(services.configurationService);123124// Create Agentic Workbench125const workbench = new AgenticWorkbench(mainWindow.document.body, {126extraClasses: this.getExtraClasses(),127}, services.serviceCollection, services.logService);128129// Listeners130this.registerListeners(workbench, services.storageService);131132// Startup133const instantiationService = workbench.startup();134135// Window136this._register(instantiationService.createInstance(NativeWindow));137138// Native menu controller139if (isMacintosh || hasNativeMenu(services.configurationService)) {140this._register(instantiationService.createInstance(NativeMenubarControl));141}142}143144private applyWindowZoomLevel(configurationService: IConfigurationService) {145let zoomLevel: number | undefined = undefined;146if (this.configuration.isCustomZoomLevel && typeof this.configuration.zoomLevel === 'number') {147zoomLevel = this.configuration.zoomLevel;148} else {149const windowConfig = configurationService.getValue<IWindowsConfiguration>();150zoomLevel = typeof windowConfig.window?.zoomLevel === 'number' ? windowConfig.window.zoomLevel : 0;151}152153applyZoom(zoomLevel, mainWindow);154}155156private getExtraClasses(): string[] {157if (isMacintosh && isTahoeOrNewer(this.configuration.os.release)) {158return ['macos-tahoe'];159}160161return [];162}163164private registerListeners(workbench: AgenticWorkbench, storageService: NativeWorkbenchStorageService): void {165166// Workbench Lifecycle167this._register(workbench.onWillShutdown(event => event.join(storageService.close(), { id: 'join.closeStorage', label: localize('join.closeStorage', "Saving UI state") })));168this._register(workbench.onDidShutdown(() => this.dispose()));169}170171private async initServices(): Promise<{ serviceCollection: ServiceCollection; logService: ILogService; storageService: NativeWorkbenchStorageService; configurationService: ConfigurationService }> {172const serviceCollection = new ServiceCollection();173174175// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!176//177// NOTE: Please do NOT register services here. Use `registerSingleton()`178// from `workbench.common.main.ts` if the service is shared between179// desktop and web or `sessions/sessions.desktop.main.ts` if the service180// is sessions desktop only.181//182// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!183184185// Main Process186const mainProcessService = this._register(new ElectronIPCMainProcessService(this.configuration.windowId));187serviceCollection.set(IMainProcessService, mainProcessService);188189// Product190const productService: IProductService = { _serviceBrand: undefined, ...product };191serviceCollection.set(IProductService, productService);192193// Environment194const environmentService = new NativeWorkbenchEnvironmentService(this.configuration, productService);195serviceCollection.set(INativeWorkbenchEnvironmentService, environmentService);196197// Logger198const loggers = this.configuration.loggers.map(loggerResource => ({ ...loggerResource, resource: URI.revive(loggerResource.resource) }));199const loggerService = new LoggerChannelClient(this.configuration.windowId, this.configuration.logLevel, environmentService.windowLogsPath, loggers, mainProcessService.getChannel('logger'));200serviceCollection.set(ILoggerService, loggerService);201202// Log203const logService = this._register(new NativeLogService(loggerService, environmentService));204serviceCollection.set(ILogService, logService);205if (isCI) {206logService.info('workbench#open()'); // marking workbench open helps to diagnose flaky integration/smoke tests207}208if (logService.getLevel() === LogLevel.Trace) {209logService.trace('workbench#open(): with configuration', safeStringify({ ...this.configuration, nls: undefined /* exclude large property */ }));210}211212// Default Account213const defaultAccountService = this._register(new DefaultAccountService(productService));214serviceCollection.set(IDefaultAccountService, defaultAccountService);215216// Policies217let policyService: IPolicyService;218const policyChannel = this.configuration.policiesData ? new PolicyChannelClient(this.configuration.policiesData, mainProcessService.getChannel('policy')) : undefined;219const accountPolicy = new AccountPolicyService(logService, defaultAccountService, policyChannel);220if (policyChannel) {221policyService = new MultiplexPolicyService([policyChannel, accountPolicy], logService);222} else {223policyService = accountPolicy;224}225serviceCollection.set(IPolicyService, policyService);226serviceCollection.set(IAccountPolicyGateService, accountPolicy);227228// Shared Process229const sharedProcessService = new SharedProcessService(this.configuration.windowId, logService);230serviceCollection.set(ISharedProcessService, sharedProcessService);231232// Utility Process Worker233const utilityProcessWorkerWorkbenchService = new UtilityProcessWorkerWorkbenchService(this.configuration.windowId, logService, mainProcessService);234serviceCollection.set(IUtilityProcessWorkerWorkbenchService, utilityProcessWorkerWorkbenchService);235236// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!237//238// NOTE: Please do NOT register services here. Use `registerSingleton()`239// from `workbench.common.main.ts` if the service is shared between240// desktop and web or `sessions/sessions.desktop.main.ts` if the service241// is sessions desktop only.242//243// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!244245246// Sign247const signService = ProxyChannel.toService<ISignService>(mainProcessService.getChannel('sign'));248serviceCollection.set(ISignService, signService);249250// Files251const fileService = this._register(new FileService(logService));252serviceCollection.set(IFileService, fileService);253254// Remote255const remoteAuthorityResolverService = new RemoteAuthorityResolverService(productService, new ElectronRemoteResourceLoader(environmentService.window.id, mainProcessService, fileService));256serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService);257258// Local Files259const diskFileSystemProvider = this._register(new DiskFileSystemProvider(mainProcessService, utilityProcessWorkerWorkbenchService, logService, loggerService));260fileService.registerProvider(Schemas.file, diskFileSystemProvider);261262// URI Identity263const uriIdentityService = new UriIdentityService(fileService);264serviceCollection.set(IUriIdentityService, uriIdentityService);265266// User Data Profiles267const userDataProfilesService = new UserDataProfilesService(this.configuration.profiles.all, URI.revive(this.configuration.profiles.home).with({ scheme: environmentService.userRoamingDataHome.scheme }), mainProcessService.getChannel('userDataProfiles'));268serviceCollection.set(IUserDataProfilesService, userDataProfilesService);269const userDataProfileService = new UserDataProfileService(reviveProfile(this.configuration.profiles.profile, userDataProfilesService.profilesHome.scheme));270serviceCollection.set(IUserDataProfileService, userDataProfileService);271272// Use FileUserDataProvider for user data to273// enable atomic read / write operations.274fileService.registerProvider(Schemas.vscodeUserData, this._register(new FileUserDataProvider(Schemas.file, diskFileSystemProvider, Schemas.vscodeUserData, userDataProfilesService, uriIdentityService, logService)));275276// Remote Agent277const remoteSocketFactoryService = new RemoteSocketFactoryService();278remoteSocketFactoryService.register(RemoteConnectionType.WebSocket, new BrowserSocketFactory(null));279serviceCollection.set(IRemoteSocketFactoryService, remoteSocketFactoryService);280const remoteAgentService = this._register(new RemoteAgentService(remoteSocketFactoryService, userDataProfileService, environmentService, productService, remoteAuthorityResolverService, signService, logService));281serviceCollection.set(IRemoteAgentService, remoteAgentService);282283// Remote Files284this._register(RemoteFileSystemProviderClient.register(remoteAgentService, fileService, logService));285286// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!287//288// NOTE: Please do NOT register services here. Use `registerSingleton()`289// from `workbench.common.main.ts` if the service is shared between290// desktop and web or `sessions/sessions.desktop.main.ts` if the service291// is sessions desktop only.292//293// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!294295const workspaceIdentifier = getWorkspaceIdentifier(environmentService.agentSessionsWorkspace);296const workspaceContextService = new SessionsWorkspaceContextService(workspaceIdentifier, uriIdentityService);297298// Workspace299serviceCollection.set(IWorkspaceContextService, workspaceContextService);300serviceCollection.set(IWorkspaceEditingService, workspaceContextService);301302const [configurationService, storageService] = await Promise.all([303this.createConfigurationService(workspaceContextService, userDataProfileService, uriIdentityService, fileService, logService, policyService).then(configurationService => {304305// Configuration306serviceCollection.set(IWorkbenchConfigurationService, configurationService);307308return configurationService;309}),310311this.createStorageService(workspaceIdentifier, environmentService, userDataProfileService, userDataProfilesService, mainProcessService).then(service => {312313// Storage314serviceCollection.set(IStorageService, service);315316return service;317}),318319this.createKeyboardLayoutService(mainProcessService).then(service => {320321// KeyboardLayout322serviceCollection.set(INativeKeyboardLayoutService, service);323324return service;325})326]);327328// Workspace Trust Service329const workspaceTrustEnablementService = new WorkspaceTrustEnablementService(configurationService, environmentService);330serviceCollection.set(IWorkspaceTrustEnablementService, workspaceTrustEnablementService);331332const workspaceTrustManagementService = new WorkspaceTrustManagementService(configurationService, remoteAuthorityResolverService, storageService, uriIdentityService, environmentService, workspaceContextService, workspaceTrustEnablementService, fileService);333serviceCollection.set(IWorkspaceTrustManagementService, workspaceTrustManagementService);334335336// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!337//338// NOTE: Please do NOT register services here. Use `registerSingleton()`339// from `workbench.common.main.ts` if the service is shared between340// desktop and web or `sessions/sessions.desktop.main.ts` if the service341// is sessions desktop only.342//343// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!344345346return { serviceCollection, logService, storageService, configurationService };347}348349private async createConfigurationService(350workspaceContextService: SessionsWorkspaceContextService,351userDataProfileService: IUserDataProfileService,352uriIdentityService: IUriIdentityService,353fileService: FileService,354logService: ILogService,355policyService: IPolicyService356): Promise<ConfigurationService> {357const configurationService = new ConfigurationService(userDataProfileService, workspaceContextService, uriIdentityService, fileService, policyService, logService);358try {359await configurationService.initialize();360} catch (error) {361onUnexpectedError(error);362}363364return configurationService;365}366367private async createStorageService(workspace: IAnyWorkspaceIdentifier, environmentService: INativeWorkbenchEnvironmentService, userDataProfileService: IUserDataProfileService, userDataProfilesService: IUserDataProfilesService, mainProcessService: IMainProcessService): Promise<NativeWorkbenchStorageService> {368const storageService = new NativeWorkbenchStorageService(workspace, userDataProfileService, userDataProfilesService, mainProcessService, environmentService);369370try {371await storageService.initialize();372373return storageService;374} catch (error) {375onUnexpectedError(error);376377return storageService;378}379}380381private async createKeyboardLayoutService(mainProcessService: IMainProcessService): Promise<NativeKeyboardLayoutService> {382const keyboardLayoutService = new NativeKeyboardLayoutService(mainProcessService);383384try {385await keyboardLayoutService.initialize();386387return keyboardLayoutService;388} catch (error) {389onUnexpectedError(error);390391return keyboardLayoutService;392}393}394}395396export interface IDesktopMain {397main(configuration: INativeWindowConfiguration): Promise<void>;398}399400export function main(configuration: INativeWindowConfiguration): Promise<void> {401const workbench = new SessionsMain(configuration);402403return workbench.open();404}405406407