Skip to content

Commit 8250a40

Browse files
author
nihonium
committed
feat: add overridable storage service
1 parent bcc5ea9 commit 8250a40

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

src/service-override/storage.ts

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import { Event } from 'vs/base/common/event'
2+
import { IDisposable } from 'vs/base/common/lifecycle'
3+
import { IStorage, IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest, Storage } from 'vs/base/parts/storage/common/storage'
4+
import { IEditorOverrideServices } from 'vs/editor/standalone/browser/standaloneServices'
5+
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'
6+
import { AbstractStorageService, IStorageService, StorageScope as VSStorageScope } from 'vs/platform/storage/common/storage'
7+
import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile'
8+
import { IAnyWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'
9+
10+
export enum StorageScope {
11+
APPLICATION = VSStorageScope.APPLICATION,
12+
PROFILE = VSStorageScope.PROFILE,
13+
WORKSPACE = VSStorageScope.WORKSPACE
14+
}
15+
16+
export interface IStorageProvider {
17+
read (scope: StorageScope): Map<string, string> | undefined
18+
write (scope: StorageScope, data: Map<string, string>): Promise<void>
19+
close? (scope: StorageScope): Promise<void>
20+
onDidChange? (listener: (event: IStorageItemsChangeEvent) => void): IDisposable
21+
}
22+
23+
class ExternalStorage extends Storage {
24+
constructor (
25+
scope: StorageScope,
26+
provider: IStorageProvider
27+
) {
28+
const items = provider.read(scope)
29+
30+
super(new ExternalStorageDatabase(scope, provider, items))
31+
32+
if (items != null) {
33+
for (const [key, value] of items) {
34+
this.items.set(key, value)
35+
}
36+
}
37+
}
38+
}
39+
40+
class ExternalStorageDatabase implements IStorageDatabase {
41+
readonly onDidChangeItemsExternal: Event<IStorageItemsChangeEvent>
42+
43+
constructor (
44+
private readonly scope: StorageScope,
45+
private readonly provider: IStorageProvider,
46+
private readonly items = new Map<string, string>()
47+
) {
48+
this.onDidChangeItemsExternal = this.provider.onDidChange ?? Event.None
49+
}
50+
51+
async getItems (): Promise<Map<string, string>> {
52+
return this.items
53+
}
54+
55+
async updateItems (request: IUpdateRequest): Promise<void> {
56+
request.insert?.forEach((value, key) => this.items.set(key, value))
57+
58+
request.delete?.forEach(key => this.items.delete(key))
59+
60+
await this.provider.write(this.scope, this.items)
61+
}
62+
63+
async close () {
64+
return this.provider.close?.(this.scope)
65+
}
66+
}
67+
68+
class ExternalStorageService extends AbstractStorageService {
69+
private readonly applicationStorage = this._register(new ExternalStorage(StorageScope.APPLICATION, this.provider))
70+
private readonly profileStorage = this._register(new ExternalStorage(StorageScope.PROFILE, this.provider))
71+
private readonly workspaceStorage = this._register(new ExternalStorage(StorageScope.WORKSPACE, this.provider))
72+
73+
constructor (protected readonly provider: IStorageProvider) {
74+
super()
75+
76+
this._register(this.workspaceStorage.onDidChangeStorage(key => this.emitDidChangeValue(VSStorageScope.WORKSPACE, key)))
77+
this._register(this.profileStorage.onDidChangeStorage(key => this.emitDidChangeValue(VSStorageScope.PROFILE, key)))
78+
this._register(this.applicationStorage.onDidChangeStorage(key => this.emitDidChangeValue(VSStorageScope.APPLICATION, key)))
79+
}
80+
81+
protected getStorage (scope: VSStorageScope): IStorage {
82+
switch (scope) {
83+
case VSStorageScope.APPLICATION:
84+
return this.applicationStorage
85+
case VSStorageScope.PROFILE:
86+
return this.profileStorage
87+
default:
88+
return this.workspaceStorage
89+
}
90+
}
91+
92+
protected getLogDetails (scope: VSStorageScope): string | undefined {
93+
switch (scope) {
94+
case VSStorageScope.APPLICATION:
95+
return 'External (application)'
96+
case VSStorageScope.PROFILE:
97+
return 'External (profile)'
98+
default:
99+
return 'External (workspace)'
100+
}
101+
}
102+
103+
protected async doInitialize (): Promise<void> {
104+
// no-op
105+
}
106+
107+
protected async switchToProfile (): Promise<void> {
108+
// no-op
109+
}
110+
111+
protected async switchToWorkspace (): Promise<void> {
112+
// no-op
113+
}
114+
115+
hasScope (_scope: IAnyWorkspaceIdentifier | IUserDataProfile): boolean {
116+
return false
117+
}
118+
}
119+
120+
export default function getStorageServiceOverride (provider: IStorageProvider): IEditorOverrideServices {
121+
return {
122+
[IStorageService.toString()]: new SyncDescriptor(ExternalStorageService, [provider])
123+
}
124+
}
125+
126+
export {
127+
IStorageItemsChangeEvent
128+
}

0 commit comments

Comments
 (0)