import { Cache } from './login-cache.ts'; import { homedir } from 'node:os'; import { join, dirname } from 'node:path'; import fs from 'node:fs'; import { readFileSync, writeFileSync, accessSync, unlinkSync, mkdirSync } from 'node:fs'; export const fileExists = ( filePath: string, { createIfNotExists = true, isFile = true, isDir = false }: { createIfNotExists?: boolean; isFile?: boolean; isDir?: boolean } = {}, ) => { try { accessSync(filePath, fs.constants.F_OK); return true; } catch (error) { if (createIfNotExists && isDir) { mkdirSync(filePath, { recursive: true }); return true; } else if (createIfNotExists && isFile) { mkdirSync(dirname(filePath), { recursive: true }); return false; } return false; } }; export const readConfigFile = (filePath: string) => { try { const data = readFileSync(filePath, 'utf-8'); const jsonData = JSON.parse(data); return jsonData; } catch (error) { return {}; } }; export const writeConfigFile = (filePath: string, data: any) => { writeFileSync(filePath, JSON.stringify(data, null, 2)); }; /** * 获取主机名, * 例如:https://kevisual.cn 返回 kevisual.cn * 这里是读取默认的配置文件 ~/.config/envision/config.json 中的 baseURL 字段来获取主机名的,如果没有配置 baseURL 则默认使用 https://kevisual.cn * @returns 主机名 */ export const getHostName = (baseURL?: string) => { const configDir = join(homedir(), '.config', 'envision'); const configFile = join(configDir, 'config.json'); const config = readConfigFile(configFile); const _baseURL = baseURL || config.baseURL || 'https://kevisual.cn'; const hostname = new URL(_baseURL).hostname; return hostname; }; export class StorageNode implements Storage { cacheData: any; filePath: string = ''; hostname: string = ''; isLoaded: boolean = false; constructor(opts?: { baseURL?: string, load?: boolean }) { this.cacheData = {}; const hostname = getHostName(opts?.baseURL); this.setHostName(hostname, { load: opts?.load }); } setHostName(hostname: string, opts?: { load?: boolean }) { const load = opts?.load ?? false; if (hostname.startsWith('http')) { hostname = new URL(hostname).hostname; } const configDir = join(homedir(), '.config', 'envision'); this.filePath = join(configDir, 'config', `${hostname}-storage.json`); this.hostname = hostname; fileExists(this.filePath, { isFile: true }); if (load) { this.loadCache(); } } loadCache(force?: boolean) { if (this.isLoaded && !force) return; const filePath = this.filePath; try { const data = readConfigFile(filePath); this.cacheData = data; this.isLoaded = true; } catch (error) { this.cacheData = {}; writeFileSync(filePath, JSON.stringify(this.cacheData, null, 2)); } } get length() { return Object.keys(this.cacheData).length; } getItem(key: string) { return this.cacheData[key]; } setItem(key: string, value: any) { this.cacheData[key] = value; writeFileSync(this.filePath, JSON.stringify(this.cacheData, null, 2)); } removeItem(key: string) { delete this.cacheData[key]; writeFileSync(this.filePath, JSON.stringify(this.cacheData, null, 2)); } clear() { this.cacheData = {}; writeFileSync(this.filePath, JSON.stringify(this.cacheData, null, 2)); } key(index: number) { return Object.keys(this.cacheData)[index]; } } export class LoginNodeCache implements Cache { filepath: string; isLoaded: boolean = false; constructor(opts?: { baseURL?: string, load?: boolean }) { this.filepath = join(homedir(), '.config', 'envision', 'config', `${getHostName(opts?.baseURL)}-login.json`); fileExists(this.filepath, { isFile: true }); if (opts?.load) { this.loadCache(this.filepath); } } async get(_key: string) { try { const filePath = this.filepath; const data = readConfigFile(filePath); return data; } catch (error) { console.log('get error', error); return {}; } } async set(_key: string, value: any) { try { const data = readConfigFile(this.filepath); const newData = { ...data, ...value }; writeConfigFile(this.filepath, newData); } catch (error) { console.log('set error', error); } } async del() { unlinkSync(this.filepath); } loadCache(filePath: string, force?: boolean) { if (this.isLoaded && !force) return; try { const data = readFileSync(filePath, 'utf-8'); const jsonData = JSON.parse(data); this.isLoaded = true; return jsonData; } catch (error) { // console.log('loadCache error', error); console.log('create new cache file:', filePath); const defaultData = { loginUsers: [] }; writeConfigFile(filePath, defaultData); return defaultData; } } init() { return this.loadCache(this.filepath); } }