TeaSpeak-Client/modules/renderer/PersistentLocalStorage.ts

98 lines
3.1 KiB
TypeScript

import * as electron from "electron";
import * as path from "path";
import * as fs from "fs-extra";
const APP_DATA = electron.remote.app.getPath("userData");
const SETTINGS_DIR = path.join(APP_DATA, "settings");
let _local_storage: {[key: string]: any} = {};
let _local_storage_save: {[key: string]: boolean} = {};
let _save_timer: NodeJS.Timer;
export async function initialize() {
await fs.mkdirp(SETTINGS_DIR);
const files = await fs.readdir(SETTINGS_DIR);
for(const file of files) {
const key = decodeURIComponent(file);
console.log("Load settings: %s", key);
try {
const data = await fs.readFile(path.join(SETTINGS_DIR, file));
_local_storage[key] = JSON.parse(data.toString() || "{}");
} catch(error) {
const target_file = path.join(SETTINGS_DIR, file + "." + Date.now() + ".broken");
console.error("Failed to load settings for %s: %o. Moving settings so the file does not get overridden. Target file: %s", key, error, target_file);
try {
await fs.move(path.join(SETTINGS_DIR, file), target_file);
} catch (error) {
console.warn("Failed to move broken settings file!");
}
}
}
let _new_storage: Storage = {} as any;
_new_storage.getItem = key => _local_storage[key] || null;
_new_storage.setItem = (key, value) => {
_local_storage[key] = value;
_local_storage_save[key] = true;
(_new_storage as any)["length"] = Object.keys(_local_storage).length;
};
_new_storage.clear = () => {
_local_storage = {};
_local_storage_save = {};
try {
fs.emptyDirSync(SETTINGS_DIR);
} catch(error) {
console.warn("Failed to empty settings dir");
}
(_new_storage as any)["length"] = 0;
};
_new_storage.key = index => Object.keys(_local_storage)[index];
_new_storage.removeItem = key => {
delete _local_storage[key];
delete_key(key).catch(error => {
console.warn("Failed to delete key on fs: %s => %o", key, error);
});
(_new_storage as any)["length"] = Object.keys(_local_storage).length;
};
Object.assign(window.localStorage, _new_storage);
/* try to save everything all 60 seconds */
_save_timer = setInterval(() => {
save_all_sync();
}, 60 * 1000);
}
export function save_all_sync() {
for(const key of Object.keys(_local_storage_save))
save_key_sync(key);
}
function key_path(key: string) {
return path.join(SETTINGS_DIR, encodeURIComponent(key));
}
export function save_key_sync(key: string) {
if(!_local_storage_save[key])
return;
delete _local_storage_save[key];
const setting_path = key_path(key);
fs.writeJsonSync(setting_path, _local_storage[key], {spaces: 0});
}
export async function delete_key(key: string) {
delete _local_storage_save[key];
const setting_path = key_path(key);
await fs.remove(setting_path); /* could be async because we're not carrying about data */
}
window.addEventListener("beforeunload", event => {
save_all_sync();
});