@zenweb/cache
Version:
Zenweb Cache module
88 lines (87 loc) • 2.37 kB
JavaScript
import { zenwebDebug } from '@zenweb/core';
import crypto from 'node:crypto';
export const debug = zenwebDebug('cache');
/**
* Promise 等待
* @param ms 毫秒
* @returns
*/
export function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
/**
* 执行 Redis Lua 脚本
* @param redis Redis 实例
* @param hash 脚本 sha1 hash
* @param script 脚本代码
* @param keys 输入键
* @param values 输入值
* @returns 执行结果
*/
export async function runRedisScript(redis, hash, script, keys, values = []) {
try {
const result = await redis.evalsha(hash, keys.length, ...keys, ...values);
return result;
}
catch (err) {
if (err instanceof Error && err.message.includes('NOSCRIPT')) {
debug('runRedisScript: NOSCRIPT');
// 缺少预设脚本,设置
const result = await redis.eval(script, keys.length, ...keys, ...values);
return result;
}
throw err;
}
}
/**
* 将一个嵌套对象转换为平面字符串结构
*/
function plainify(obj) {
if (Array.isArray(obj)) {
return obj.map(plainify).join(',');
}
if (obj instanceof Date) {
return obj.toJSON();
}
if (Buffer.isBuffer(obj)) {
return obj.toString('utf-8');
}
if (obj && typeof obj === 'object') {
return Object.keys(obj).sort().map(k => `${k}=${plainify(obj[k])}`).join('&');
}
return String(obj);
}
/**
* 对象使用 `plainify` 处理,如果对象过长则使用摘要
* @param obj
* @returns
*/
function plainifyOrHash(obj) {
let p = plainify(obj);
if (Buffer.byteLength(p, 'utf8') > 16) {
// 参数太长只取摘要
p = crypto.createHash('sha1').update(p, 'utf8').digest().subarray(0, 10).toString('base64url');
}
return p;
}
/**
* 生成一个参数缓存key
* - 多个元素用 : 连接
*/
export function cacheKey(...key) {
return key.map(i => {
if (i === null)
return 'N';
switch (typeof i) {
case 'string': return i;
case 'number': return String(i);
case 'boolean': return i ? 'T' : 'F';
case 'undefined': return '';
}
if (i instanceof Date)
return i.toJSON();
return plainifyOrHash(i);
}).join(':');
}