mm_cachebase 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -16
- package/index.js +801 -1079
- package/package.json +1 -1
- package/test.js +471 -68
package/index.js
CHANGED
|
@@ -1,1169 +1,866 @@
|
|
|
1
|
-
require('mm_logs');
|
|
2
1
|
const EventEmitter = require('events');
|
|
2
|
+
require('mm_logs');
|
|
3
3
|
|
|
4
|
-
// 符合Redis API的CacheBase类
|
|
5
4
|
class CacheBase extends EventEmitter {
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* 构造函数,初始化缓存
|
|
7
|
+
* @param {Object} options - 配置选项
|
|
8
|
+
*/
|
|
9
|
+
constructor(options = {}) {
|
|
7
10
|
super();
|
|
11
|
+
// 配置选项
|
|
12
|
+
this.options = options;
|
|
13
|
+
// 日志实例
|
|
14
|
+
this.log = options.log || $;
|
|
15
|
+
// 数据存储对象
|
|
8
16
|
this.data = {};
|
|
9
|
-
|
|
10
|
-
this.list = [];
|
|
17
|
+
// 键列表,用于存储所有的键名
|
|
18
|
+
this.list = [];
|
|
19
|
+
// 为了兼容旧版本,提供dict属性指向data
|
|
20
|
+
this.dict = this.data;
|
|
11
21
|
}
|
|
12
22
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return;
|
|
23
|
+
/**
|
|
24
|
+
* 检查键是否过期
|
|
25
|
+
* @private
|
|
26
|
+
* @param {string} key - 键名
|
|
27
|
+
* @returns {boolean} - 是否已过期
|
|
28
|
+
*/
|
|
29
|
+
_checkExpire(key) {
|
|
30
|
+
if (this.data.hasOwnProperty(key)) {
|
|
31
|
+
const item = this.data[key];
|
|
32
|
+
if (item && typeof item === 'object' && item.expire > 0) {
|
|
33
|
+
// 检查是否过期
|
|
34
|
+
if (Date.now() > item.expire) {
|
|
35
|
+
// 删除过期键
|
|
36
|
+
this.del(key);
|
|
37
|
+
return true;
|
|
29
38
|
}
|
|
30
|
-
|
|
31
|
-
// 执行实际操作
|
|
32
|
-
this.data[key] = { value, expire: 0 };
|
|
33
|
-
|
|
34
|
-
// 如果键不存在于列表中,添加到列表
|
|
35
|
-
if (!this.list.includes(key)) {
|
|
36
|
-
this.list.push(key);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// 触发后置事件
|
|
40
|
-
this.emit('set_after', {
|
|
41
|
-
key,
|
|
42
|
-
value,
|
|
43
|
-
result: 'OK'
|
|
44
|
-
});
|
|
45
|
-
resolve('OK');
|
|
46
|
-
} catch (error) {
|
|
47
|
-
// 触发错误事件
|
|
48
|
-
this.emit('set_error', {
|
|
49
|
-
key,
|
|
50
|
-
value,
|
|
51
|
-
error
|
|
52
|
-
});
|
|
53
|
-
$.log.error('[cachebase] set操作失败:', error);
|
|
54
|
-
resolve(null);
|
|
55
39
|
}
|
|
56
|
-
}
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
57
42
|
}
|
|
58
43
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
// 如果事件处理器设置了cancel为true,则取消操作
|
|
71
|
-
if (beforeEventData.cancel) {
|
|
72
|
-
resolve(0);
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// 检查键是否存在
|
|
77
|
-
const exists = key in this.data;
|
|
78
|
-
|
|
79
|
-
// 执行删除操作
|
|
80
|
-
if (exists) {
|
|
81
|
-
delete this.data[key];
|
|
82
|
-
// 从列表中移除
|
|
83
|
-
const index = this.list.indexOf(key);
|
|
84
|
-
if (index > -1) {
|
|
85
|
-
this.list.splice(index, 1);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// 触发后置事件
|
|
90
|
-
this.emit('del_after', {
|
|
91
|
-
key,
|
|
92
|
-
result: exists ? 1 : 0
|
|
93
|
-
});
|
|
94
|
-
resolve(exists ? 1 : 0);
|
|
95
|
-
} catch (error) {
|
|
96
|
-
// 触发错误事件
|
|
97
|
-
this.emit('del_error', {
|
|
98
|
-
key,
|
|
99
|
-
error
|
|
100
|
-
});
|
|
101
|
-
$.log.error('[cachebase] del操作失败:', error);
|
|
102
|
-
resolve(0);
|
|
44
|
+
/**
|
|
45
|
+
* 设置键的过期时间
|
|
46
|
+
* @private
|
|
47
|
+
* @param {string} key - 键名
|
|
48
|
+
* @param {number} seconds - 过期时间(秒)
|
|
49
|
+
*/
|
|
50
|
+
_setExpire(key, seconds) {
|
|
51
|
+
if (this.data.hasOwnProperty(key)) {
|
|
52
|
+
const item = this.data[key];
|
|
53
|
+
if (item && typeof item === 'object') {
|
|
54
|
+
item.expire = seconds > 0 ? Date.now() + seconds * 1000 : 0;
|
|
103
55
|
}
|
|
104
|
-
}
|
|
56
|
+
}
|
|
105
57
|
}
|
|
106
58
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
// 执行实际操作
|
|
125
|
-
const obj = this.data[key];
|
|
126
|
-
let result = null;
|
|
127
|
-
if (obj) {
|
|
128
|
-
result = obj.value;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// 触发后置事件
|
|
132
|
-
this.emit('get_after', {
|
|
133
|
-
key,
|
|
134
|
-
result
|
|
135
|
-
});
|
|
136
|
-
resolve(result);
|
|
137
|
-
} catch (error) {
|
|
138
|
-
// 触发错误事件
|
|
139
|
-
this.emit('get_error', {
|
|
140
|
-
key,
|
|
141
|
-
error
|
|
142
|
-
});
|
|
143
|
-
$.log.error('[cachebase] get操作失败:', error);
|
|
144
|
-
resolve(null);
|
|
59
|
+
/**
|
|
60
|
+
* 设置键值
|
|
61
|
+
* @param {string} key - 键名
|
|
62
|
+
* @param {*} value - 键值
|
|
63
|
+
* @param {number} expire - 过期时间(秒),0表示永不过期
|
|
64
|
+
* @returns {Promise<string>} - 返回'OK'
|
|
65
|
+
*/
|
|
66
|
+
async set(key, value, expire = 0) {
|
|
67
|
+
try {
|
|
68
|
+
this.emit('set_before', { key, value, expire });
|
|
69
|
+
|
|
70
|
+
// 设置值和过期时间
|
|
71
|
+
this.data[key] = { value, expire: expire > 0 ? Date.now() + expire * 1000 : 0 };
|
|
72
|
+
|
|
73
|
+
// 如果键不存在于列表中,添加到列表
|
|
74
|
+
if (!this.list.includes(key)) {
|
|
75
|
+
this.list.push(key);
|
|
145
76
|
}
|
|
146
|
-
|
|
77
|
+
|
|
78
|
+
this.emit('set_after', { key, value, expire, result: 'OK' });
|
|
79
|
+
return 'OK';
|
|
80
|
+
} catch (error) {
|
|
81
|
+
this.emit('set_error', { key, value, expire, error });
|
|
82
|
+
this.log.error('[cachebase] set操作失败:', error);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
147
85
|
}
|
|
148
86
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
this.emit('getset_before', beforeEventData);
|
|
160
|
-
|
|
161
|
-
// 如果事件处理器设置了cancel为true,则取消操作
|
|
162
|
-
if (beforeEventData.cancel) {
|
|
163
|
-
resolve(null);
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// 获取旧值
|
|
168
|
-
const obj = this.data[key];
|
|
169
|
-
const oldValue = obj ? obj.value : null;
|
|
170
|
-
|
|
171
|
-
// 设置新值
|
|
172
|
-
this.data[key] = { value, expire: 0 };
|
|
173
|
-
|
|
174
|
-
// 如果键不存在于列表中,添加到列表
|
|
175
|
-
if (!this.list.includes(key)) {
|
|
176
|
-
this.list.push(key);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// 触发后置事件
|
|
180
|
-
this.emit('getset_after', {
|
|
181
|
-
key,
|
|
182
|
-
value,
|
|
183
|
-
result: oldValue
|
|
184
|
-
});
|
|
185
|
-
resolve(oldValue);
|
|
186
|
-
} catch (error) {
|
|
187
|
-
// 触发错误事件
|
|
188
|
-
this.emit('getset_error', {
|
|
189
|
-
key,
|
|
190
|
-
value,
|
|
191
|
-
error
|
|
192
|
-
});
|
|
193
|
-
$.log.error('[cachebase] getset操作失败:', error);
|
|
194
|
-
resolve(null);
|
|
87
|
+
/**
|
|
88
|
+
* 获取键值
|
|
89
|
+
* @param {string} key - 键名
|
|
90
|
+
* @returns {Promise<*>} - 返回键值,不存在返回undefined
|
|
91
|
+
*/
|
|
92
|
+
async get(key) {
|
|
93
|
+
try {
|
|
94
|
+
// 检查键是否存在
|
|
95
|
+
if (!this.data.hasOwnProperty(key)) {
|
|
96
|
+
return undefined;
|
|
195
97
|
}
|
|
196
|
-
|
|
98
|
+
|
|
99
|
+
const item = this.data[key];
|
|
100
|
+
|
|
101
|
+
// 检查是否过期
|
|
102
|
+
if (item.expire > 0 && Date.now() > item.expire) {
|
|
103
|
+
// 删除过期键
|
|
104
|
+
delete this.data[key];
|
|
105
|
+
const index = this.list.indexOf(key);
|
|
106
|
+
if (index !== -1) {
|
|
107
|
+
this.list.splice(index, 1);
|
|
108
|
+
}
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return item.value;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
this.log.error('[cachebase] get操作失败:', error);
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
197
117
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// 获取当前值或默认为空字符串
|
|
218
|
-
const obj = this.data[key];
|
|
219
|
-
let currentValue = '';
|
|
220
|
-
if (obj) {
|
|
221
|
-
currentValue = String(obj.value);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// 执行字符串拼接
|
|
225
|
-
const newValue = currentValue + String(value);
|
|
226
|
-
const result = newValue.length;
|
|
227
|
-
|
|
228
|
-
// 保存结果
|
|
229
|
-
this.data[key] = { value: newValue, expire: 0 };
|
|
230
|
-
|
|
231
|
-
// 如果键不存在于列表中,添加到列表
|
|
232
|
-
if (!this.list.includes(key)) {
|
|
233
|
-
this.list.push(key);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// 触发后置事件
|
|
237
|
-
this.emit('append_after', {
|
|
238
|
-
key,
|
|
239
|
-
value,
|
|
240
|
-
result
|
|
241
|
-
});
|
|
242
|
-
resolve(result);
|
|
243
|
-
} catch (error) {
|
|
244
|
-
// 触发错误事件
|
|
245
|
-
this.emit('append_error', {
|
|
246
|
-
key,
|
|
247
|
-
value,
|
|
248
|
-
error
|
|
249
|
-
});
|
|
250
|
-
$.log.error('[cachebase] append操作失败:', error);
|
|
251
|
-
resolve(0);
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 删除键
|
|
121
|
+
* @param {string} key - 键名
|
|
122
|
+
* @returns {Promise<number>} - 返回删除的键数量
|
|
123
|
+
*/
|
|
124
|
+
async del(key) {
|
|
125
|
+
try {
|
|
126
|
+
this.emit('del_before', { key });
|
|
127
|
+
|
|
128
|
+
// 检查键是否存在
|
|
129
|
+
let deleted = 0;
|
|
130
|
+
if (this.data.hasOwnProperty(key)) {
|
|
131
|
+
delete this.data[key];
|
|
132
|
+
const index = this.list.indexOf(key);
|
|
133
|
+
if (index !== -1) {
|
|
134
|
+
this.list.splice(index, 1);
|
|
135
|
+
}
|
|
136
|
+
deleted = 1;
|
|
252
137
|
}
|
|
253
|
-
|
|
138
|
+
|
|
139
|
+
this.emit('del_after', { key, result: deleted });
|
|
140
|
+
return deleted;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
this.emit('del_error', { key, error });
|
|
143
|
+
this.log.error('[cachebase] del操作失败:', error);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
254
146
|
}
|
|
255
147
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
//
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
148
|
+
/**
|
|
149
|
+
* 检查键是否存在
|
|
150
|
+
* @param {string|Array<string>} key - 键名或键名数组
|
|
151
|
+
* @returns {Promise<number>} - 返回存在的键数量
|
|
152
|
+
*/
|
|
153
|
+
async exists(key) {
|
|
154
|
+
try {
|
|
155
|
+
let existsCount = 0;
|
|
156
|
+
|
|
157
|
+
// 检查输入类型并处理
|
|
158
|
+
if (Array.isArray(key)) {
|
|
159
|
+
// 处理多键检查
|
|
160
|
+
for (const k of key) {
|
|
161
|
+
if (this.data.hasOwnProperty(k)) {
|
|
162
|
+
// 检查是否过期
|
|
163
|
+
const item = this.data[k];
|
|
164
|
+
if (!(item.expire > 0 && Date.now() > item.expire)) {
|
|
165
|
+
existsCount++;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
271
168
|
}
|
|
272
|
-
|
|
273
|
-
//
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
169
|
+
} else {
|
|
170
|
+
// 处理单键检查
|
|
171
|
+
if (this.data.hasOwnProperty(key)) {
|
|
172
|
+
// 检查是否过期
|
|
173
|
+
const item = this.data[key];
|
|
174
|
+
if (!(item.expire > 0 && Date.now() > item.expire)) {
|
|
175
|
+
existsCount = 1;
|
|
176
|
+
}
|
|
278
177
|
}
|
|
279
|
-
|
|
280
|
-
// 触发后置事件
|
|
281
|
-
this.emit('strlen_after', {
|
|
282
|
-
key,
|
|
283
|
-
result
|
|
284
|
-
});
|
|
285
|
-
resolve(result);
|
|
286
|
-
} catch (error) {
|
|
287
|
-
// 触发错误事件
|
|
288
|
-
this.emit('strlen_error', {
|
|
289
|
-
key,
|
|
290
|
-
error
|
|
291
|
-
});
|
|
292
|
-
$.log.error('[cachebase] strlen操作失败:', error);
|
|
293
|
-
resolve(0);
|
|
294
178
|
}
|
|
295
|
-
|
|
179
|
+
|
|
180
|
+
return existsCount;
|
|
181
|
+
} catch (error) {
|
|
182
|
+
this.log.error('[cachebase] exists操作失败:', error);
|
|
183
|
+
throw error;
|
|
184
|
+
}
|
|
296
185
|
}
|
|
297
186
|
|
|
298
|
-
|
|
187
|
+
/**
|
|
188
|
+
* 设置哈希表字段
|
|
189
|
+
* @param {string} key - 键名
|
|
190
|
+
* @param {string} field - 字段名
|
|
191
|
+
* @param {*} value - 字段值
|
|
192
|
+
* @returns {Promise<number>} - 返回1表示新建字段,0表示更新字段
|
|
193
|
+
*/
|
|
299
194
|
async hset(key, field, value) {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// 确保哈希表存在
|
|
317
|
-
if (!this.data[key]) {
|
|
318
|
-
this.data[key] = { value: {}, expire: 0 };
|
|
319
|
-
// 添加到列表
|
|
320
|
-
if (!this.list.includes(key)) {
|
|
321
|
-
this.list.push(key);
|
|
322
|
-
}
|
|
323
|
-
} else if (typeof this.data[key].value !== 'object') {
|
|
324
|
-
this.data[key].value = {};
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// 记录是否是新字段
|
|
328
|
-
const isNewField = !this.data[key].value.hasOwnProperty(field);
|
|
329
|
-
|
|
330
|
-
// 设置字段值
|
|
331
|
-
this.data[key].value[field] = value;
|
|
332
|
-
|
|
333
|
-
// 触发后置事件
|
|
334
|
-
this.emit('hset_after', {
|
|
335
|
-
key,
|
|
336
|
-
value: { field, value },
|
|
337
|
-
result: isNewField ? 1 : 0
|
|
338
|
-
});
|
|
339
|
-
resolve(isNewField ? 1 : 0);
|
|
340
|
-
} catch (error) {
|
|
341
|
-
// 触发错误事件
|
|
342
|
-
this.emit('hset_error', {
|
|
343
|
-
key,
|
|
344
|
-
value: { field, value },
|
|
345
|
-
error
|
|
346
|
-
});
|
|
347
|
-
$.log.error('[cachebase] hset操作失败:', error);
|
|
348
|
-
resolve(0);
|
|
195
|
+
try {
|
|
196
|
+
this.emit('hset_before', { key, field, value });
|
|
197
|
+
|
|
198
|
+
// 初始化哈希表
|
|
199
|
+
if (!this.data.hasOwnProperty(key)) {
|
|
200
|
+
this.data[key] = { value: {}, expire: 0 };
|
|
201
|
+
this.list.push(key);
|
|
202
|
+
} else if (this.data[key].expire > 0 && Date.now() > this.data[key].expire) {
|
|
203
|
+
// 键已过期,重新初始化
|
|
204
|
+
this.data[key] = { value: {}, expire: 0 };
|
|
205
|
+
} else if (typeof this.data[key].value !== 'object') {
|
|
206
|
+
// 类型错误
|
|
207
|
+
throw new Error(`[cachebase] 键 ${key} 不是哈希表类型`);
|
|
349
208
|
}
|
|
350
|
-
|
|
209
|
+
|
|
210
|
+
// 检查字段是否存在
|
|
211
|
+
const isNewField = !this.data[key].value.hasOwnProperty(field);
|
|
212
|
+
this.data[key].value[field] = value;
|
|
213
|
+
|
|
214
|
+
const result = isNewField ? 1 : 0;
|
|
215
|
+
this.emit('hset_after', { key, field, value, result });
|
|
216
|
+
return result;
|
|
217
|
+
} catch (error) {
|
|
218
|
+
this.emit('hset_error', { key, field, value, error });
|
|
219
|
+
this.log.error('[cachebase] hset操作失败:', error);
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
351
222
|
}
|
|
352
223
|
|
|
353
|
-
|
|
224
|
+
/**
|
|
225
|
+
* 获取哈希表字段
|
|
226
|
+
* @param {string} key - 键名
|
|
227
|
+
* @param {string} field - 字段名
|
|
228
|
+
* @returns {Promise<*>} - 返回字段值,不存在返回undefined
|
|
229
|
+
*/
|
|
354
230
|
async hget(key, field) {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
key
|
|
360
|
-
|
|
361
|
-
cancel: false
|
|
362
|
-
};
|
|
363
|
-
this.emit('hget_before', beforeEventData);
|
|
364
|
-
|
|
365
|
-
// 如果事件处理器设置了cancel为true,则取消操作
|
|
366
|
-
if (beforeEventData.cancel) {
|
|
367
|
-
resolve(null);
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// 执行实际操作
|
|
372
|
-
const obj = this.data[key];
|
|
373
|
-
let result = null;
|
|
374
|
-
if (obj && typeof obj.value === 'object' && field in obj.value) {
|
|
375
|
-
result = obj.value[field];
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// 触发后置事件
|
|
379
|
-
this.emit('hget_after', {
|
|
380
|
-
key,
|
|
381
|
-
value: { field },
|
|
382
|
-
result
|
|
383
|
-
});
|
|
384
|
-
resolve(result);
|
|
385
|
-
} catch (error) {
|
|
386
|
-
// 触发错误事件
|
|
387
|
-
this.emit('hget_error', {
|
|
388
|
-
key,
|
|
389
|
-
value: { field },
|
|
390
|
-
error
|
|
391
|
-
});
|
|
392
|
-
$.log.error('[cachebase] hget操作失败:', error);
|
|
393
|
-
resolve(null);
|
|
231
|
+
try {
|
|
232
|
+
// 检查键是否存在且未过期
|
|
233
|
+
if (!this.data.hasOwnProperty(key) ||
|
|
234
|
+
(this.data[key].expire > 0 && Date.now() > this.data[key].expire) ||
|
|
235
|
+
typeof this.data[key].value !== 'object') {
|
|
236
|
+
return undefined;
|
|
394
237
|
}
|
|
395
|
-
|
|
238
|
+
|
|
239
|
+
return this.data[key].value[field];
|
|
240
|
+
} catch (error) {
|
|
241
|
+
this.log.error('[cachebase] hget操作失败:', error);
|
|
242
|
+
throw error;
|
|
243
|
+
}
|
|
396
244
|
}
|
|
397
245
|
|
|
398
|
-
|
|
246
|
+
/**
|
|
247
|
+
* 获取哈希表所有字段
|
|
248
|
+
* @param {string} key - 键名
|
|
249
|
+
* @returns {Promise<Object>} - 返回哈希表对象,不存在或不是哈希表返回{}
|
|
250
|
+
*/
|
|
399
251
|
async hgetall(key) {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
key
|
|
405
|
-
|
|
406
|
-
};
|
|
407
|
-
this.emit('hgetall_before', beforeEventData);
|
|
408
|
-
|
|
409
|
-
// 如果事件处理器设置了cancel为true,则取消操作
|
|
410
|
-
if (beforeEventData.cancel) {
|
|
411
|
-
resolve({});
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// 执行实际操作
|
|
416
|
-
const obj = this.data[key];
|
|
417
|
-
let result = {};
|
|
418
|
-
if (obj && typeof obj.value === 'object') {
|
|
419
|
-
result = {...obj.value};
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// 触发后置事件
|
|
423
|
-
this.emit('hgetall_after', {
|
|
424
|
-
key,
|
|
425
|
-
result
|
|
426
|
-
});
|
|
427
|
-
resolve(result);
|
|
428
|
-
} catch (error) {
|
|
429
|
-
// 触发错误事件
|
|
430
|
-
this.emit('hgetall_error', {
|
|
431
|
-
key,
|
|
432
|
-
error
|
|
433
|
-
});
|
|
434
|
-
$.log.error('[cachebase] hgetall操作失败:', error);
|
|
435
|
-
resolve({});
|
|
252
|
+
try {
|
|
253
|
+
// 检查键是否存在且未过期
|
|
254
|
+
if (!this.data.hasOwnProperty(key) ||
|
|
255
|
+
(this.data[key].expire > 0 && Date.now() > this.data[key].expire) ||
|
|
256
|
+
typeof this.data[key].value !== 'object') {
|
|
257
|
+
return {};
|
|
436
258
|
}
|
|
437
|
-
|
|
259
|
+
|
|
260
|
+
// 返回哈希表的副本
|
|
261
|
+
return { ...this.data[key].value };
|
|
262
|
+
} catch (error) {
|
|
263
|
+
this.log.error('[cachebase] hgetall操作失败:', error);
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
438
266
|
}
|
|
439
267
|
|
|
440
|
-
|
|
268
|
+
/**
|
|
269
|
+
* 删除哈希表字段
|
|
270
|
+
* @param {string} key - 键名
|
|
271
|
+
* @param {string} field - 字段名
|
|
272
|
+
* @returns {Promise<number>} - 返回删除的字段数量
|
|
273
|
+
*/
|
|
441
274
|
async hdel(key, field) {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
this.emit('
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
delete this.data[key];
|
|
466
|
-
const index = this.list.indexOf(key);
|
|
467
|
-
if (index > -1) {
|
|
468
|
-
this.list.splice(index, 1);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
result = 1;
|
|
275
|
+
try {
|
|
276
|
+
this.emit('hdel_before', { key, field });
|
|
277
|
+
|
|
278
|
+
// 检查键是否存在且未过期
|
|
279
|
+
if (!this.data.hasOwnProperty(key) ||
|
|
280
|
+
(this.data[key].expire > 0 && Date.now() > this.data[key].expire) ||
|
|
281
|
+
typeof this.data[key].value !== 'object' ||
|
|
282
|
+
!this.data[key].value.hasOwnProperty(field)) {
|
|
283
|
+
this.emit('hdel_after', { key, field, result: 0 });
|
|
284
|
+
return 0;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// 删除字段
|
|
288
|
+
delete this.data[key].value[field];
|
|
289
|
+
|
|
290
|
+
// 检查哈希表是否为空
|
|
291
|
+
const hashKeys = Object.keys(this.data[key].value);
|
|
292
|
+
if (hashKeys.length === 0) {
|
|
293
|
+
// 删除空哈希表
|
|
294
|
+
delete this.data[key];
|
|
295
|
+
const index = this.list.indexOf(key);
|
|
296
|
+
if (index !== -1) {
|
|
297
|
+
this.list.splice(index, 1);
|
|
472
298
|
}
|
|
473
|
-
|
|
474
|
-
// 触发后置事件
|
|
475
|
-
this.emit('hdel_after', {
|
|
476
|
-
key,
|
|
477
|
-
value: { field },
|
|
478
|
-
result
|
|
479
|
-
});
|
|
480
|
-
resolve(result);
|
|
481
|
-
} catch (error) {
|
|
482
|
-
// 触发错误事件
|
|
483
|
-
this.emit('hdel_error', {
|
|
484
|
-
key,
|
|
485
|
-
value: { field },
|
|
486
|
-
error
|
|
487
|
-
});
|
|
488
|
-
$.log.error('[cachebase] hdel操作失败:', error);
|
|
489
|
-
resolve(0);
|
|
490
299
|
}
|
|
491
|
-
|
|
300
|
+
|
|
301
|
+
this.emit('hdel_after', { key, field, result: 1 });
|
|
302
|
+
return 1;
|
|
303
|
+
} catch (error) {
|
|
304
|
+
this.emit('hdel_error', { key, field, error });
|
|
305
|
+
this.log.error('[cachebase] hdel操作失败:', error);
|
|
306
|
+
throw error;
|
|
307
|
+
}
|
|
492
308
|
}
|
|
493
309
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
// 参数校验
|
|
512
|
-
if (args.length % 2 !== 0) {
|
|
513
|
-
$.log.error('[cachebase] mset参数数量不正确');
|
|
514
|
-
resolve('ERR');
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// 执行实际操作
|
|
519
|
-
for (let i = 0; i < args.length; i += 2) {
|
|
520
|
-
const key = args[i];
|
|
521
|
-
const value = args[i + 1];
|
|
522
|
-
this.data[key] = { value, expire: 0 };
|
|
523
|
-
// 添加到列表
|
|
310
|
+
/**
|
|
311
|
+
* 批量设置键值
|
|
312
|
+
* @param {Object} keyValues - 键值对对象
|
|
313
|
+
* @returns {Promise<string>} - 返回'OK'
|
|
314
|
+
*/
|
|
315
|
+
async mset(keyValues) {
|
|
316
|
+
try {
|
|
317
|
+
this.emit('mset_before', { keyValues });
|
|
318
|
+
|
|
319
|
+
if (typeof keyValues !== 'object' || keyValues === null) {
|
|
320
|
+
throw new Error('[cachebase] mset参数必须是对象');
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// 批量设置键值
|
|
324
|
+
for (const key in keyValues) {
|
|
325
|
+
if (keyValues.hasOwnProperty(key)) {
|
|
326
|
+
this.data[key] = { value: keyValues[key], expire: 0 };
|
|
524
327
|
if (!this.list.includes(key)) {
|
|
525
328
|
this.list.push(key);
|
|
526
329
|
}
|
|
527
330
|
}
|
|
528
|
-
|
|
529
|
-
// 触发后置事件
|
|
530
|
-
this.emit('mset_after', {
|
|
531
|
-
value: { args },
|
|
532
|
-
result: 'OK'
|
|
533
|
-
});
|
|
534
|
-
resolve('OK');
|
|
535
|
-
} catch (error) {
|
|
536
|
-
// 触发错误事件
|
|
537
|
-
this.emit('mset_error', {
|
|
538
|
-
value: { args },
|
|
539
|
-
error
|
|
540
|
-
});
|
|
541
|
-
$.log.error('[cachebase] mset操作失败:', error);
|
|
542
|
-
resolve('ERR');
|
|
543
331
|
}
|
|
544
|
-
|
|
332
|
+
|
|
333
|
+
this.emit('mset_after', { keyValues, result: 'OK' });
|
|
334
|
+
return 'OK';
|
|
335
|
+
} catch (error) {
|
|
336
|
+
this.emit('mset_error', { keyValues, error });
|
|
337
|
+
this.log.error('[cachebase] mset操作失败:', error);
|
|
338
|
+
throw error;
|
|
339
|
+
}
|
|
545
340
|
}
|
|
546
341
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
this.emit('mget_before', beforeEventData);
|
|
557
|
-
|
|
558
|
-
// 如果事件处理器设置了cancel为true,则取消操作
|
|
559
|
-
if (beforeEventData.cancel) {
|
|
560
|
-
resolve([]);
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// 执行实际操作 - 返回数组格式,与Redis保持一致
|
|
565
|
-
const result = keys.map(key => {
|
|
566
|
-
const obj = this.data[key];
|
|
567
|
-
return obj ? obj.value : null;
|
|
568
|
-
});
|
|
569
|
-
|
|
570
|
-
// 触发后置事件
|
|
571
|
-
this.emit('mget_after', {
|
|
572
|
-
value: { keys },
|
|
573
|
-
result
|
|
574
|
-
});
|
|
575
|
-
resolve(result);
|
|
576
|
-
} catch (error) {
|
|
577
|
-
// 触发错误事件
|
|
578
|
-
this.emit('mget_error', {
|
|
579
|
-
value: { keys },
|
|
580
|
-
error
|
|
581
|
-
});
|
|
582
|
-
$.log.error('[cachebase] mget操作失败:', error);
|
|
583
|
-
resolve([]);
|
|
342
|
+
/**
|
|
343
|
+
* 批量获取键值
|
|
344
|
+
* @param {Array<string>} keys - 键名数组
|
|
345
|
+
* @returns {Promise<Array>} - 返回值数组
|
|
346
|
+
*/
|
|
347
|
+
async mget(keys) {
|
|
348
|
+
try {
|
|
349
|
+
if (!Array.isArray(keys)) {
|
|
350
|
+
throw new Error('[cachebase] mget参数必须是数组');
|
|
584
351
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
352
|
+
|
|
353
|
+
// 批量获取键值
|
|
354
|
+
const results = [];
|
|
355
|
+
for (const key of keys) {
|
|
356
|
+
if (this.data.hasOwnProperty(key)) {
|
|
357
|
+
// 检查是否过期
|
|
358
|
+
const item = this.data[key];
|
|
359
|
+
if (item.expire === 0 || Date.now() <= item.expire) {
|
|
360
|
+
results.push(item.value);
|
|
361
|
+
} else {
|
|
362
|
+
// 删除过期键
|
|
363
|
+
delete this.data[key];
|
|
364
|
+
const index = this.list.indexOf(key);
|
|
365
|
+
if (index !== -1) {
|
|
366
|
+
this.list.splice(index, 1);
|
|
367
|
+
}
|
|
368
|
+
results.push(undefined);
|
|
369
|
+
}
|
|
370
|
+
} else {
|
|
371
|
+
results.push(undefined);
|
|
603
372
|
}
|
|
604
|
-
|
|
605
|
-
// 执行实际操作
|
|
606
|
-
const result = keys.filter(key => key in this.data).length;
|
|
607
|
-
|
|
608
|
-
// 触发后置事件
|
|
609
|
-
this.emit('exists_after', {
|
|
610
|
-
value: { keys },
|
|
611
|
-
result
|
|
612
|
-
});
|
|
613
|
-
resolve(result);
|
|
614
|
-
} catch (error) {
|
|
615
|
-
// 触发错误事件
|
|
616
|
-
this.emit('exists_error', {
|
|
617
|
-
value: { keys },
|
|
618
|
-
error
|
|
619
|
-
});
|
|
620
|
-
$.log.error('[cachebase] exists操作失败:', error);
|
|
621
|
-
resolve(0);
|
|
622
373
|
}
|
|
623
|
-
|
|
374
|
+
|
|
375
|
+
return results;
|
|
376
|
+
} catch (error) {
|
|
377
|
+
this.log.error('[cachebase] mget操作失败:', error);
|
|
378
|
+
throw error;
|
|
379
|
+
}
|
|
624
380
|
}
|
|
625
381
|
|
|
626
|
-
|
|
382
|
+
/**
|
|
383
|
+
* 获取键的剩余生存时间
|
|
384
|
+
* @param {string} key - 键名
|
|
385
|
+
* @returns {Promise<number>} - 返回剩余时间(秒),-1表示永不过期,-2表示键不存在
|
|
386
|
+
*/
|
|
627
387
|
async ttl(key) {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
if (
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
const obj = this.data[key];
|
|
645
|
-
let result;
|
|
646
|
-
|
|
647
|
-
if (!obj) {
|
|
648
|
-
result = -2; // 键不存在
|
|
649
|
-
} else {
|
|
650
|
-
// 查询过期时间
|
|
651
|
-
if (obj.expire === 0) {
|
|
652
|
-
result = -1; // 永不过期
|
|
653
|
-
} else {
|
|
654
|
-
const remaining = Math.floor((obj.expire - Date.now()) / 1000);
|
|
655
|
-
result = remaining > 0 ? remaining : -2; // -2表示已过期
|
|
388
|
+
try {
|
|
389
|
+
// 检查键是否存在
|
|
390
|
+
if (!this.data.hasOwnProperty(key)) {
|
|
391
|
+
return -2;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const item = this.data[key];
|
|
395
|
+
|
|
396
|
+
// 检查是否过期
|
|
397
|
+
if (item.expire > 0) {
|
|
398
|
+
if (Date.now() > item.expire) {
|
|
399
|
+
// 键已过期,删除并返回-2
|
|
400
|
+
delete this.data[key];
|
|
401
|
+
const index = this.list.indexOf(key);
|
|
402
|
+
if (index !== -1) {
|
|
403
|
+
this.list.splice(index, 1);
|
|
656
404
|
}
|
|
405
|
+
return -2;
|
|
406
|
+
} else {
|
|
407
|
+
// 计算剩余时间
|
|
408
|
+
const ttl = Math.floor((item.expire - Date.now()) / 1000);
|
|
409
|
+
return ttl;
|
|
657
410
|
}
|
|
658
|
-
|
|
659
|
-
//
|
|
660
|
-
|
|
661
|
-
key,
|
|
662
|
-
result
|
|
663
|
-
});
|
|
664
|
-
resolve(result);
|
|
665
|
-
} catch (error) {
|
|
666
|
-
// 触发错误事件
|
|
667
|
-
this.emit('ttl_error', {
|
|
668
|
-
key,
|
|
669
|
-
error
|
|
670
|
-
});
|
|
671
|
-
$.log.error('[cachebase] ttl操作失败:', error);
|
|
672
|
-
resolve(-2);
|
|
411
|
+
} else {
|
|
412
|
+
// 永不过期
|
|
413
|
+
return -1;
|
|
673
414
|
}
|
|
674
|
-
})
|
|
415
|
+
} catch (error) {
|
|
416
|
+
this.log.error('[cachebase] ttl操作失败:', error);
|
|
417
|
+
throw error;
|
|
418
|
+
}
|
|
675
419
|
}
|
|
676
420
|
|
|
677
|
-
|
|
421
|
+
/**
|
|
422
|
+
* 设置键的过期时间
|
|
423
|
+
* @param {string} key - 键名
|
|
424
|
+
* @param {number} seconds - 过期时间(秒)
|
|
425
|
+
* @returns {Promise<number>} - 返回1表示设置成功,0表示键不存在
|
|
426
|
+
*/
|
|
678
427
|
async expire(key, seconds) {
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
if (obj) {
|
|
700
|
-
if (seconds === 0) {
|
|
701
|
-
obj.expire = 0; // 永不过期
|
|
702
|
-
} else {
|
|
703
|
-
obj.expire = Date.now() + (parseInt(seconds, 10) * 1000);
|
|
704
|
-
}
|
|
705
|
-
result = 1;
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
// 触发后置事件
|
|
709
|
-
this.emit('expire_after', {
|
|
710
|
-
key,
|
|
711
|
-
value: { seconds },
|
|
712
|
-
result
|
|
713
|
-
});
|
|
714
|
-
resolve(result);
|
|
715
|
-
} catch (error) {
|
|
716
|
-
// 触发错误事件
|
|
717
|
-
this.emit('expire_error', {
|
|
718
|
-
key,
|
|
719
|
-
value: { seconds },
|
|
720
|
-
error
|
|
721
|
-
});
|
|
722
|
-
$.log.error('[cachebase] expire操作失败:', error);
|
|
723
|
-
resolve(0);
|
|
428
|
+
try {
|
|
429
|
+
this.emit('expire_before', { key, seconds });
|
|
430
|
+
|
|
431
|
+
// 检查键是否存在
|
|
432
|
+
if (!this.data.hasOwnProperty(key)) {
|
|
433
|
+
this.emit('expire_after', { key, seconds, result: 0 });
|
|
434
|
+
return 0;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// 检查是否已过期
|
|
438
|
+
const item = this.data[key];
|
|
439
|
+
if (item.expire > 0 && Date.now() > item.expire) {
|
|
440
|
+
// 键已过期,删除并返回0
|
|
441
|
+
delete this.data[key];
|
|
442
|
+
const index = this.list.indexOf(key);
|
|
443
|
+
if (index !== -1) {
|
|
444
|
+
this.list.splice(index, 1);
|
|
445
|
+
}
|
|
446
|
+
this.emit('expire_after', { key, seconds, result: 0 });
|
|
447
|
+
return 0;
|
|
724
448
|
}
|
|
725
|
-
|
|
449
|
+
|
|
450
|
+
// 设置过期时间
|
|
451
|
+
this.data[key].expire = Date.now() + seconds * 1000;
|
|
452
|
+
|
|
453
|
+
this.emit('expire_after', { key, seconds, result: 1 });
|
|
454
|
+
return 1;
|
|
455
|
+
} catch (error) {
|
|
456
|
+
this.emit('expire_error', { key, seconds, error });
|
|
457
|
+
this.log.error('[cachebase] expire操作失败:', error);
|
|
458
|
+
throw error;
|
|
459
|
+
}
|
|
726
460
|
}
|
|
727
461
|
|
|
728
|
-
|
|
462
|
+
/**
|
|
463
|
+
* 移除键的过期时间
|
|
464
|
+
* @param {string} key - 键名
|
|
465
|
+
* @returns {Promise<number>} - 返回1表示移除成功,0表示键不存在或没有过期时间
|
|
466
|
+
*/
|
|
729
467
|
async persist(key) {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
this.emit('persist_before', beforeEventData);
|
|
738
|
-
|
|
739
|
-
// 如果事件处理器设置了cancel为true,则取消操作
|
|
740
|
-
if (beforeEventData.cancel) {
|
|
741
|
-
resolve(0);
|
|
742
|
-
return;
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
// 执行实际操作
|
|
746
|
-
const obj = this.data[key];
|
|
747
|
-
let result = 0;
|
|
748
|
-
|
|
749
|
-
if (obj && obj.expire !== 0) {
|
|
750
|
-
obj.expire = 0; // 移除过期时间
|
|
751
|
-
result = 1;
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
// 触发后置事件
|
|
755
|
-
this.emit('persist_after', {
|
|
756
|
-
key,
|
|
757
|
-
result
|
|
758
|
-
});
|
|
759
|
-
resolve(result);
|
|
760
|
-
} catch (error) {
|
|
761
|
-
// 触发错误事件
|
|
762
|
-
this.emit('persist_error', {
|
|
763
|
-
key,
|
|
764
|
-
error
|
|
765
|
-
});
|
|
766
|
-
$.log.error('[cachebase] persist操作失败:', error);
|
|
767
|
-
resolve(0);
|
|
468
|
+
try {
|
|
469
|
+
this.emit('persist_before', { key });
|
|
470
|
+
|
|
471
|
+
// 检查键是否存在
|
|
472
|
+
if (!this.data.hasOwnProperty(key)) {
|
|
473
|
+
this.emit('persist_after', { key, result: 0 });
|
|
474
|
+
return 0;
|
|
768
475
|
}
|
|
769
|
-
|
|
476
|
+
|
|
477
|
+
// 检查是否已过期
|
|
478
|
+
const item = this.data[key];
|
|
479
|
+
if (item.expire > 0 && Date.now() > item.expire) {
|
|
480
|
+
// 键已过期,删除并返回0
|
|
481
|
+
delete this.data[key];
|
|
482
|
+
const index = this.list.indexOf(key);
|
|
483
|
+
if (index !== -1) {
|
|
484
|
+
this.list.splice(index, 1);
|
|
485
|
+
}
|
|
486
|
+
this.emit('persist_after', { key, result: 0 });
|
|
487
|
+
return 0;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// 检查是否有过期时间
|
|
491
|
+
if (item.expire === 0) {
|
|
492
|
+
// 没有过期时间,返回0
|
|
493
|
+
this.emit('persist_after', { key, result: 0 });
|
|
494
|
+
return 0;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// 移除过期时间
|
|
498
|
+
this.data[key].expire = 0;
|
|
499
|
+
|
|
500
|
+
this.emit('persist_after', { key, result: 1 });
|
|
501
|
+
return 1;
|
|
502
|
+
} catch (error) {
|
|
503
|
+
this.emit('persist_error', { key, error });
|
|
504
|
+
this.log.error('[cachebase] persist操作失败:', error);
|
|
505
|
+
throw error;
|
|
506
|
+
}
|
|
770
507
|
}
|
|
771
508
|
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
// 执行实际操作
|
|
790
|
-
let result;
|
|
791
|
-
if (!pattern || pattern === '*') {
|
|
792
|
-
result = [...this.list];
|
|
793
|
-
} else {
|
|
794
|
-
// 转换模式为正则表达式
|
|
795
|
-
const regexPattern = pattern
|
|
796
|
-
.replace(/\./g, '\\.')
|
|
797
|
-
.replace(/\*/g, '.*')
|
|
798
|
-
.replace(/\?/g, '.');
|
|
799
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
800
|
-
|
|
801
|
-
// 过滤匹配的键
|
|
802
|
-
result = this.list.filter(key => regex.test(key));
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
// 触发后置事件
|
|
806
|
-
this.emit('keys_after', {
|
|
807
|
-
value: { pattern },
|
|
808
|
-
result
|
|
809
|
-
});
|
|
810
|
-
resolve(result);
|
|
811
|
-
} catch (error) {
|
|
812
|
-
// 触发错误事件
|
|
813
|
-
this.emit('keys_error', {
|
|
814
|
-
value: { pattern },
|
|
815
|
-
error
|
|
816
|
-
});
|
|
817
|
-
$.log.error('[cachebase] keys操作失败:', error);
|
|
818
|
-
resolve([]);
|
|
509
|
+
/**
|
|
510
|
+
* 获取所有键名
|
|
511
|
+
* @param {string} pattern - 模式匹配
|
|
512
|
+
* @returns {Promise<Array>} - 返回键名数组
|
|
513
|
+
*/
|
|
514
|
+
async keys(pattern = '*') {
|
|
515
|
+
try {
|
|
516
|
+
// 支持通配符匹配
|
|
517
|
+
let filteredKeys = [];
|
|
518
|
+
if (pattern === '*') {
|
|
519
|
+
// 通配符匹配所有
|
|
520
|
+
filteredKeys = [...this.list];
|
|
521
|
+
} else {
|
|
522
|
+
// 简单的通配符匹配
|
|
523
|
+
const regex = new RegExp(pattern.replace(/\*/g, '.*'));
|
|
524
|
+
filteredKeys = this.list.filter(key => regex.test(key));
|
|
819
525
|
}
|
|
820
|
-
|
|
526
|
+
|
|
527
|
+
return filteredKeys;
|
|
528
|
+
} catch (error) {
|
|
529
|
+
this.log.error('[cachebase] keys操作失败:', error);
|
|
530
|
+
throw error;
|
|
531
|
+
}
|
|
821
532
|
}
|
|
822
533
|
|
|
823
|
-
|
|
534
|
+
/**
|
|
535
|
+
* 获取键数量
|
|
536
|
+
* @returns {Promise<number>} - 返回键数量
|
|
537
|
+
*/
|
|
824
538
|
async dbsize() {
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
if (beforeEventData.cancel) {
|
|
835
|
-
resolve(0);
|
|
836
|
-
return;
|
|
539
|
+
try {
|
|
540
|
+
// 过滤掉已过期的键
|
|
541
|
+
let count = 0;
|
|
542
|
+
for (const key of this.list) {
|
|
543
|
+
if (this.data.hasOwnProperty(key)) {
|
|
544
|
+
const item = this.data[key];
|
|
545
|
+
if (item.expire === 0 || Date.now() <= item.expire) {
|
|
546
|
+
count++;
|
|
547
|
+
}
|
|
837
548
|
}
|
|
838
|
-
|
|
839
|
-
// 执行实际操作
|
|
840
|
-
const result = this.list.length;
|
|
841
|
-
|
|
842
|
-
// 触发后置事件
|
|
843
|
-
this.emit('dbsize_after', {
|
|
844
|
-
result
|
|
845
|
-
});
|
|
846
|
-
resolve(result);
|
|
847
|
-
} catch (error) {
|
|
848
|
-
// 触发错误事件
|
|
849
|
-
this.emit('dbsize_error', {
|
|
850
|
-
error
|
|
851
|
-
});
|
|
852
|
-
$.log.error('[cachebase] dbsize操作失败:', error);
|
|
853
|
-
resolve(0);
|
|
854
549
|
}
|
|
855
|
-
|
|
550
|
+
|
|
551
|
+
return count;
|
|
552
|
+
} catch (error) {
|
|
553
|
+
this.log.error('[cachebase] dbsize操作失败:', error);
|
|
554
|
+
throw error;
|
|
555
|
+
}
|
|
856
556
|
}
|
|
857
557
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
558
|
+
/**
|
|
559
|
+
* 设置键值并返回旧值
|
|
560
|
+
* @param {string} key - 键名
|
|
561
|
+
* @param {*} value - 键值
|
|
562
|
+
* @returns {Promise<*>} - 返回旧值
|
|
563
|
+
*/
|
|
564
|
+
async getset(key, value) {
|
|
565
|
+
try {
|
|
566
|
+
this.emit('getset_before', { key, value });
|
|
567
|
+
|
|
568
|
+
// 获取旧值
|
|
569
|
+
let oldValue = undefined;
|
|
570
|
+
if (this.data.hasOwnProperty(key)) {
|
|
571
|
+
const item = this.data[key];
|
|
572
|
+
if (!(item.expire > 0 && Date.now() > item.expire)) {
|
|
573
|
+
oldValue = item.value;
|
|
872
574
|
}
|
|
873
|
-
|
|
874
|
-
// 执行实际操作
|
|
875
|
-
this.data = {};
|
|
876
|
-
this.list = [];
|
|
877
|
-
this.dict = this.data; // 同步dict引用
|
|
878
|
-
|
|
879
|
-
// 触发后置事件
|
|
880
|
-
this.emit('flushdb_after', {
|
|
881
|
-
result: 'OK'
|
|
882
|
-
});
|
|
883
|
-
resolve('OK');
|
|
884
|
-
} catch (error) {
|
|
885
|
-
// 触发错误事件
|
|
886
|
-
this.emit('flushdb_error', {
|
|
887
|
-
error
|
|
888
|
-
});
|
|
889
|
-
$.log.error('[cachebase] flushdb操作失败:', error);
|
|
890
|
-
resolve(null);
|
|
891
575
|
}
|
|
892
|
-
|
|
576
|
+
|
|
577
|
+
// 设置新值
|
|
578
|
+
this.data[key] = { value, expire: 0 };
|
|
579
|
+
|
|
580
|
+
// 添加到键列表
|
|
581
|
+
if (!this.list.includes(key)) {
|
|
582
|
+
this.list.push(key);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
this.emit('getset_after', { key, value, result: oldValue });
|
|
586
|
+
return oldValue;
|
|
587
|
+
} catch (error) {
|
|
588
|
+
this.emit('getset_error', { key, value, error });
|
|
589
|
+
this.log.error('[cachebase] getset操作失败:', error);
|
|
590
|
+
throw error;
|
|
591
|
+
}
|
|
893
592
|
}
|
|
894
593
|
|
|
895
|
-
|
|
594
|
+
/**
|
|
595
|
+
* 数值递增
|
|
596
|
+
* @param {string} key - 键名
|
|
597
|
+
* @returns {Promise<number>} - 返回递增后的值
|
|
598
|
+
*/
|
|
896
599
|
async incr(key) {
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
currentValue = parseInt(this.data[key].value, 10);
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
// 执行递增
|
|
919
|
-
const result = currentValue + 1;
|
|
920
|
-
|
|
921
|
-
// 保存结果
|
|
922
|
-
this.data[key] = { value: result, expire: 0 };
|
|
923
|
-
|
|
924
|
-
// 如果键不存在于列表中,添加到列表
|
|
925
|
-
if (!this.list.includes(key)) {
|
|
926
|
-
this.list.push(key);
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
// 触发后置事件
|
|
930
|
-
this.emit('incr_after', {
|
|
931
|
-
key,
|
|
932
|
-
result
|
|
933
|
-
});
|
|
934
|
-
resolve(result);
|
|
935
|
-
} catch (error) {
|
|
936
|
-
// 触发错误事件
|
|
937
|
-
this.emit('incr_error', {
|
|
938
|
-
key,
|
|
939
|
-
error
|
|
940
|
-
});
|
|
941
|
-
$.log.error('[cachebase] incr操作失败:', error);
|
|
942
|
-
resolve(0);
|
|
600
|
+
try {
|
|
601
|
+
this.emit('incr_before', { key });
|
|
602
|
+
|
|
603
|
+
// 获取当前值或默认为0
|
|
604
|
+
let currentValue = 0;
|
|
605
|
+
if (this.data.hasOwnProperty(key) && !this._checkExpire(key)) {
|
|
606
|
+
currentValue = parseFloat(this.data[key].value) || 0;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// 递增
|
|
610
|
+
const result = currentValue + 1;
|
|
611
|
+
|
|
612
|
+
// 保存结果
|
|
613
|
+
this.data[key] = { value: result, expire: 0 };
|
|
614
|
+
|
|
615
|
+
// 如果键不存在于列表中,添加到列表
|
|
616
|
+
if (!this.list.includes(key)) {
|
|
617
|
+
this.list.push(key);
|
|
943
618
|
}
|
|
944
|
-
|
|
619
|
+
|
|
620
|
+
this.emit('incr_after', { key, result });
|
|
621
|
+
return result;
|
|
622
|
+
} catch (error) {
|
|
623
|
+
this.emit('incr_error', { key, error });
|
|
624
|
+
this.log.error('[cachebase] incr操作失败:', error);
|
|
625
|
+
throw error;
|
|
626
|
+
}
|
|
945
627
|
}
|
|
946
628
|
|
|
947
|
-
|
|
629
|
+
/**
|
|
630
|
+
* 数值递减
|
|
631
|
+
* @param {string} key - 键名
|
|
632
|
+
* @returns {Promise<number>} - 返回递减后的值
|
|
633
|
+
*/
|
|
948
634
|
async decr(key) {
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
currentValue = parseInt(this.data[key].value, 10);
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
// 执行递减
|
|
971
|
-
const result = currentValue - 1;
|
|
972
|
-
|
|
973
|
-
// 保存结果
|
|
974
|
-
this.data[key] = { value: result, expire: 0 };
|
|
975
|
-
|
|
976
|
-
// 如果键不存在于列表中,添加到列表
|
|
977
|
-
if (!this.list.includes(key)) {
|
|
978
|
-
this.list.push(key);
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
// 触发后置事件
|
|
982
|
-
this.emit('decr_after', {
|
|
983
|
-
key,
|
|
984
|
-
result
|
|
985
|
-
});
|
|
986
|
-
resolve(result);
|
|
987
|
-
} catch (error) {
|
|
988
|
-
// 触发错误事件
|
|
989
|
-
this.emit('decr_error', {
|
|
990
|
-
key,
|
|
991
|
-
error
|
|
992
|
-
});
|
|
993
|
-
$.log.error('[cachebase] decr操作失败:', error);
|
|
994
|
-
resolve(0);
|
|
635
|
+
try {
|
|
636
|
+
this.emit('decr_before', { key });
|
|
637
|
+
|
|
638
|
+
// 获取当前值或默认为0
|
|
639
|
+
let currentValue = 0;
|
|
640
|
+
if (this.data.hasOwnProperty(key) && !this._checkExpire(key)) {
|
|
641
|
+
currentValue = parseFloat(this.data[key].value) || 0;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// 递减
|
|
645
|
+
const result = currentValue - 1;
|
|
646
|
+
|
|
647
|
+
// 保存结果
|
|
648
|
+
this.data[key] = { value: result, expire: 0 };
|
|
649
|
+
|
|
650
|
+
// 如果键不存在于列表中,添加到列表
|
|
651
|
+
if (!this.list.includes(key)) {
|
|
652
|
+
this.list.push(key);
|
|
995
653
|
}
|
|
996
|
-
|
|
654
|
+
|
|
655
|
+
this.emit('decr_after', { key, result });
|
|
656
|
+
return result;
|
|
657
|
+
} catch (error) {
|
|
658
|
+
this.emit('decr_error', { key, error });
|
|
659
|
+
this.log.error('[cachebase] decr操作失败:', error);
|
|
660
|
+
throw error;
|
|
661
|
+
}
|
|
997
662
|
}
|
|
998
663
|
|
|
999
|
-
|
|
664
|
+
/**
|
|
665
|
+
* 数值增加指定值
|
|
666
|
+
* @param {string} key - 键名
|
|
667
|
+
* @param {number} increment - 增加的值
|
|
668
|
+
* @returns {Promise<number>} - 返回增加后的值
|
|
669
|
+
*/
|
|
1000
670
|
async incrby(key, increment) {
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
if (this.data[key] && !isNaN(this.data[key].value)) {
|
|
1020
|
-
currentValue = parseInt(this.data[key].value, 10);
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
// 执行递增
|
|
1024
|
-
const result = currentValue + parseInt(increment, 10);
|
|
1025
|
-
|
|
1026
|
-
// 保存结果
|
|
1027
|
-
this.data[key] = { value: result, expire: 0 };
|
|
1028
|
-
|
|
1029
|
-
// 如果键不存在于列表中,添加到列表
|
|
1030
|
-
if (!this.list.includes(key)) {
|
|
1031
|
-
this.list.push(key);
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
// 触发后置事件
|
|
1035
|
-
this.emit('incrby_after', {
|
|
1036
|
-
key,
|
|
1037
|
-
value: { increment },
|
|
1038
|
-
result
|
|
1039
|
-
});
|
|
1040
|
-
resolve(result);
|
|
1041
|
-
} catch (error) {
|
|
1042
|
-
// 触发错误事件
|
|
1043
|
-
this.emit('incrby_error', {
|
|
1044
|
-
key,
|
|
1045
|
-
value: { increment },
|
|
1046
|
-
error
|
|
1047
|
-
});
|
|
1048
|
-
$.log.error('[cachebase] incrby操作失败:', error);
|
|
1049
|
-
resolve(0);
|
|
671
|
+
try {
|
|
672
|
+
this.emit('incrby_before', { key, increment });
|
|
673
|
+
|
|
674
|
+
// 获取当前值或默认为0
|
|
675
|
+
let currentValue = 0;
|
|
676
|
+
if (this.data.hasOwnProperty(key) && !this._checkExpire(key)) {
|
|
677
|
+
currentValue = parseFloat(this.data[key].value) || 0;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// 增加指定值
|
|
681
|
+
const result = currentValue + parseFloat(increment);
|
|
682
|
+
|
|
683
|
+
// 保存结果
|
|
684
|
+
this.data[key] = { value: result, expire: 0 };
|
|
685
|
+
|
|
686
|
+
// 如果键不存在于列表中,添加到列表
|
|
687
|
+
if (!this.list.includes(key)) {
|
|
688
|
+
this.list.push(key);
|
|
1050
689
|
}
|
|
1051
|
-
|
|
690
|
+
|
|
691
|
+
this.emit('incrby_after', { key, increment, result });
|
|
692
|
+
return result;
|
|
693
|
+
} catch (error) {
|
|
694
|
+
this.emit('incrby_error', { key, increment, error });
|
|
695
|
+
this.log.error('[cachebase] incrby操作失败:', error);
|
|
696
|
+
throw error;
|
|
697
|
+
}
|
|
1052
698
|
}
|
|
1053
699
|
|
|
1054
|
-
|
|
700
|
+
/**
|
|
701
|
+
* 数值减少指定值
|
|
702
|
+
* @param {string} key - 键名
|
|
703
|
+
* @param {number} decrement - 减少的值
|
|
704
|
+
* @returns {Promise<number>} - 返回减少后的值
|
|
705
|
+
*/
|
|
1055
706
|
async decrby(key, decrement) {
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
if (this.data[key] && !isNaN(this.data[key].value)) {
|
|
1075
|
-
currentValue = parseInt(this.data[key].value, 10);
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
// 执行递减
|
|
1079
|
-
const result = currentValue - parseInt(decrement, 10);
|
|
1080
|
-
|
|
1081
|
-
// 保存结果
|
|
1082
|
-
this.data[key] = { value: result, expire: 0 };
|
|
1083
|
-
|
|
1084
|
-
// 如果键不存在于列表中,添加到列表
|
|
1085
|
-
if (!this.list.includes(key)) {
|
|
1086
|
-
this.list.push(key);
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
// 触发后置事件
|
|
1090
|
-
this.emit('decrby_after', {
|
|
1091
|
-
key,
|
|
1092
|
-
value: { decrement },
|
|
1093
|
-
result
|
|
1094
|
-
});
|
|
1095
|
-
resolve(result);
|
|
1096
|
-
} catch (error) {
|
|
1097
|
-
// 触发错误事件
|
|
1098
|
-
this.emit('decrby_error', {
|
|
1099
|
-
key,
|
|
1100
|
-
value: { decrement },
|
|
1101
|
-
error
|
|
1102
|
-
});
|
|
1103
|
-
$.log.error('[cachebase] decrby操作失败:', error);
|
|
1104
|
-
resolve(0);
|
|
707
|
+
try {
|
|
708
|
+
this.emit('decrby_before', { key, decrement });
|
|
709
|
+
|
|
710
|
+
// 获取当前值或默认为0
|
|
711
|
+
let currentValue = 0;
|
|
712
|
+
if (this.data.hasOwnProperty(key) && !this._checkExpire(key)) {
|
|
713
|
+
currentValue = parseFloat(this.data[key].value) || 0;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// 减少指定值
|
|
717
|
+
const result = currentValue - parseFloat(decrement);
|
|
718
|
+
|
|
719
|
+
// 保存结果
|
|
720
|
+
this.data[key] = { value: result, expire: 0 };
|
|
721
|
+
|
|
722
|
+
// 如果键不存在于列表中,添加到列表
|
|
723
|
+
if (!this.list.includes(key)) {
|
|
724
|
+
this.list.push(key);
|
|
1105
725
|
}
|
|
1106
|
-
|
|
726
|
+
|
|
727
|
+
this.emit('decrby_after', { key, decrement, result });
|
|
728
|
+
return result;
|
|
729
|
+
} catch (error) {
|
|
730
|
+
this.emit('decrby_error', { key, decrement, error });
|
|
731
|
+
this.log.error('[cachebase] decrby操作失败:', error);
|
|
732
|
+
throw error;
|
|
733
|
+
}
|
|
1107
734
|
}
|
|
1108
735
|
|
|
1109
|
-
|
|
736
|
+
/**
|
|
737
|
+
* 浮点数增加指定值
|
|
738
|
+
* @param {string} key - 键名
|
|
739
|
+
* @param {number} increment - 增加的值
|
|
740
|
+
* @returns {Promise<number>} - 返回增加后的值
|
|
741
|
+
*/
|
|
1110
742
|
async incrbyfloat(key, increment) {
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
// 如果键不存在于列表中,添加到列表
|
|
1140
|
-
if (!this.list.includes(key)) {
|
|
1141
|
-
this.list.push(key);
|
|
1142
|
-
}
|
|
743
|
+
try {
|
|
744
|
+
this.emit('incrbyfloat_before', { key, increment });
|
|
745
|
+
|
|
746
|
+
// 获取当前值或默认为0
|
|
747
|
+
let currentValue = 0;
|
|
748
|
+
if (this.data.hasOwnProperty(key) && !this._checkExpire(key)) {
|
|
749
|
+
currentValue = parseFloat(this.data[key].value) || 0;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// 增加指定值
|
|
753
|
+
const result = currentValue + parseFloat(increment);
|
|
754
|
+
|
|
755
|
+
// 保存结果
|
|
756
|
+
this.data[key] = { value: result, expire: 0 };
|
|
757
|
+
|
|
758
|
+
// 如果键不存在于列表中,添加到列表
|
|
759
|
+
if (!this.list.includes(key)) {
|
|
760
|
+
this.list.push(key);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
this.emit('incrbyfloat_after', { key, increment, result });
|
|
764
|
+
return result;
|
|
765
|
+
} catch (error) {
|
|
766
|
+
this.emit('incrbyfloat_error', { key, increment, error });
|
|
767
|
+
this.log.error('[cachebase] incrbyfloat操作失败:', error);
|
|
768
|
+
throw error;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
1143
771
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
772
|
+
/**
|
|
773
|
+
* 字符串追加
|
|
774
|
+
* @param {string} key - 键名
|
|
775
|
+
* @param {string} value - 追加的字符串
|
|
776
|
+
* @returns {Promise<number>} - 返回追加后的字符串长度
|
|
777
|
+
*/
|
|
778
|
+
async append(key, value) {
|
|
779
|
+
try {
|
|
780
|
+
this.emit('append_before', { key, value });
|
|
781
|
+
|
|
782
|
+
// 获取当前值或默认为空字符串
|
|
783
|
+
let currentValue = '';
|
|
784
|
+
if (this.data.hasOwnProperty(key) && !this._checkExpire(key)) {
|
|
785
|
+
currentValue = String(this.data[key].value);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// 执行字符串拼接
|
|
789
|
+
const newValue = currentValue + String(value);
|
|
790
|
+
const result = newValue.length;
|
|
791
|
+
|
|
792
|
+
// 保存结果
|
|
793
|
+
this.data[key] = { value: newValue, expire: 0 };
|
|
794
|
+
|
|
795
|
+
// 如果键不存在于列表中,添加到列表
|
|
796
|
+
if (!this.list.includes(key)) {
|
|
797
|
+
this.list.push(key);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
this.emit('append_after', { key, value, result });
|
|
801
|
+
return result;
|
|
802
|
+
} catch (error) {
|
|
803
|
+
this.emit('append_error', { key, value, error });
|
|
804
|
+
this.log.error('[cachebase] append操作失败:', error);
|
|
805
|
+
throw error;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* 获取字符串长度
|
|
811
|
+
* @param {string} key - 键名
|
|
812
|
+
* @returns {Promise<number>} - 返回字符串长度
|
|
813
|
+
*/
|
|
814
|
+
async strlen(key) {
|
|
815
|
+
try {
|
|
816
|
+
this.emit('strlen_before', { key });
|
|
817
|
+
|
|
818
|
+
// 检查键是否存在且未过期
|
|
819
|
+
if (this.data.hasOwnProperty(key) && !this._checkExpire(key)) {
|
|
820
|
+
const result = String(this.data[key].value).length;
|
|
821
|
+
this.emit('strlen_after', { key, result });
|
|
822
|
+
return result;
|
|
1160
823
|
}
|
|
1161
|
-
|
|
824
|
+
|
|
825
|
+
this.emit('strlen_after', { key, result: 0 });
|
|
826
|
+
return 0;
|
|
827
|
+
} catch (error) {
|
|
828
|
+
this.emit('strlen_error', { key, error });
|
|
829
|
+
this.log.error('[cachebase] strlen操作失败:', error);
|
|
830
|
+
throw error;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* 清空数据库
|
|
836
|
+
* @returns {Promise<string>} - 返回'OK'
|
|
837
|
+
*/
|
|
838
|
+
async flushdb() {
|
|
839
|
+
try {
|
|
840
|
+
this.emit('flushdb_before');
|
|
841
|
+
|
|
842
|
+
// 清空数据
|
|
843
|
+
this.data = {};
|
|
844
|
+
this.list = [];
|
|
845
|
+
|
|
846
|
+
this.emit('flushdb_after', { result: 'OK' });
|
|
847
|
+
return 'OK';
|
|
848
|
+
} catch (error) {
|
|
849
|
+
this.emit('flushdb_error', { error });
|
|
850
|
+
this.log.error('[cachebase] flushdb操作失败:', error);
|
|
851
|
+
throw error;
|
|
852
|
+
}
|
|
1162
853
|
}
|
|
1163
854
|
|
|
1164
855
|
// 保持兼容性的方法
|
|
1165
856
|
async has(key) {
|
|
1166
|
-
|
|
857
|
+
try {
|
|
858
|
+
const exists = await this.exists(key);
|
|
859
|
+
return exists > 0;
|
|
860
|
+
} catch (error) {
|
|
861
|
+
this.log.error('[cachebase] has操作失败:', error);
|
|
862
|
+
throw error;
|
|
863
|
+
}
|
|
1167
864
|
}
|
|
1168
865
|
|
|
1169
866
|
async clear(pattern) {
|
|
@@ -1182,36 +879,61 @@ class CacheBase extends EventEmitter {
|
|
|
1182
879
|
return this.append(key, value);
|
|
1183
880
|
}
|
|
1184
881
|
|
|
1185
|
-
|
|
882
|
+
/**
|
|
883
|
+
* 资源销毁方法
|
|
884
|
+
*/
|
|
1186
885
|
dispose() {
|
|
1187
886
|
try {
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
// 如果事件处理器设置了cancel为true,则取消操作
|
|
1193
|
-
if (beforeEventData.cancel) {
|
|
1194
|
-
return;
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
// 执行实际操作
|
|
887
|
+
this.emit('dispose_before');
|
|
888
|
+
|
|
889
|
+
// 清空数据
|
|
1198
890
|
this.data = {};
|
|
1199
891
|
this.list = [];
|
|
1200
|
-
this.dict = this.data; // 同步dict引用
|
|
1201
892
|
|
|
1202
|
-
|
|
1203
|
-
this.emit('dispose_after', {});
|
|
893
|
+
this.emit('dispose_after');
|
|
1204
894
|
|
|
1205
|
-
//
|
|
895
|
+
// 移除所有监听器
|
|
1206
896
|
this.removeAllListeners();
|
|
1207
897
|
} catch (error) {
|
|
1208
|
-
// 触发错误事件
|
|
1209
898
|
this.emit('dispose_error', { error });
|
|
1210
|
-
|
|
899
|
+
this.log.error('[cachebase] dispose操作失败:', error);
|
|
1211
900
|
}
|
|
1212
901
|
}
|
|
1213
902
|
}
|
|
1214
903
|
|
|
1215
904
|
// 导出CacheBase类
|
|
1216
|
-
|
|
905
|
+
exports.CacheBase = CacheBase;
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
/**
|
|
909
|
+
* 确保连接池对象存在
|
|
910
|
+
*/
|
|
911
|
+
if (!$.pool) {
|
|
912
|
+
$.pool = {};
|
|
913
|
+
}
|
|
914
|
+
if (!$.pool.cachebase) {
|
|
915
|
+
$.pool.cachebase = {};
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* @description cachebase管理器,用于创建缓存
|
|
920
|
+
* @param {String} scope 作用域
|
|
921
|
+
* @param {String} dir 当前路径
|
|
922
|
+
* @return {Object} 返回一个cachebase类实例
|
|
923
|
+
*/
|
|
924
|
+
function cachebase_admin(scope, dir) {
|
|
925
|
+
if (!scope) {
|
|
926
|
+
scope = 'sys';
|
|
927
|
+
}
|
|
928
|
+
var obj = $.pool.cachebase[scope];
|
|
929
|
+
if (!obj) {
|
|
930
|
+
$.pool.cachebase[scope] = new CacheBase(scope, dir);
|
|
931
|
+
obj = $.pool.cachebase[scope];
|
|
932
|
+
}
|
|
933
|
+
return obj;
|
|
934
|
+
}
|
|
1217
935
|
|
|
936
|
+
/**
|
|
937
|
+
* @module 导出cachebase管理器
|
|
938
|
+
*/
|
|
939
|
+
exports.cachebase_admin = cachebase_admin;
|