mm_cachebase 1.4.4 → 1.4.6
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 +699 -15
- package/index.js +2129 -511
- package/package.json +2 -2
- package/test.js +16 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# mm_cachebase
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
一个轻量级的本地缓存类库,提供了丰富的缓存操作接口,支持过期时间设置、数组操作、哈希表、集合、有序集合等功能,以及完整的事件通知系统。
|
|
4
4
|
|
|
5
5
|
## 安装
|
|
6
6
|
|
|
@@ -126,21 +126,90 @@ await cache.setrange(key, index, value)
|
|
|
126
126
|
```
|
|
127
127
|
- 从指定位置替换字符串
|
|
128
128
|
|
|
129
|
-
###
|
|
129
|
+
### 哈希表操作
|
|
130
130
|
|
|
131
|
-
####
|
|
131
|
+
#### 设置哈希表字段
|
|
132
|
+
```javascript
|
|
133
|
+
await cache.hset(key, field, value)
|
|
134
|
+
```
|
|
135
|
+
- `key`: 哈希表的键名
|
|
136
|
+
- `field`: 字段名
|
|
137
|
+
- `value`: 字段值
|
|
138
|
+
- 返回: 成功返回1,失败返回0
|
|
139
|
+
|
|
140
|
+
#### 获取哈希表字段
|
|
141
|
+
```javascript
|
|
142
|
+
await cache.hget(key, field)
|
|
143
|
+
```
|
|
144
|
+
- 返回: 字段值,不存在则返回null
|
|
145
|
+
|
|
146
|
+
#### 删除哈希表字段
|
|
147
|
+
```javascript
|
|
148
|
+
await cache.hdel(key, field)
|
|
149
|
+
```
|
|
150
|
+
- 返回: 成功返回1,失败返回0
|
|
151
|
+
|
|
152
|
+
#### 获取哈希表所有键名
|
|
153
|
+
```javascript
|
|
154
|
+
await cache.hkeys(key)
|
|
155
|
+
```
|
|
156
|
+
- 返回: 键名数组
|
|
157
|
+
|
|
158
|
+
#### 获取哈希表所有值
|
|
159
|
+
```javascript
|
|
160
|
+
await cache.hvals(key)
|
|
161
|
+
```
|
|
162
|
+
- 返回: 值数组
|
|
163
|
+
|
|
164
|
+
### 列表操作
|
|
165
|
+
|
|
166
|
+
#### 设置列表
|
|
132
167
|
```javascript
|
|
133
168
|
await cache.list_set(key, value, maxAge)
|
|
134
169
|
```
|
|
135
170
|
- 设置一个数组类型的缓存
|
|
136
171
|
|
|
137
|
-
####
|
|
172
|
+
#### 添加列表元素
|
|
138
173
|
```javascript
|
|
139
174
|
await cache.list_add(key, value)
|
|
140
175
|
```
|
|
141
176
|
- 向数组末尾添加元素
|
|
142
177
|
- 返回: 成功返回1,失败返回-1
|
|
143
178
|
|
|
179
|
+
#### 从左侧推入元素
|
|
180
|
+
```javascript
|
|
181
|
+
await cache.lpush(key, ...values)
|
|
182
|
+
```
|
|
183
|
+
- 从列表左侧添加一个或多个元素
|
|
184
|
+
- 返回: 操作后的列表长度
|
|
185
|
+
|
|
186
|
+
#### 从左侧弹出元素
|
|
187
|
+
```javascript
|
|
188
|
+
await cache.lpop(key)
|
|
189
|
+
```
|
|
190
|
+
- 从列表左侧移除并返回一个元素
|
|
191
|
+
- 返回: 弹出的元素,列表为空返回null
|
|
192
|
+
|
|
193
|
+
#### 从右侧推入元素
|
|
194
|
+
```javascript
|
|
195
|
+
await cache.rpush(key, ...values)
|
|
196
|
+
```
|
|
197
|
+
- 从列表右侧添加一个或多个元素
|
|
198
|
+
- 返回: 操作后的列表长度
|
|
199
|
+
|
|
200
|
+
#### 从右侧弹出元素
|
|
201
|
+
```javascript
|
|
202
|
+
await cache.rpop(key)
|
|
203
|
+
```
|
|
204
|
+
- 从列表右侧移除并返回一个元素
|
|
205
|
+
- 返回: 弹出的元素,列表为空返回null
|
|
206
|
+
|
|
207
|
+
#### 获取列表长度
|
|
208
|
+
```javascript
|
|
209
|
+
await cache.llen(key)
|
|
210
|
+
```
|
|
211
|
+
- 返回: 列表长度,键不存在返回0
|
|
212
|
+
|
|
144
213
|
#### 判断数组元素是否存在
|
|
145
214
|
```javascript
|
|
146
215
|
await cache.list_has(key, value)
|
|
@@ -159,6 +228,70 @@ await cache.list_clear(key, value)
|
|
|
159
228
|
```
|
|
160
229
|
- 清空数组或用新数组替换
|
|
161
230
|
|
|
231
|
+
### 集合操作
|
|
232
|
+
|
|
233
|
+
#### 添加集合成员
|
|
234
|
+
```javascript
|
|
235
|
+
await cache.sadd(key, member)
|
|
236
|
+
```
|
|
237
|
+
- 向集合添加一个成员
|
|
238
|
+
- 返回: 成功返回1,成员已存在返回0
|
|
239
|
+
|
|
240
|
+
#### 删除集合成员
|
|
241
|
+
```javascript
|
|
242
|
+
await cache.srem(key, member)
|
|
243
|
+
```
|
|
244
|
+
- 从集合移除一个成员
|
|
245
|
+
- 返回: 成功返回1,成员不存在返回0
|
|
246
|
+
|
|
247
|
+
#### 获取集合所有成员
|
|
248
|
+
```javascript
|
|
249
|
+
await cache.smembers(key)
|
|
250
|
+
```
|
|
251
|
+
- 返回: 成员数组,键不存在返回空数组
|
|
252
|
+
|
|
253
|
+
#### 判断成员是否存在
|
|
254
|
+
```javascript
|
|
255
|
+
await cache.sismember(key, member)
|
|
256
|
+
```
|
|
257
|
+
- 返回: 存在返回1,不存在返回0
|
|
258
|
+
|
|
259
|
+
#### 获取集合大小
|
|
260
|
+
```javascript
|
|
261
|
+
await cache.scard(key)
|
|
262
|
+
```
|
|
263
|
+
- 返回: 集合大小,键不存在返回0
|
|
264
|
+
|
|
265
|
+
### 有序集合操作
|
|
266
|
+
|
|
267
|
+
#### 添加有序集合成员
|
|
268
|
+
```javascript
|
|
269
|
+
await cache.zadd(key, score, member)
|
|
270
|
+
```
|
|
271
|
+
- 向有序集合添加一个成员
|
|
272
|
+
- 返回: 成功返回1,成员已存在返回0
|
|
273
|
+
|
|
274
|
+
#### 获取有序集合范围
|
|
275
|
+
```javascript
|
|
276
|
+
await cache.zrange(key, start, stop, withScores)
|
|
277
|
+
```
|
|
278
|
+
- `start`/`stop`: 范围索引
|
|
279
|
+
- `withScores`: 是否返回分数
|
|
280
|
+
- 返回: 成员数组或[成员, 分数]数组
|
|
281
|
+
|
|
282
|
+
#### 删除有序集合成员
|
|
283
|
+
```javascript
|
|
284
|
+
await cache.zrem(key, member)
|
|
285
|
+
```
|
|
286
|
+
- 从有序集合移除一个成员
|
|
287
|
+
- 返回: 成功返回1,成员不存在返回0
|
|
288
|
+
|
|
289
|
+
#### 获取成员分数
|
|
290
|
+
```javascript
|
|
291
|
+
await cache.zscore(key, member)
|
|
292
|
+
```
|
|
293
|
+
- 返回: 成员分数,成员不存在返回null
|
|
294
|
+
|
|
162
295
|
### 其他操作
|
|
163
296
|
|
|
164
297
|
#### 排序
|
|
@@ -182,6 +315,12 @@ await cache.clear(pattern)
|
|
|
182
315
|
- `pattern`: 可选,支持*通配符,清空匹配的键
|
|
183
316
|
- 不传则清空所有缓存
|
|
184
317
|
|
|
318
|
+
#### 销毁缓存实例
|
|
319
|
+
```javascript
|
|
320
|
+
await cache.dispose()
|
|
321
|
+
```
|
|
322
|
+
- 清理所有资源,移除所有监听器
|
|
323
|
+
|
|
185
324
|
## 使用示例
|
|
186
325
|
|
|
187
326
|
### 基本缓存操作
|
|
@@ -205,21 +344,119 @@ async function example() {
|
|
|
205
344
|
}
|
|
206
345
|
```
|
|
207
346
|
|
|
208
|
-
###
|
|
347
|
+
### 哈希表操作示例
|
|
209
348
|
```javascript
|
|
210
|
-
async function
|
|
211
|
-
//
|
|
212
|
-
await cache.
|
|
349
|
+
async function hashExample() {
|
|
350
|
+
// 设置哈希表字段
|
|
351
|
+
await cache.hset("user:123", "name", "张三");
|
|
352
|
+
await cache.hset("user:123", "age", 30);
|
|
353
|
+
await cache.hset("user:123", "email", "zhangsan@example.com");
|
|
213
354
|
|
|
214
|
-
//
|
|
215
|
-
await cache.
|
|
355
|
+
// 获取哈希表字段
|
|
356
|
+
const name = await cache.hget("user:123", "name");
|
|
357
|
+
console.log(name); // 输出: 张三
|
|
216
358
|
|
|
217
|
-
//
|
|
218
|
-
const
|
|
219
|
-
console.log(
|
|
359
|
+
// 获取所有键名
|
|
360
|
+
const keys = await cache.hkeys("user:123");
|
|
361
|
+
console.log(keys); // 输出: ["name", "age", "email"]
|
|
362
|
+
|
|
363
|
+
// 获取所有值
|
|
364
|
+
const values = await cache.hvals("user:123");
|
|
365
|
+
console.log(values); // 输出: ["张三", 30, "zhangsan@example.com"]
|
|
366
|
+
|
|
367
|
+
// 删除字段
|
|
368
|
+
await cache.hdel("user:123", "email");
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### 列表操作示例
|
|
373
|
+
```javascript
|
|
374
|
+
async function listExample() {
|
|
375
|
+
// 设置列表
|
|
376
|
+
await cache.list_set("tasks", ["任务1", "任务2"], 300);
|
|
377
|
+
|
|
378
|
+
// 添加元素到末尾
|
|
379
|
+
await cache.list_add("tasks", "任务3");
|
|
380
|
+
|
|
381
|
+
// 从左侧推入元素
|
|
382
|
+
await cache.lpush("tasks", "任务0");
|
|
383
|
+
|
|
384
|
+
// 从右侧推入元素
|
|
385
|
+
await cache.rpush("tasks", "任务4");
|
|
386
|
+
|
|
387
|
+
// 从左侧弹出元素
|
|
388
|
+
const task0 = await cache.lpop("tasks");
|
|
389
|
+
console.log("弹出任务:", task0); // 输出: 任务0
|
|
390
|
+
|
|
391
|
+
// 从右侧弹出元素
|
|
392
|
+
const task4 = await cache.rpop("tasks");
|
|
393
|
+
console.log("弹出任务:", task4); // 输出: 任务4
|
|
394
|
+
|
|
395
|
+
// 获取列表长度
|
|
396
|
+
const length = await cache.llen("tasks");
|
|
397
|
+
console.log("任务数量:", length); // 输出: 3
|
|
398
|
+
|
|
399
|
+
// 获取列表
|
|
400
|
+
const tasks = await cache.list_get("tasks");
|
|
401
|
+
console.log("任务列表:", tasks); // 输出: ["任务1", "任务2", "任务3"]
|
|
220
402
|
|
|
221
403
|
// 排序
|
|
222
|
-
await cache.sort("
|
|
404
|
+
await cache.sort("tasks", "asc");
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### 集合操作示例
|
|
409
|
+
```javascript
|
|
410
|
+
async function setExample() {
|
|
411
|
+
// 添加集合成员
|
|
412
|
+
await cache.sadd("users", "张三");
|
|
413
|
+
await cache.sadd("users", "李四");
|
|
414
|
+
await cache.sadd("users", "王五");
|
|
415
|
+
|
|
416
|
+
// 尝试添加重复成员
|
|
417
|
+
const result = await cache.sadd("users", "张三");
|
|
418
|
+
console.log("添加重复成员结果:", result); // 输出: 0
|
|
419
|
+
|
|
420
|
+
// 判断成员是否存在
|
|
421
|
+
const exists = await cache.sismember("users", "张三");
|
|
422
|
+
console.log("张三是否在用户集合中:", exists); // 输出: 1
|
|
423
|
+
|
|
424
|
+
// 获取集合所有成员
|
|
425
|
+
const members = await cache.smembers("users");
|
|
426
|
+
console.log("用户集合:", members); // 输出: ["张三", "李四", "王五"]
|
|
427
|
+
|
|
428
|
+
// 获取集合大小
|
|
429
|
+
const size = await cache.scard("users");
|
|
430
|
+
console.log("集合大小:", size); // 输出: 3
|
|
431
|
+
|
|
432
|
+
// 删除成员
|
|
433
|
+
await cache.srem("users", "李四");
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### 有序集合操作示例
|
|
438
|
+
```javascript
|
|
439
|
+
async function sortedSetExample() {
|
|
440
|
+
// 添加有序集合成员
|
|
441
|
+
await cache.zadd("scores", 95, "张三");
|
|
442
|
+
await cache.zadd("scores", 88, "李四");
|
|
443
|
+
await cache.zadd("scores", 92, "王五");
|
|
444
|
+
|
|
445
|
+
// 获取有序集合范围(升序)
|
|
446
|
+
const ascendingScores = await cache.zrange("scores", 0, -1, true);
|
|
447
|
+
console.log("分数排序(升序):", ascendingScores);
|
|
448
|
+
// 输出: ["李四", 88, "王五", 92, "张三", 95]
|
|
449
|
+
|
|
450
|
+
// 获取指定成员分数
|
|
451
|
+
const zhangScore = await cache.zscore("scores", "张三");
|
|
452
|
+
console.log("张三的分数:", zhangScore); // 输出: 95
|
|
453
|
+
|
|
454
|
+
// 删除成员
|
|
455
|
+
await cache.zrem("scores", "李四");
|
|
456
|
+
|
|
457
|
+
// 再次获取有序集合
|
|
458
|
+
const remainingScores = await cache.zrange("scores", 0, -1);
|
|
459
|
+
console.log("剩余成员:", remainingScores); // 输出: ["王五", "张三"]
|
|
223
460
|
}
|
|
224
461
|
```
|
|
225
462
|
|
|
@@ -253,6 +490,449 @@ async function batchExample() {
|
|
|
253
490
|
// 清空所有缓存
|
|
254
491
|
await cache.clear();
|
|
255
492
|
}
|
|
493
|
+
|
|
494
|
+
### 事件系统使用示例
|
|
495
|
+
```javascript
|
|
496
|
+
async function eventExample() {
|
|
497
|
+
// 设置操作的前置事件
|
|
498
|
+
cache.on('set_before', (data) => {
|
|
499
|
+
console.log(`即将设置键: ${data.key}`);
|
|
500
|
+
|
|
501
|
+
// 示例:进行数据验证
|
|
502
|
+
if (typeof data.value === 'string' && data.value.length > 100) {
|
|
503
|
+
console.log('值长度过长,取消设置');
|
|
504
|
+
data.cancel = true; // 取消操作
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
// 获取操作的后置事件
|
|
509
|
+
cache.on('get_after', (data) => {
|
|
510
|
+
console.log(`获取键 ${data.key} 的结果: ${data.result}`);
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// 尝试设置缓存
|
|
514
|
+
await cache.set("test", "这是一个测试值");
|
|
515
|
+
|
|
516
|
+
// 获取缓存
|
|
517
|
+
const value = await cache.get("test");
|
|
518
|
+
|
|
519
|
+
// 错误事件监听
|
|
520
|
+
cache.on('get_error', (data) => {
|
|
521
|
+
console.error(`获取键 ${data.key} 时出错: ${data.error.message}`);
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
## 事件系统
|
|
527
|
+
|
|
528
|
+
CacheBase 提供了完整的事件系统,允许你监听各种缓存操作的前后事件,以便进行日志记录、数据验证或操作取消等功能。
|
|
529
|
+
|
|
530
|
+
### 事件监听方法
|
|
531
|
+
|
|
532
|
+
```javascript
|
|
533
|
+
// 监听事件
|
|
534
|
+
cache.on('event_name', callback);
|
|
535
|
+
|
|
536
|
+
// 监听一次性事件
|
|
537
|
+
cache.once('event_name', callback);
|
|
538
|
+
|
|
539
|
+
// 移除事件监听
|
|
540
|
+
cache.off('event_name', callback);
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### 事件参数格式
|
|
544
|
+
|
|
545
|
+
所有事件的回调函数都会接收一个标准化的事件数据对象,包含以下属性:
|
|
546
|
+
|
|
547
|
+
- `key`: 操作的缓存键名(如果适用)
|
|
548
|
+
- `value`: 操作的值,可以是基本类型或包含多个属性的对象
|
|
549
|
+
- `result`: 操作的结果
|
|
550
|
+
- `error`: 错误信息(仅错误事件)
|
|
551
|
+
- `cancel`: 用于取消操作的标志(仅前置事件)
|
|
552
|
+
- `ttl`: 过期时间(秒)(仅过期时间相关操作)
|
|
553
|
+
|
|
554
|
+
### 支持的事件类型
|
|
555
|
+
|
|
556
|
+
每个缓存操作都有对应的前置事件(`_before`)、后置事件(`_after`)和错误事件(`_error`)。以下是主要支持的事件类型:
|
|
557
|
+
|
|
558
|
+
#### 基本操作事件
|
|
559
|
+
- `set_before`, `set_after`, `set_error`
|
|
560
|
+
- `get_before`, `get_after`, `get_error`
|
|
561
|
+
- `del_before`, `del_after`, `del_error`
|
|
562
|
+
- `exists_before`, `exists_after`, `exists_error`
|
|
563
|
+
- `dispose_before`, `dispose_after`, `dispose_error`
|
|
564
|
+
|
|
565
|
+
#### 哈希表操作事件
|
|
566
|
+
- `hset_before`, `hset_after`, `hset_error`
|
|
567
|
+
- `hget_before`, `hget_after`, `hget_error`
|
|
568
|
+
- `hdel_before`, `hdel_after`, `hdel_error`
|
|
569
|
+
- `hkeys_before`, `hkeys_after`, `hkeys_error`
|
|
570
|
+
- `hvals_before`, `hvals_after`, `hvals_error`
|
|
571
|
+
|
|
572
|
+
#### 列表操作事件
|
|
573
|
+
- `lpush_before`, `lpush_after`, `lpush_error`
|
|
574
|
+
- `lpop_before`, `lpop_after`, `lpop_error`
|
|
575
|
+
- `rpush_before`, `rpush_after`, `rpush_error`
|
|
576
|
+
- `rpop_before`, `rpop_after`, `rpop_error`
|
|
577
|
+
- `llen_before`, `llen_after`, `llen_error`
|
|
578
|
+
- `list_set_before`, `list_set_after`, `list_set_error`
|
|
579
|
+
- `list_add_before`, `list_add_after`, `list_add_error`
|
|
580
|
+
- `list_clear_before`, `list_clear_after`, `list_clear_error`
|
|
581
|
+
|
|
582
|
+
#### 集合操作事件
|
|
583
|
+
- `sadd_before`, `sadd_after`, `sadd_error`
|
|
584
|
+
- `srem_before`, `srem_after`, `srem_error`
|
|
585
|
+
- `smembers_before`, `smembers_after`, `smembers_error`
|
|
586
|
+
- `sismember_before`, `sismember_after`, `sismember_error`
|
|
587
|
+
- `scard_before`, `scard_after`, `scard_error`
|
|
588
|
+
|
|
589
|
+
#### 有序集合操作事件
|
|
590
|
+
- `zadd_before`, `zadd_after`, `zadd_error`
|
|
591
|
+
- `zrange_before`, `zrange_after`, `zrange_error`
|
|
592
|
+
- `zrem_before`, `zrem_after`, `zrem_error`
|
|
593
|
+
- `zscore_before`, `zscore_after`, `zscore_error`
|
|
594
|
+
|
|
595
|
+
#### 其他操作事件
|
|
596
|
+
- `mset_before`, `mset_after`, `mset_error`
|
|
597
|
+
- `setex_before`, `setex_after`, `setex_error`
|
|
598
|
+
- `setnx_before`, `setnx_after`, `setnx_error`
|
|
599
|
+
- `add_before`, `add_after`, `add_error`
|
|
600
|
+
- `addFloat_before`, `addFloat_after`, `addFloat_error`
|
|
601
|
+
- `addStr_before`, `addStr_after`, `addStr_error`
|
|
602
|
+
- `setrange_before`, `setrange_after`, `setrange_error`
|
|
603
|
+
|
|
604
|
+
### 取消操作示例
|
|
605
|
+
|
|
606
|
+
在前置事件中,你可以通过设置 `cancel` 标志为 `true` 来取消操作:
|
|
607
|
+
|
|
608
|
+
```javascript
|
|
609
|
+
// 监听设置操作的前置事件
|
|
610
|
+
cache.on('set_before', (data) => {
|
|
611
|
+
console.log('即将设置键:', data.key, '值:', data.value);
|
|
612
|
+
|
|
613
|
+
// 检查值是否合法
|
|
614
|
+
if (typeof data.value !== 'string' || data.value.length > 100) {
|
|
615
|
+
console.log('值不合法,取消设置操作');
|
|
616
|
+
data.cancel = true; // 取消操作
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
// 监听获取操作的前置事件 - 实现访问控制
|
|
621
|
+
cache.on('get_before', (data) => {
|
|
622
|
+
console.log('尝试获取键:', data.key);
|
|
623
|
+
|
|
624
|
+
// 实现简单的访问控制
|
|
625
|
+
const restrictedKeys = ['admin_data', 'sensitive_info'];
|
|
626
|
+
if (restrictedKeys.includes(data.key) && !userHasPermission()) {
|
|
627
|
+
console.log('无权限访问此键,取消获取操作');
|
|
628
|
+
data.cancel = true; // 取消操作
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
// 监听集合删除操作的前置事件
|
|
633
|
+
cache.on('srem_before', (data) => {
|
|
634
|
+
console.log('尝试从集合', data.key, '中删除成员:', data.value.member);
|
|
635
|
+
|
|
636
|
+
// 防止删除特定成员
|
|
637
|
+
if (data.value.member === 'protected_member') {
|
|
638
|
+
console.log('保护成员不能删除,取消操作');
|
|
639
|
+
data.cancel = true;
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
// 监听删除键操作的前置事件
|
|
644
|
+
cache.on('del_before', (data) => {
|
|
645
|
+
console.log('尝试删除键:', data.key);
|
|
646
|
+
|
|
647
|
+
// 防止删除系统键
|
|
648
|
+
if (data.key.startsWith('system:')) {
|
|
649
|
+
console.log('系统键不能删除,取消操作');
|
|
650
|
+
data.cancel = true;
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
### 完整事件系统示例
|
|
656
|
+
|
|
657
|
+
以下是一个完整的示例,展示如何使用事件系统进行缓存操作的全面监控、日志记录和访问控制:
|
|
658
|
+
|
|
659
|
+
```javascript
|
|
660
|
+
const CacheBase = require('./index.js');
|
|
661
|
+
|
|
662
|
+
async function eventSystemExample() {
|
|
663
|
+
const cache = new CacheBase();
|
|
664
|
+
|
|
665
|
+
// 1. 实现统一的操作日志记录
|
|
666
|
+
const operations = ['get', 'set', 'del', 'exists', 'hget', 'hset',
|
|
667
|
+
'lpush', 'lpop', 'rpush', 'rpop', 'sadd', 'srem',
|
|
668
|
+
'smembers', 'zadd', 'zrange'];
|
|
669
|
+
|
|
670
|
+
// 为所有操作添加日志记录
|
|
671
|
+
operations.forEach(op => {
|
|
672
|
+
// 记录操作开始
|
|
673
|
+
cache.on(`${op}_before`, (data) => {
|
|
674
|
+
console.log(`[CACHE] 开始 ${op} 操作`, {
|
|
675
|
+
key: data.key,
|
|
676
|
+
value: data.value,
|
|
677
|
+
timestamp: new Date().toISOString()
|
|
678
|
+
});
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
// 记录操作成功完成
|
|
682
|
+
cache.on(`${op}_after`, (data) => {
|
|
683
|
+
console.log(`[CACHE] ${op} 操作成功`, {
|
|
684
|
+
key: data.key,
|
|
685
|
+
result: data.result,
|
|
686
|
+
timestamp: new Date().toISOString()
|
|
687
|
+
});
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
// 记录操作失败
|
|
691
|
+
cache.on(`${op}_error`, (data) => {
|
|
692
|
+
console.error(`[CACHE] ${op} 操作失败`, {
|
|
693
|
+
key: data.key,
|
|
694
|
+
error: data.error.message,
|
|
695
|
+
timestamp: new Date().toISOString()
|
|
696
|
+
});
|
|
697
|
+
});
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
// 2. 实现缓存操作统计
|
|
701
|
+
const stats = {
|
|
702
|
+
totalOperations: 0,
|
|
703
|
+
successfulOperations: 0,
|
|
704
|
+
failedOperations: 0,
|
|
705
|
+
canceledOperations: 0,
|
|
706
|
+
operationTypes: {}
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
// 更新统计信息
|
|
710
|
+
operations.forEach(op => {
|
|
711
|
+
cache.on(`${op}_before`, () => {
|
|
712
|
+
stats.totalOperations++;
|
|
713
|
+
stats.operationTypes[op] = (stats.operationTypes[op] || 0) + 1;
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
cache.on(`${op}_after`, (data) => {
|
|
717
|
+
if (op === 'get' && data.result === null) {
|
|
718
|
+
// 可以特殊处理缓存未命中的情况
|
|
719
|
+
console.log(`[CACHE] 缓存未命中: ${data.key}`);
|
|
720
|
+
}
|
|
721
|
+
stats.successfulOperations++;
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
cache.on(`${op}_error`, () => {
|
|
725
|
+
stats.failedOperations++;
|
|
726
|
+
});
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
// 3. 实现复杂的访问控制
|
|
730
|
+
const accessControl = {
|
|
731
|
+
// 定义哪些用户角色可以访问哪些键模式
|
|
732
|
+
permissions: {
|
|
733
|
+
'admin': ['*'],
|
|
734
|
+
'user': ['user:*', 'public:*'],
|
|
735
|
+
'guest': ['public:*']
|
|
736
|
+
},
|
|
737
|
+
|
|
738
|
+
// 当前用户角色
|
|
739
|
+
currentRole: 'user'
|
|
740
|
+
};
|
|
741
|
+
|
|
742
|
+
// 为敏感操作添加访问控制
|
|
743
|
+
['get', 'del', 'hget', 'hdel'].forEach(op => {
|
|
744
|
+
cache.on(`${op}_before`, (data) => {
|
|
745
|
+
const hasPermission = accessControl.permissions[accessControl.currentRole].some(pattern => {
|
|
746
|
+
// 简单的通配符匹配实现
|
|
747
|
+
if (pattern === '*') return true;
|
|
748
|
+
const regexPattern = pattern.replace(/\*/g, '.*');
|
|
749
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
750
|
+
return regex.test(data.key);
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
if (!hasPermission) {
|
|
754
|
+
console.warn(`[SECURITY] 拒绝访问: 用户 ${accessControl.currentRole} 尝试访问键 ${data.key}`);
|
|
755
|
+
data.cancel = true;
|
|
756
|
+
stats.canceledOperations++;
|
|
757
|
+
}
|
|
758
|
+
});
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
// 4. 执行一些测试操作
|
|
762
|
+
console.log('执行测试操作...');
|
|
763
|
+
|
|
764
|
+
// 应该成功的操作
|
|
765
|
+
await cache.set('user:123:name', '张三');
|
|
766
|
+
await cache.hset('user:123:profile', 'email', 'zhangsan@example.com');
|
|
767
|
+
await cache.sadd('user:123:tags', 'vip');
|
|
768
|
+
|
|
769
|
+
// 尝试访问无权限的键
|
|
770
|
+
const restrictedData = await cache.get('admin:settings');
|
|
771
|
+
console.log('受限访问结果:', restrictedData); // 应该是 null
|
|
772
|
+
|
|
773
|
+
// 正常访问有权限的键
|
|
774
|
+
const userName = await cache.get('user:123:name');
|
|
775
|
+
console.log('用户名:', userName);
|
|
776
|
+
|
|
777
|
+
// 5. 显示操作统计
|
|
778
|
+
console.log('\n操作统计:');
|
|
779
|
+
console.log(stats);
|
|
780
|
+
|
|
781
|
+
// 6. 清理资源
|
|
782
|
+
await cache.dispose();
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// 运行示例
|
|
786
|
+
eventSystemExample().catch(console.error);
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
### 事件参数格式示例
|
|
790
|
+
|
|
791
|
+
#### 基本操作事件数据
|
|
792
|
+
```javascript
|
|
793
|
+
// set_before 事件数据
|
|
794
|
+
{
|
|
795
|
+
key: 'test_key',
|
|
796
|
+
value: 'test_value',
|
|
797
|
+
cancel: false
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// set_after 事件数据
|
|
801
|
+
{
|
|
802
|
+
key: 'test_key',
|
|
803
|
+
value: 'test_value',
|
|
804
|
+
result: 1
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
// get_before 事件数据
|
|
808
|
+
{
|
|
809
|
+
key: 'test_key',
|
|
810
|
+
cancel: false
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// get_after 事件数据
|
|
814
|
+
{
|
|
815
|
+
key: 'test_key',
|
|
816
|
+
result: 'test_value'
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// exists_before 事件数据
|
|
820
|
+
{
|
|
821
|
+
key: 'test_key',
|
|
822
|
+
cancel: false
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// exists_after 事件数据
|
|
826
|
+
{
|
|
827
|
+
key: 'test_key',
|
|
828
|
+
result: 1 // 1表示存在,0表示不存在
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// dispose_before 事件数据
|
|
832
|
+
{
|
|
833
|
+
cancel: false
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// dispose_after 事件无参数
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
#### 复合操作事件数据
|
|
840
|
+
```javascript
|
|
841
|
+
// hset_before 事件数据
|
|
842
|
+
{
|
|
843
|
+
key: 'hash_key',
|
|
844
|
+
value: { field: 'field1', value: 'value1' },
|
|
845
|
+
cancel: false
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// hget_before 事件数据
|
|
849
|
+
{
|
|
850
|
+
key: 'hash_key',
|
|
851
|
+
value: { field: 'field1' },
|
|
852
|
+
cancel: false
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// lpush_before 事件数据
|
|
856
|
+
{
|
|
857
|
+
key: 'list_key',
|
|
858
|
+
value: { values: ['item1', 'item2'] },
|
|
859
|
+
cancel: false
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
// lpop_before/lpop_after 事件数据
|
|
863
|
+
{
|
|
864
|
+
key: 'list_key',
|
|
865
|
+
cancel: false // lpop_after 中包含 result
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// rpop_before/rpop_after 事件数据
|
|
869
|
+
{
|
|
870
|
+
key: 'list_key',
|
|
871
|
+
cancel: false // rpop_after 中包含 result
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// llen_before/llen_after 事件数据
|
|
875
|
+
{
|
|
876
|
+
key: 'list_key',
|
|
877
|
+
cancel: false // llen_after 中包含 result
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// srem_before 事件数据
|
|
881
|
+
{
|
|
882
|
+
key: 'set_key',
|
|
883
|
+
value: { member: 'member1' },
|
|
884
|
+
cancel: false
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// smembers_before/smembers_after 事件数据
|
|
888
|
+
{
|
|
889
|
+
key: 'set_key',
|
|
890
|
+
cancel: false // smembers_after 中包含 result 数组
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
// sismember_before 事件数据
|
|
894
|
+
{
|
|
895
|
+
key: 'set_key',
|
|
896
|
+
value: { member: 'member1' },
|
|
897
|
+
cancel: false
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// scard_before/scard_after 事件数据
|
|
901
|
+
{
|
|
902
|
+
key: 'set_key',
|
|
903
|
+
cancel: false // scard_after 中包含 result
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// zrange_before 事件数据
|
|
907
|
+
{
|
|
908
|
+
key: 'zset_key',
|
|
909
|
+
value: { start: 0, stop: -1, withScores: false },
|
|
910
|
+
cancel: false
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// zrem_before 事件数据
|
|
914
|
+
{
|
|
915
|
+
key: 'zset_key',
|
|
916
|
+
value: { member: 'zmember1' },
|
|
917
|
+
cancel: false
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// zscore_before 事件数据
|
|
921
|
+
{
|
|
922
|
+
key: 'zset_key',
|
|
923
|
+
value: { member: 'zmember1' },
|
|
924
|
+
cancel: false
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
#### 过期时间操作事件数据
|
|
928
|
+
```javascript
|
|
929
|
+
// setex_before 事件数据
|
|
930
|
+
{
|
|
931
|
+
key: 'setex_key',
|
|
932
|
+
value: 'setex_value',
|
|
933
|
+
ttl: 60,
|
|
934
|
+
cancel: false
|
|
935
|
+
}
|
|
256
936
|
```
|
|
257
937
|
|
|
258
938
|
## 注意事项
|
|
@@ -261,4 +941,8 @@ async function batchExample() {
|
|
|
261
941
|
2. 过期时间单位为秒,-1表示永不过期
|
|
262
942
|
3. 数组操作方法只能用于数组类型的缓存值
|
|
263
943
|
4. 键名支持*通配符匹配,可用于批量操作
|
|
264
|
-
5. 缓存数据存储在内存中,重启后数据会丢失
|
|
944
|
+
5. 缓存数据存储在内存中,重启后数据会丢失
|
|
945
|
+
6. 事件回调函数中的 `cancel` 标志只在前置事件中有效,后置事件中修改不会产生效果
|
|
946
|
+
7. 当List、Set或Sorted Set类型的缓存变为空时,对应的键会被自动删除
|
|
947
|
+
8. 所有事件参数都遵循统一的格式,包含key、value、result、error和cancel等字段
|
|
948
|
+
9. 错误日志都添加了`[cachebase]`前缀,便于日志识别和过滤
|