@sussudio/platform
Version:
Internal APIs for VS Code's service injection the base services.
151 lines (150 loc) • 4.7 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var __decorate =
(this && this.__decorate) ||
function (decorators, target, key, desc) {
var c = arguments.length,
r = c < 3 ? target : desc === null ? (desc = Object.getOwnPropertyDescriptor(target, key)) : desc,
d;
if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function')
r = Reflect.decorate(decorators, target, key, desc);
else
for (var i = decorators.length - 1; i >= 0; i--)
if ((d = decorators[i])) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param =
(this && this.__param) ||
function (paramIndex, decorator) {
return function (target, key) {
decorator(target, key, paramIndex);
};
};
import { ThrottledDelayer } from '@sussudio/base/common/async.mjs';
import { VSBuffer } from '@sussudio/base/common/buffer.mjs';
import { isUndefined, isUndefinedOrNull } from '@sussudio/base/common/types.mjs';
import { IEnvironmentService } from '../../environment/common/environment.mjs';
import { IFileService } from '../../files/common/files.mjs';
import { ILogService } from '../../log/common/log.mjs';
export class FileStorage {
storagePath;
logService;
fileService;
storage = Object.create(null);
lastSavedStorageContents = '';
flushDelayer = new ThrottledDelayer(100 /* buffer saves over a short time */);
initializing = undefined;
closing = undefined;
constructor(storagePath, logService, fileService) {
this.storagePath = storagePath;
this.logService = logService;
this.fileService = fileService;
}
init() {
if (!this.initializing) {
this.initializing = this.doInit();
}
return this.initializing;
}
async doInit() {
try {
this.lastSavedStorageContents = (await this.fileService.readFile(this.storagePath)).value.toString();
this.storage = JSON.parse(this.lastSavedStorageContents);
} catch (error) {
if (error.fileOperationResult !== 1 /* FileOperationResult.FILE_NOT_FOUND */) {
this.logService.error(error);
}
}
}
getItem(key, defaultValue) {
const res = this.storage[key];
if (isUndefinedOrNull(res)) {
return defaultValue;
}
return res;
}
setItem(key, data) {
this.setItems([{ key, data }]);
}
setItems(items) {
let save = false;
for (const { key, data } of items) {
// Shortcut for data that did not change
if (this.storage[key] === data) {
continue;
}
// Remove items when they are undefined or null
if (isUndefinedOrNull(data)) {
if (!isUndefined(this.storage[key])) {
this.storage[key] = undefined;
save = true;
}
}
// Otherwise add an item
else {
this.storage[key] = data;
save = true;
}
}
if (save) {
this.save();
}
}
removeItem(key) {
// Only update if the key is actually present (not undefined)
if (!isUndefined(this.storage[key])) {
this.storage[key] = undefined;
this.save();
}
}
async save() {
if (this.closing) {
return; // already about to close
}
return this.flushDelayer.trigger(() => this.doSave());
}
async doSave() {
if (!this.initializing) {
return; // if we never initialized, we should not save our state
}
// Make sure to wait for init to finish first
await this.initializing;
// Return early if the database has not changed
const serializedDatabase = JSON.stringify(this.storage, null, 4);
if (serializedDatabase === this.lastSavedStorageContents) {
return;
}
// Write to disk
try {
await this.fileService.writeFile(this.storagePath, VSBuffer.fromString(serializedDatabase));
this.lastSavedStorageContents = serializedDatabase;
} catch (error) {
this.logService.error(error);
}
}
async close() {
if (!this.closing) {
this.closing = this.flushDelayer.trigger(() => this.doSave(), 0 /* as soon as possible */);
}
return this.closing;
}
}
let StateService = class StateService {
fileStorage;
constructor(environmentService, logService, fileService) {
this.fileStorage = new FileStorage(environmentService.stateResource, logService, fileService);
}
async init() {
await this.fileStorage.init();
}
getItem(key, defaultValue) {
return this.fileStorage.getItem(key, defaultValue);
}
};
StateService = __decorate(
[__param(0, IEnvironmentService), __param(1, ILogService), __param(2, IFileService)],
StateService,
);
export { StateService };