1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
/*---------------------------------------------------------------------------------------------
* 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 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage';
import { ISerializedSingleFolderWorkspaceIdentifier, ISerializedWorkspaceIdentifier, IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
export type Key = string;
export type Value = string;
export type Item = [Key, Value];
export interface IBaseSerializableStorageRequest {
readonly workspace: ISerializedWorkspaceIdentifier | ISerializedSingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined;
}
export interface ISerializableUpdateRequest extends IBaseSerializableStorageRequest {
insert?: Item[];
delete?: Key[];
}
export interface ISerializableItemsChangeEvent {
readonly changed?: Item[];
readonly deleted?: Key[];
}
abstract class BaseStorageDatabaseClient extends Disposable implements IStorageDatabase {
abstract readonly onDidChangeItemsExternal: Event<IStorageItemsChangeEvent>;
constructor(protected channel: IChannel, protected workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined) {
super();
}
async getItems(): Promise<Map<string, string>> {
const serializableRequest: IBaseSerializableStorageRequest = { workspace: this.workspace };
const items: Item[] = await this.channel.call('getItems', serializableRequest);
return new Map(items);
}
updateItems(request: IUpdateRequest): Promise<void> {
const serializableRequest: ISerializableUpdateRequest = { workspace: this.workspace };
if (request.insert) {
serializableRequest.insert = Array.from(request.insert.entries());
}
if (request.delete) {
serializableRequest.delete = Array.from(request.delete.values());
}
return this.channel.call('updateItems', serializableRequest);
}
abstract close(): Promise<void>;
}
class GlobalStorageDatabaseClient extends BaseStorageDatabaseClient implements IStorageDatabase {
private readonly _onDidChangeItemsExternal = this._register(new Emitter<IStorageItemsChangeEvent>());
readonly onDidChangeItemsExternal = this._onDidChangeItemsExternal.event;
constructor(channel: IChannel) {
super(channel, undefined);
this.registerListeners();
}
private registerListeners(): void {
this._register(this.channel.listen<ISerializableItemsChangeEvent>('onDidChangeGlobalStorage')((e: ISerializableItemsChangeEvent) => this.onDidChangeGlobalStorage(e)));
}
private onDidChangeGlobalStorage(e: ISerializableItemsChangeEvent): void {
if (Array.isArray(e.changed) || Array.isArray(e.deleted)) {
this._onDidChangeItemsExternal.fire({
changed: e.changed ? new Map(e.changed) : undefined,
deleted: e.deleted ? new Set<string>(e.deleted) : undefined
});
}
}
async close(): Promise<void> {
// The global storage database is shared across all instances so
// we do not close it from the window. However we dispose the
// listener for external changes because we no longer interested in it.
this.dispose();
}
}
class WorkspaceStorageDatabaseClient extends BaseStorageDatabaseClient implements IStorageDatabase {
readonly onDidChangeItemsExternal = Event.None; // unsupported for workspace storage because we only ever write from one window
constructor(channel: IChannel, workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier) {
super(channel, workspace);
}
async close(): Promise<void> {
// The workspace storage database is only used in this instance
// but we do not need to close it from here, the main process
// can take care of that.
this.dispose();
}
}
export class StorageDatabaseChannelClient extends Disposable {
private _globalStorage: GlobalStorageDatabaseClient | undefined = undefined;
get globalStorage() {
if (!this._globalStorage) {
this._globalStorage = new GlobalStorageDatabaseClient(this.channel);
}
return this._globalStorage;
}
private _workspaceStorage: WorkspaceStorageDatabaseClient | undefined = undefined;
get workspaceStorage() {
if (!this._workspaceStorage && this.workspace) {
this._workspaceStorage = new WorkspaceStorageDatabaseClient(this.channel, this.workspace);
}
return this._workspaceStorage;
}
constructor(
private channel: IChannel,
private workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined
) {
super();
}
}
|