UNPKG

@sussudio/platform

Version:

Internal APIs for VS Code's service injection the base services.

138 lines (137 loc) 4.46 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from '@sussudio/base/common/event.mjs'; import { Disposable } from '@sussudio/base/common/lifecycle.mjs'; import { revive } from '@sussudio/base/common/marshalling.mjs'; import { reviveIdentifier } from '../../workspace/common/workspace.mjs'; export class StorageDatabaseChannel extends Disposable { logService; storageMainService; static STORAGE_CHANGE_DEBOUNCE_TIME = 100; onDidChangeApplicationStorageEmitter = this._register(new Emitter()); mapProfileToOnDidChangeProfileStorageEmitter = new Map(); constructor(logService, storageMainService) { super(); this.logService = logService; this.storageMainService = storageMainService; this.registerStorageChangeListeners( storageMainService.applicationStorage, this.onDidChangeApplicationStorageEmitter, ); } //#region Storage Change Events registerStorageChangeListeners(storage, emitter) { // Listen for changes in provided storage to send to listeners // that are listening. Use a debouncer to reduce IPC traffic. this._register( Event.debounce( storage.onDidChangeStorage, (prev, cur) => { if (!prev) { prev = [cur]; } else { prev.push(cur); } return prev; }, StorageDatabaseChannel.STORAGE_CHANGE_DEBOUNCE_TIME, )((events) => { if (events.length) { emitter.fire(this.serializeStorageChangeEvents(events, storage)); } }), ); } serializeStorageChangeEvents(events, storage) { const changed = new Map(); const deleted = new Set(); events.forEach((event) => { const existing = storage.get(event.key); if (typeof existing === 'string') { changed.set(event.key, existing); } else { deleted.add(event.key); } }); return { changed: Array.from(changed.entries()), deleted: Array.from(deleted.values()), }; } listen(_, event, arg) { switch (event) { case 'onDidChangeStorage': { const profile = arg.profile ? revive(arg.profile) : undefined; // Without profile: application scope if (!profile) { return this.onDidChangeApplicationStorageEmitter.event; } // With profile: profile scope for the profile let profileStorageChangeEmitter = this.mapProfileToOnDidChangeProfileStorageEmitter.get(profile.id); if (!profileStorageChangeEmitter) { profileStorageChangeEmitter = this._register(new Emitter()); this.registerStorageChangeListeners( this.storageMainService.profileStorage(profile), profileStorageChangeEmitter, ); this.mapProfileToOnDidChangeProfileStorageEmitter.set(profile.id, profileStorageChangeEmitter); } return profileStorageChangeEmitter.event; } } throw new Error(`Event not found: ${event}`); } //#endregion async call(_, command, arg) { const profile = arg.profile ? revive(arg.profile) : undefined; const workspace = reviveIdentifier(arg.workspace); // Get storage to be ready const storage = await this.withStorageInitialized(profile, workspace); // handle call switch (command) { case 'getItems': { return Array.from(storage.items.entries()); } case 'updateItems': { const items = arg; if (items.insert) { for (const [key, value] of items.insert) { storage.set(key, value); } } items.delete?.forEach((key) => storage.delete(key)); break; } case 'isUsed': { const path = arg.payload; if (typeof path === 'string') { return this.storageMainService.isUsed(path); } } default: throw new Error(`Call not found: ${command}`); } } async withStorageInitialized(profile, workspace) { let storage; if (workspace) { storage = this.storageMainService.workspaceStorage(workspace); } else if (profile) { storage = this.storageMainService.profileStorage(profile); } else { storage = this.storageMainService.applicationStorage; } try { await storage.init(); } catch (error) { this.logService.error( `StorageIPC#init: Unable to init ${ workspace ? 'workspace' : profile ? 'profile' : 'application' } storage due to ${error}`, ); } return storage; } }