fix: fix login-node-cache error

This commit is contained in:
xion 2025-03-23 12:16:43 +08:00
parent 9ba45c37c2
commit 54672a5574
5 changed files with 95 additions and 58 deletions

View File

@ -18,7 +18,7 @@
"access": "public" "access": "public"
}, },
"peerDependencies": { "peerDependencies": {
"@kevisual/query": "^0.0.14" "@kevisual/query": "^0.0.15"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.13.11", "@types/node": "^22.13.11",

View File

@ -11,6 +11,10 @@ export interface Cache {
* @update * @update
*/ */
del(): Promise<void>; del(): Promise<void>;
/**
*
*/
init?: () => Promise<any>;
} }
export type CacheLoginUser = { export type CacheLoginUser = {
@ -23,7 +27,7 @@ type CacheLogin = {
loginUsers: CacheLoginUser[]; loginUsers: CacheLoginUser[];
} & CacheLoginUser; } & CacheLoginUser;
export type CacheStore<T = any> = { export type CacheStore<T = Cache> = {
name: string; name: string;
cacheData: CacheLogin; cacheData: CacheLogin;
/** /**
@ -51,10 +55,6 @@ export type CacheStore<T = any> = {
* accessToken * accessToken
*/ */
getAccessToken(): Promise<string>; getAccessToken(): Promise<string>;
/**
*
*/
init(): Promise<void>;
/** /**
* *
*/ */
@ -63,9 +63,14 @@ export type CacheStore<T = any> = {
* *
*/ */
clearAll(): Promise<void>; clearAll(): Promise<void>;
} & Cache;
type LoginCacheStoreOpts = { getValue(): Promise<CacheLogin>;
setValue(value: CacheLogin): Promise<CacheLogin>;
delValue(): Promise<void>;
init(): Promise<any>;
};
export type LoginCacheStoreOpts = {
name: string; name: string;
cache: Cache; cache: Cache;
}; };
@ -94,28 +99,41 @@ export class LoginCacheStore implements CacheStore<any> {
* @param value * @param value
* @returns * @returns
*/ */
async set(key: string, value: CacheLogin) { async setValue(value: CacheLogin) {
await this.cache.set(key, value); await this.cache.set(this.name, value);
this.cacheData = value;
return value; return value;
} }
/** /**
* *
*/ */
async del() { async delValue() {
await this.cache.del(); await this.cache.del();
} }
get(key: string): Promise<CacheLogin> { getValue(): Promise<CacheLogin> {
return this.cache.get(key); return this.cache.get(this.name);
} }
/**
* ,
*/
async init() { async init() {
this.cacheData = (await this.get(this.name)) || { const defaultData = {
loginUsers: [], loginUsers: [],
user: null, user: null,
id: null, id: null,
accessToken: null, accessToken: null,
refreshToken: null, refreshToken: null,
}; };
if (this.cache.init) {
try {
const cacheData = await this.cache.init();
this.cacheData = cacheData || defaultData;
} catch (error) {
console.log('cacheInit error', error);
}
} else {
this.cacheData = (await this.getValue()) || defaultData;
}
} }
/** /**
* *
@ -131,7 +149,7 @@ export class LoginCacheStore implements CacheStore<any> {
this.cacheData.id = user.id; this.cacheData.id = user.id;
this.cacheData.accessToken = user.accessToken; this.cacheData.accessToken = user.accessToken;
this.cacheData.refreshToken = user.refreshToken; this.cacheData.refreshToken = user.refreshToken;
await this.set(this.name, this.cacheData); await this.setValue(this.cacheData);
} }
getCurrentUser(): Promise<CacheLoginUser> { getCurrentUser(): Promise<CacheLoginUser> {
@ -160,7 +178,7 @@ export class LoginCacheStore implements CacheStore<any> {
this.cacheData.id = undefined; this.cacheData.id = undefined;
this.cacheData.accessToken = undefined; this.cacheData.accessToken = undefined;
this.cacheData.refreshToken = undefined; this.cacheData.refreshToken = undefined;
await this.set(this.name, this.cacheData); await this.setValue(this.cacheData);
} }
async clearAll() { async clearAll() {
this.cacheData.loginUsers = []; this.cacheData.loginUsers = [];
@ -168,6 +186,6 @@ export class LoginCacheStore implements CacheStore<any> {
this.cacheData.id = undefined; this.cacheData.id = undefined;
this.cacheData.accessToken = undefined; this.cacheData.accessToken = undefined;
this.cacheData.refreshToken = undefined; this.cacheData.refreshToken = undefined;
await this.set(this.name, this.cacheData); await this.setValue(this.cacheData);
} }
} }

View File

@ -1,11 +1,12 @@
import { Cache } from './login-cache.ts'; import { Cache, LoginCacheStore, LoginCacheStoreOpts } from './login-cache.ts';
import { homedir } from 'node:os'; import { homedir } from 'node:os';
import { join, dirname } from 'node:path'; import { join, dirname } from 'node:path';
import { readFileSync } from 'node:fs'; import fs from 'node:fs';
import { readFile, writeFile, unlink, stat, mkdir } from 'node:fs/promises'; import { readFileSync, writeFileSync, accessSync } from 'node:fs';
import { readFile, writeFile, unlink, mkdir } from 'node:fs/promises';
export const fileExists = async (filePath: string, createIfNotExists = false) => { export const fileExists = async (filePath: string, createIfNotExists = false) => {
try { try {
await stat(filePath); accessSync(filePath, fs.constants.F_OK);
return true; return true;
} catch (error) { } catch (error) {
if (createIfNotExists) { if (createIfNotExists) {
@ -76,37 +77,48 @@ export class StorageNode implements Storage {
} }
} }
export class LoginNodeCache implements Cache { export class LoginNodeCache implements Cache {
name: string; filepath: string;
cacheData: any;
filePath: string;
constructor(name: string) {
this.name = name;
const hostname = getHostName();
this.filePath = join(homedir(), '.config', 'envision', 'config', `${hostname}-${name}.json`);
fileExists(this.filePath, true);
this.loadCache(this.filePath);
}
constructor(filepath?: string) {
this.filepath = filepath || join(homedir(), '.config', 'envision', 'config', `${getHostName()}-login.json`);
fileExists(this.filepath, true);
}
async get(_key: string) {
const data = readFileSync(this.filepath, 'utf-8');
try {
const jsonData = JSON.parse(data);
return jsonData;
} catch (error) {
console.log('get error', error);
return null;
}
}
async set(_key: string, value: any) {
const data = readFileSync(this.filepath, 'utf-8');
try {
const jsonData = JSON.parse(data);
const newData = { ...jsonData, ...value };
writeFileSync(this.filepath, JSON.stringify(newData, null, 2));
} catch (error) {
console.log('set error', error);
}
}
async del() {
await unlink(this.filepath);
}
async loadCache(filePath: string) { async loadCache(filePath: string) {
try { try {
const data = await readFile(filePath, 'utf-8'); const data = await readFile(filePath, 'utf-8');
const jsonData = JSON.parse(data); const jsonData = JSON.parse(data);
this.cacheData = jsonData; return jsonData;
} catch (error) { } catch (error) {
console.log('loadCache error', error);
const defaultData = { loginUsers: [] }; const defaultData = { loginUsers: [] };
this.cacheData = defaultData;
await writeFile(filePath, JSON.stringify(defaultData, null, 2)); await writeFile(filePath, JSON.stringify(defaultData, null, 2));
return defaultData;
} }
} }
async init() {
async get() { return await this.loadCache(this.filepath);
return this.cacheData;
}
async set(key: string, value: any) {
this.cacheData = value;
await writeFile(this.filePath, JSON.stringify(this.cacheData, null, 2));
}
async del() {
await unlink(this.filePath);
} }
} }

View File

@ -8,7 +8,7 @@ export class QueryLoginNode extends QueryLogin {
super({ super({
...opts, ...opts,
storage, storage,
cache: new LoginNodeCache('login'), cache: new LoginNodeCache(),
}); });
} }
} }

View File

@ -26,7 +26,7 @@ export class QueryLogin {
/** /**
* query login cache cache的包裹模块 * query login cache cache的包裹模块
*/ */
cache: CacheStore; cacheStore: CacheStore;
isBrowser: boolean; isBrowser: boolean;
load?: boolean; load?: boolean;
storage: Storage; storage: Storage;
@ -34,7 +34,7 @@ export class QueryLogin {
constructor(opts?: QueryLoginOpts) { constructor(opts?: QueryLoginOpts) {
this.query = opts?.query || new Query(); this.query = opts?.query || new Query();
this.cache = new LoginCacheStore({ name: 'login', cache: opts.cache }); this.cacheStore = new LoginCacheStore({ name: 'login', cache: opts.cache });
this.isBrowser = opts?.isBrowser ?? true; this.isBrowser = opts?.isBrowser ?? true;
this.init(); this.init();
this.onLoad = opts?.onLoad; this.onLoad = opts?.onLoad;
@ -44,12 +44,19 @@ export class QueryLogin {
this.query = query; this.query = query;
} }
private async init() { private async init() {
await this.cache.init(); await this.cacheStore.init()
this.load = true; this.load = true;
this.onLoad?.(); this.onLoad?.();
} }
async post<T = any>(data: any, opts?: DataOpts) { async post<T = any>(data: any, opts?: DataOpts) {
return this.query.post<T>({ path: 'user', ...data }, opts); try {
return this.query.post<T>({ path: 'user', ...data }, opts);
} catch (error) {
console.log('error', error);
return {
code: 400,
} as any;
}
} }
/** /**
* , * ,
@ -89,7 +96,7 @@ export class QueryLogin {
if (resUser.code === 200) { if (resUser.code === 200) {
const user = resUser.data; const user = resUser.data;
if (user) { if (user) {
this.cache.setLoginUser({ this.cacheStore.setLoginUser({
user, user,
id: user.id, id: user.id,
accessToken, accessToken,
@ -107,10 +114,10 @@ export class QueryLogin {
* @returns * @returns
*/ */
async queryRefreshToken(refreshToken?: string) { async queryRefreshToken(refreshToken?: string) {
const _refreshToken = refreshToken || this.cache.getRefreshToken(); const _refreshToken = refreshToken || this.cacheStore.getRefreshToken();
let data = { refreshToken: _refreshToken }; let data = { refreshToken: _refreshToken };
if (!_refreshToken) { if (!_refreshToken) {
await this.cache.clearCurrentUser(); await this.cacheStore.clearCurrentUser();
return { return {
code: 401, code: 401,
message: '请先登录', message: '请先登录',
@ -137,7 +144,7 @@ export class QueryLogin {
async afterCheck401ToRefreshToken(response: Result, ctx?: { req?: any; res?: any; fetch?: any }, refetch?: boolean) { async afterCheck401ToRefreshToken(response: Result, ctx?: { req?: any; res?: any; fetch?: any }, refetch?: boolean) {
const that = this; const that = this;
if (response?.code === 401) { if (response?.code === 401) {
const hasRefreshToken = await that.cache.getRefreshToken(); const hasRefreshToken = await that.cacheStore.getRefreshToken();
if (hasRefreshToken) { if (hasRefreshToken) {
const res = await that.queryRefreshToken(hasRefreshToken); const res = await that.queryRefreshToken(hasRefreshToken);
if (res.code === 200) { if (res.code === 200) {
@ -159,7 +166,7 @@ export class QueryLogin {
} }
} else { } else {
that.storage.removeItem('token'); that.storage.removeItem('token');
await that.cache.clearCurrentUser(); await that.cacheStore.clearCurrentUser();
} }
return res; return res;
} }
@ -250,7 +257,7 @@ export class QueryLogin {
* @returns * @returns
*/ */
async switchUser(username: string) { async switchUser(username: string) {
const localUserList = await this.cache.getCurrentUserList(); const localUserList = await this.cacheStore.getCurrentUserList();
const user = localUserList.find((userItem) => userItem.user.username === username); const user = localUserList.find((userItem) => userItem.user.username === username);
if (user) { if (user) {
this.storage.setItem('token', user.accessToken || ''); this.storage.setItem('token', user.accessToken || '');
@ -275,18 +282,18 @@ export class QueryLogin {
return res; return res;
} }
/** /**
* 退token * 退token
* @returns * @returns
*/ */
async logout() { async logout() {
this.storage.removeItem('token'); this.storage.removeItem('token');
const users = await this.cache.getCurrentUserList(); const users = await this.cacheStore.getCurrentUserList();
const tokens = users const tokens = users
.map((user) => { .map((user) => {
return user?.accessToken; return user?.accessToken;
}) })
.filter(Boolean); .filter(Boolean);
this.cache.del(); this.cacheStore.delValue();
return this.post<Result>({ key: 'logout', data: { tokens } }); return this.post<Result>({ key: 'logout', data: { tokens } });
} }
/** /**