Skip to content

Commit cb74663

Browse files
committed
change user data init into a service.
initialize resources at necessary phases
1 parent 2bdb172 commit cb74663

4 files changed

Lines changed: 145 additions & 79 deletions

File tree

src/vs/workbench/browser/web.main.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
5252
import { IndexedDB, INDEXEDDB_LOGS_OBJECT_STORE, INDEXEDDB_USERDATA_OBJECT_STORE } from 'vs/platform/files/browser/indexedDBFileSystemProvider';
5353
import { BrowserRequestService } from 'vs/workbench/services/request/browser/requestService';
5454
import { IRequestService } from 'vs/platform/request/common/request';
55-
import { initializeUserData } from 'vs/workbench/services/userData/browser/userDataInit';
55+
import { IUserDataInitializationService, UserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit';
5656

5757
class BrowserMain extends Disposable {
5858

@@ -209,7 +209,9 @@ class BrowserMain extends Disposable {
209209
serviceCollection.set(IRequestService, requestService);
210210

211211
// initialize user data
212-
await initializeUserData(environmentService, fileService, storageService, productService, requestService, logService);
212+
const userDataInitializationService = new UserDataInitializationService(environmentService, fileService, storageService, productService, requestService, logService);
213+
serviceCollection.set(IUserDataInitializationService, userDataInitializationService);
214+
await userDataInitializationService.initializeRequiredResources();
213215

214216
return { serviceCollection, logService, storageService };
215217
}

src/vs/workbench/services/extensions/browser/extensionService.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import { FetchFileSystemProvider } from 'vs/workbench/services/extensions/browse
2424
import { Schemas } from 'vs/base/common/network';
2525
import { DisposableStore } from 'vs/base/common/lifecycle';
2626
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
27+
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
28+
import { IUserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit';
2729

2830
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
2931

@@ -43,6 +45,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten
4345
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
4446
@IConfigurationService private readonly _configService: IConfigurationService,
4547
@IWebExtensionsScannerService private readonly _webExtensionsScannerService: IWebExtensionsScannerService,
48+
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
49+
@IUserDataInitializationService private readonly _userDataInitializationService: IUserDataInitializationService,
4650
) {
4751
super(
4852
instantiationService,
@@ -56,7 +60,12 @@ export class ExtensionService extends AbstractExtensionService implements IExten
5660

5761
this._runningLocation = new Map<string, ExtensionRunningLocation>();
5862

59-
this._initialize();
63+
// Initialize extensions first and do it only after workbench is ready
64+
this._lifecycleService.when(LifecyclePhase.Ready).then(async () => {
65+
await this._userDataInitializationService.initializeExtensions(this._instantiationService);
66+
this._initialize();
67+
});
68+
6069
this._initFetchFileSystem();
6170
}
6271

src/vs/workbench/services/userData/browser/userDataInit.ts

Lines changed: 129 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -12,106 +12,159 @@ import { SettingsInitializer } from 'vs/platform/userDataSync/common/settingsSyn
1212
import { SnippetsInitializer } from 'vs/platform/userDataSync/common/snippetsSync';
1313
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
1414
import { IFileService } from 'vs/platform/files/common/files';
15-
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
15+
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
1616
import { ILogService } from 'vs/platform/log/common/log';
1717
import { UserDataSyncStoreClient } from 'vs/platform/userDataSync/common/userDataSyncStoreService';
1818
import { IProductService } from 'vs/platform/product/common/productService';
1919
import { IRequestService } from 'vs/platform/request/common/request';
20-
import { CONFIGURATION_SYNC_STORE_KEY } from 'vs/platform/userDataSync/common/userDataSync';
20+
import { CONFIGURATION_SYNC_STORE_KEY, IUserDataSyncStoreClient, SyncResource } from 'vs/platform/userDataSync/common/userDataSync';
2121
import { URI } from 'vs/base/common/uri';
2222
import { getAuthenticationSession } from 'vs/workbench/services/authentication/browser/authenticationService';
23+
import { getSyncAreaLabel } from 'vs/workbench/services/userDataSync/common/userDataSync';
24+
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions';
25+
import { Registry } from 'vs/platform/registry/common/platform';
26+
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
27+
import { isWeb } from 'vs/base/common/platform';
2328

24-
export function initializeUserData(
25-
environmentService: IWorkbenchEnvironmentService,
26-
fileService: IFileService,
27-
storageService: IStorageService,
28-
productService: IProductService,
29-
requestService: IRequestService,
30-
logService: ILogService,
31-
): Promise<void> {
32-
const initializers: AbstractInitializer[] = [
33-
new SettingsInitializer(fileService, environmentService, logService),
34-
new KeybindingsInitializer(fileService, environmentService, logService),
35-
new SnippetsInitializer(fileService, environmentService, logService),
36-
new GlobalStateInitializer(storageService, fileService, environmentService, logService),
37-
];
38-
return initialize(initializers, 'user data', environmentService, fileService, storageService, productService, requestService, logService);
39-
}
29+
export const IUserDataInitializationService = createDecorator<IUserDataInitializationService>('IUserDataInitializationService');
30+
export interface IUserDataInitializationService {
31+
_serviceBrand: any;
4032

41-
export function initializeExtensions(instantiationService: IInstantiationService): Promise<void> {
42-
return instantiationService.invokeFunction(accessor => {
43-
return initialize([instantiationService.createInstance(ExtensionsInitializer)], 'extensions',
44-
accessor.get(IWorkbenchEnvironmentService),
45-
accessor.get(IFileService),
46-
accessor.get(IStorageService),
47-
accessor.get(IProductService),
48-
accessor.get(IRequestService),
49-
accessor.get(ILogService));
50-
});
33+
initializeRequiredResources(): Promise<void>;
34+
initializeOtherResources(): Promise<void>;
35+
initializeExtensions(instantiationService: IInstantiationService): Promise<void>;
5136
}
5237

53-
async function initialize(
54-
initializers: AbstractInitializer[],
55-
userDataLabel: string,
56-
environmentService: IWorkbenchEnvironmentService,
57-
fileService: IFileService,
58-
storageService: IStorageService,
59-
productService: IProductService,
60-
requestService: IRequestService,
61-
logService: ILogService,
62-
): Promise<void> {
63-
64-
if (!environmentService.options?.enableSyncByDefault) {
65-
logService.trace(`Skipping initializing ${userDataLabel} as sync is not enabled by default`);
66-
return;
67-
}
38+
export class UserDataInitializationService implements IUserDataInitializationService {
6839

69-
if (!storageService.isNew(StorageScope.GLOBAL)) {
70-
logService.trace(`Skipping initializing ${userDataLabel} as application was opened before`);
71-
return;
72-
}
40+
_serviceBrand: any;
7341

74-
if (!storageService.isNew(StorageScope.WORKSPACE)) {
75-
logService.trace(`Skipping initializing ${userDataLabel} as workspace was opened before`);
76-
return;
77-
}
42+
private readonly initialized: SyncResource[] = [];
43+
44+
constructor(
45+
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
46+
@IFileService private readonly fileService: IFileService,
47+
@IStorageService private readonly storageService: IStorageService,
48+
@IProductService private readonly productService: IProductService,
49+
@IRequestService private readonly requestService: IRequestService,
50+
@ILogService private readonly logService: ILogService
51+
) { }
52+
53+
private _userDataSyncStoreClientPromise: Promise<IUserDataSyncStoreClient | undefined> | undefined;
54+
private createUserDataSyncStoreClient(): Promise<IUserDataSyncStoreClient | undefined> {
55+
if (!this._userDataSyncStoreClientPromise) {
56+
this._userDataSyncStoreClientPromise = (async (): Promise<IUserDataSyncStoreClient | undefined> => {
57+
if (!isWeb) {
58+
this.logService.trace(`Skipping initializing user data in desktop`);
59+
return;
60+
}
61+
62+
if (!this.environmentService.options?.enableSyncByDefault) {
63+
this.logService.trace(`Skipping initializing user data as sync is not enabled by default`);
64+
return;
65+
}
7866

79-
const userDataSyncStore = productService[CONFIGURATION_SYNC_STORE_KEY];
80-
if (!userDataSyncStore) {
81-
logService.trace(`Skipping initializing ${userDataLabel} as sync service is not provided`);
82-
return;
67+
if (!this.storageService.isNew(StorageScope.GLOBAL)) {
68+
this.logService.trace(`Skipping initializing user data as application was opened before`);
69+
return;
70+
}
71+
72+
if (!this.storageService.isNew(StorageScope.WORKSPACE)) {
73+
this.logService.trace(`Skipping initializing user data as workspace was opened before`);
74+
return;
75+
}
76+
77+
const userDataSyncStore = this.productService[CONFIGURATION_SYNC_STORE_KEY];
78+
if (!userDataSyncStore) {
79+
this.logService.trace(`Skipping initializing user data as sync service is not provided`);
80+
return;
81+
}
82+
83+
if (!this.environmentService.options?.credentialsProvider) {
84+
this.logService.trace(`Skipping initializing user data as credentials provider is not provided`);
85+
return;
86+
}
87+
88+
let authenticationSession;
89+
try {
90+
authenticationSession = await getAuthenticationSession(this.environmentService.options.credentialsProvider, this.productService);
91+
} catch (error) {
92+
this.logService.error(error);
93+
}
94+
if (!authenticationSession) {
95+
this.logService.trace(`Skipping initializing user data as authentication session is not set`);
96+
return;
97+
}
98+
99+
const userDataSyncStoreClient = new UserDataSyncStoreClient(URI.parse(userDataSyncStore.url), this.productService, this.requestService, this.logService, this.environmentService, this.fileService, this.storageService);
100+
userDataSyncStoreClient.setAuthToken(authenticationSession.accessToken, authenticationSession.providerId);
101+
return userDataSyncStoreClient;
102+
})();
103+
}
104+
105+
return this._userDataSyncStoreClientPromise;
83106
}
84107

85-
if (!environmentService.options?.credentialsProvider) {
86-
return;
108+
async initializeRequiredResources(): Promise<void> {
109+
return this.initialize([SyncResource.Settings, SyncResource.GlobalState]);
87110
}
88111

89-
let authenticationSession;
90-
try {
91-
authenticationSession = await getAuthenticationSession(environmentService.options.credentialsProvider, productService);
92-
} catch (error) {
93-
logService.error(error);
112+
async initializeOtherResources(): Promise<void> {
113+
return this.initialize([SyncResource.Keybindings, SyncResource.Snippets]);
94114
}
95-
if (!authenticationSession) {
96-
logService.trace(`Skipping initializing ${userDataLabel} as authentication session is not set`);
97-
return;
115+
116+
async initializeExtensions(instantiationService: IInstantiationService): Promise<void> {
117+
return this.initialize([SyncResource.Extensions], instantiationService);
98118
}
99119

100-
const userDataSyncStoreClient = new UserDataSyncStoreClient(URI.parse(userDataSyncStore.url), productService, requestService, logService, environmentService, fileService, storageService);
101-
try {
102-
userDataSyncStoreClient.setAuthToken(authenticationSession.accessToken, authenticationSession.providerId);
103-
logService.info(`Started initializing ${userDataLabel}`);
104-
for (const initializer of initializers) {
120+
private async initialize(syncResources: SyncResource[], instantiationService?: IInstantiationService): Promise<void> {
121+
const userDataSyncStoreClient = await this.createUserDataSyncStoreClient();
122+
if (!userDataSyncStoreClient) {
123+
return;
124+
}
125+
126+
await Promise.all(syncResources.map(async syncResource => {
105127
try {
106-
const userData = await userDataSyncStoreClient.read(initializer.resource, null);
128+
if (this.initialized.includes(syncResource)) {
129+
this.logService.info(`${getSyncAreaLabel(syncResource)} initialized already.`);
130+
return;
131+
}
132+
this.initialized.push(syncResource);
133+
this.logService.trace(`Initializing ${getSyncAreaLabel(syncResource)}`);
134+
const initializer = this.createSyncResourceInitializer(syncResource, instantiationService);
135+
const userData = await userDataSyncStoreClient.read(syncResource, null);
107136
await initializer.initialize(userData);
137+
this.logService.info(`Initialized ${getSyncAreaLabel(syncResource)}`);
108138
} catch (error) {
109-
logService.info(`Error while initializing ${initializer.resource}`);
110-
logService.error(error);
139+
this.logService.info(`Error while initializing ${getSyncAreaLabel(syncResource)}`);
140+
this.logService.error(error);
111141
}
142+
}));
143+
}
144+
145+
private createSyncResourceInitializer(syncResource: SyncResource, instantiationService?: IInstantiationService): AbstractInitializer {
146+
switch (syncResource) {
147+
case SyncResource.Settings: return new SettingsInitializer(this.fileService, this.environmentService, this.logService);
148+
case SyncResource.Keybindings: return new KeybindingsInitializer(this.fileService, this.environmentService, this.logService);
149+
case SyncResource.Snippets: return new SnippetsInitializer(this.fileService, this.environmentService, this.logService);
150+
case SyncResource.GlobalState: return new GlobalStateInitializer(this.storageService, this.fileService, this.environmentService, this.logService);
151+
case SyncResource.Extensions:
152+
if (!instantiationService) {
153+
throw new Error('Instantiation Service is required to initialize extension');
154+
}
155+
return instantiationService.createInstance(ExtensionsInitializer);
112156
}
113-
logService.info(`Initializing ${userDataLabel} completed`);
114-
} finally {
115-
userDataSyncStoreClient.dispose();
116157
}
158+
159+
}
160+
161+
class InitializeOtherResourcesContribution implements IWorkbenchContribution {
162+
constructor(@IUserDataInitializationService userDataInitializeService: IUserDataInitializationService) {
163+
userDataInitializeService.initializeOtherResources();
164+
}
165+
}
166+
167+
if (isWeb) {
168+
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(Extensions.Workbench);
169+
workbenchRegistry.registerWorkbenchContribution(InitializeOtherResourcesContribution, LifecyclePhase.Eventually);
117170
}

src/vs/workbench/workbench.desktop.main.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,14 @@ import { ITunnelService } from 'vs/platform/remote/common/tunnel';
6969
import { TunnelService } from 'vs/platform/remote/node/tunnelService';
7070
import { ITimerService } from 'vs/workbench/services/timer/browser/timerService';
7171
import { TimerService } from 'vs/workbench/services/timer/electron-browser/timerService';
72+
import { IUserDataInitializationService, UserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit';
7273

7374
registerSingleton(ICredentialsService, KeytarCredentialsService, true);
7475
registerSingleton(IUserDataSyncStoreManagementService, UserDataSyncStoreManagementService);
7576
registerSingleton(IUserDataAutoSyncService, UserDataAutoSyncService);
7677
registerSingleton(ITunnelService, TunnelService);
7778
registerSingleton(ITimerService, TimerService);
79+
registerSingleton(IUserDataInitializationService, UserDataInitializationService);
7880

7981
//#endregion
8082

0 commit comments

Comments
 (0)