1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-09 13:10:17 +00:00

Add write-cache to desktop

This commit is contained in:
Bernd Schoolmann
2025-04-18 18:09:29 +02:00
parent c8c7807717
commit e48b3d9b56
2 changed files with 52 additions and 11 deletions

View File

@@ -121,6 +121,9 @@ export class Main {
const storageDefaults: any = {};
this.storageService = new ElectronStorageService(app.getPath("userData"), storageDefaults);
app.on("before-quit", () => {
this.storageService.flush();
});
this.memoryStorageService = new MemoryStorageService();
this.memoryStorageForStateProviders = new MemoryStorageServiceForStateProviders();
const storageServiceProvider = new StorageServiceProvider(

View File

@@ -24,7 +24,7 @@ const Store: ElectronStoreConstructor = require("electron-store");
interface ElectronStore {
get: (key: string) => unknown;
set: (key: string, obj: unknown) => void;
set: (obj: unknown) => void;
delete: (key: string) => void;
}
@@ -39,6 +39,44 @@ interface SaveOptions extends BaseOptions<"save"> {
type Options = BaseOptions<"get"> | BaseOptions<"has"> | SaveOptions | BaseOptions<"remove">;
// Max one second
const MAX_FILE_CACHE_WRITE_INTERVAL = 1000;
class InMemoryFileCache {
private fileCache: any = null;
private needsWrite = false;
private lastWritten = 0;
constructor(private store: ElectronStore) {
this.fileCache = (this.store as any).store;
setInterval(() => {
if (this.needsWrite && Date.now() - this.lastWritten > MAX_FILE_CACHE_WRITE_INTERVAL) {
this.needsWrite = false;
this.store.set(this.fileCache);
this.lastWritten = Date.now();
}
}, MAX_FILE_CACHE_WRITE_INTERVAL);
}
get(key: string): unknown {
return this.fileCache[key];
}
set(key: string, obj: unknown): void {
this.fileCache[key] = obj;
this.needsWrite = true;
}
delete(key: string): void {
delete this.fileCache[key];
this.needsWrite = true;
}
flush(): void {
this.store.set(this.fileCache);
this.needsWrite = false;
}
}
export class ElectronStorageService implements AbstractStorageService {
private store: ElectronStore;
private updatesSubject = new Subject<StorageUpdate>();
@@ -48,7 +86,7 @@ export class ElectronStorageService implements AbstractStorageService {
//
// electron store and conf read the entire file per individual key accessed, which blocks the main
// thread making in-memory store access slow, and causing a lot of file I/O.
private fileCache: any = null;
private fileCache: InMemoryFileCache;
constructor(dir: string, defaults = {}) {
if (!fs.existsSync(dir)) {
@@ -60,7 +98,7 @@ export class ElectronStorageService implements AbstractStorageService {
};
this.store = new Store(storeConfig);
this.updates$ = this.updatesSubject.asObservable();
this.fileCache = (this.store as any).store;
this.fileCache = new InMemoryFileCache(this.store);
ipcMain.handle("storageService", (event, options: Options) => {
switch (options.action) {
@@ -81,11 +119,11 @@ export class ElectronStorageService implements AbstractStorageService {
}
get<T>(key: string): Promise<T> {
return Promise.resolve(this.fileCache[key]);
return Promise.resolve(this.fileCache.get(key) as T);
}
has(key: string): Promise<boolean> {
return Promise.resolve(this.fileCache[key] !== undefined);
return Promise.resolve(this.fileCache.get(key) !== undefined);
}
save(key: string, obj: unknown): Promise<void> {
@@ -97,18 +135,18 @@ export class ElectronStorageService implements AbstractStorageService {
obj = Array.from(obj);
}
this.fileCache[key] = obj;
this.store.set(key, obj);
this.fileCache.set(key, obj);
this.updatesSubject.next({ key, updateType: "save" });
return Promise.resolve();
}
remove(key: string): Promise<void> {
delete this.fileCache[key];
this.store.delete(key);
this.fileCache.delete(key);
this.updatesSubject.next({ key, updateType: "remove" });
return Promise.resolve();
}
flush() {
this.fileCache.flush();
}
}