import * as path from "path"; import * as fs from "fs-extra"; import * as electron from "electron"; export namespace v1 { /* main entry */ interface LocalUICache { fetch_history?: FetchStatus; versions?: LocalUICacheEntry[]; remote_index?: UIVersion[] | UIVersion; remote_index_channel?: string; /* only set if the last status was a channel only*/ local_index?: UIVersion; } interface FetchStatus { timestamp: number; /** * 0 = success * 1 = connect fail * 2 = internal fail */ status: number; } interface LocalUICacheEntry { version: UIVersion; download_timestamp: number; tar_file: string; checksum: string; /* SHA512 */ } export interface UIVersion { channel: string; version: string; git_hash: string; timestamp: number; required_client?: string; filename?: string; client_shipped?: boolean; } } export interface CacheFile { version: number; /* currently 2 */ cached_ui_packs: CachedUIPack[]; } export interface UIPackInfo { timestamp: number; /* build timestamp */ version: string; /* not really used anymore */ versions_hash: string; /* used, identifies the version. Its the git hash. */ channel: string; min_client_version: string; /* minimum version from the client required for the pack */ } export interface CachedUIPack { download_timestamp: number; local_file_path: string; local_checksum: string | "none"; /* sha512 of the locally downloaded file. */ //TODO: Get the remote checksum and compare them instead of the local one pack_info: UIPackInfo; status: "valid" | "invalid"; invalid_reason?: string; } let cached_loading_promise_: Promise; let ui_cache_: CacheFile = { version: 2, cached_ui_packs: [] }; async function load_() : Promise { const file = path.join(cache_path(), "data.json"); try { if(!(await fs.pathExists(file))) { return ui_cache_; } const data = await fs.readJSON(file) as CacheFile; if(!data) { throw "invalid data object"; } else if(typeof data["version"] !== "number") { throw "invalid versions tag"; } else if(data["version"] !== 2) { console.warn("UI cache file contains an old version. Ignoring file and may override with newer version."); return ui_cache_; } /* validating data */ if(!Array.isArray(data.cached_ui_packs)) { throw "Invalid 'cached_ui_packs' entry within the UI cache file"; } return (ui_cache_ = data as CacheFile); } catch(error) { console.warn("Failed to load UI cache file: %o. This will cause loss of the file content.", error); return ui_cache_; } } /** * Will not throw or return undefined! */ export function load() : Promise { if(cached_loading_promise_) return cached_loading_promise_; return (cached_loading_promise_ = load_()); } export function unload() { ui_cache_ = undefined; cached_loading_promise_ = undefined; } /** * Will not throw anything */ export async function save() { const file = path.join(cache_path(), "data.json"); try { if(!(await fs.pathExists(path.dirname(file)))) await fs.mkdirs(path.dirname(file)); await fs.writeJson(file, ui_cache_); } catch (error) { console.error("Failed to save UI cache file. This will may cause some data loss: %o", error); } } export function cache_path() { return path.join(electron.app.getPath('userData'), "cache", "ui"); }