84 lines
2.2 KiB
TypeScript
84 lines
2.2 KiB
TypeScript
// Copyright 2018-2020 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import { readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
|
|
import { get, set } from 'lodash';
|
|
|
|
const ENCODING = 'utf8';
|
|
|
|
type InternalConfigType = Record<string, unknown>;
|
|
|
|
export type ConfigType = {
|
|
set: (keyPath: string, value: unknown) => void;
|
|
get: (keyPath: string) => unknown;
|
|
remove: () => void;
|
|
|
|
// Test-only
|
|
_getCachedValue: () => InternalConfigType | undefined;
|
|
};
|
|
|
|
export function start(
|
|
name: string,
|
|
targetPath: string,
|
|
options?: { allowMalformedOnStartup?: boolean }
|
|
): ConfigType {
|
|
let cachedValue: InternalConfigType | undefined;
|
|
let incomingJson: string | undefined;
|
|
|
|
try {
|
|
incomingJson = readFileSync(targetPath, ENCODING);
|
|
cachedValue = incomingJson ? JSON.parse(incomingJson) : undefined;
|
|
console.log(`config/get: Successfully read ${name} config file`);
|
|
|
|
if (!cachedValue) {
|
|
console.log(
|
|
`config/get: ${name} config value was falsy, cache is now empty object`
|
|
);
|
|
cachedValue = Object.create(null);
|
|
}
|
|
} catch (error) {
|
|
if (!options?.allowMalformedOnStartup && error.code !== 'ENOENT') {
|
|
throw error;
|
|
}
|
|
|
|
if (incomingJson) {
|
|
console.log(
|
|
`config/get: ${name} config file was malformed, starting afresh`
|
|
);
|
|
} else {
|
|
console.log(
|
|
`config/get: Did not find ${name} config file (or it was empty), cache is now empty object`
|
|
);
|
|
}
|
|
cachedValue = Object.create(null);
|
|
}
|
|
|
|
function ourGet(keyPath: string): unknown {
|
|
return get(cachedValue, keyPath);
|
|
}
|
|
|
|
function ourSet(keyPath: string, value: unknown): void {
|
|
if (!cachedValue) {
|
|
throw new Error('ourSet: no cachedValue!');
|
|
}
|
|
|
|
set(cachedValue, keyPath, value);
|
|
console.log(`config/set: Saving ${name} config to disk`);
|
|
const outgoingJson = JSON.stringify(cachedValue, null, ' ');
|
|
writeFileSync(targetPath, outgoingJson, ENCODING);
|
|
}
|
|
|
|
function remove(): void {
|
|
console.log(`config/remove: Deleting ${name} config from disk`);
|
|
unlinkSync(targetPath);
|
|
cachedValue = Object.create(null);
|
|
}
|
|
|
|
return {
|
|
set: ourSet,
|
|
get: ourGet,
|
|
remove,
|
|
_getCachedValue: () => cachedValue,
|
|
};
|
|
}
|