UNPKG

@lakutata-component/cacher

Version:

Lakutata Cacher Component

201 lines (186 loc) 7.44 kB
import {Accept, Application, Component, Configurable, Inject, Validator} from '@lakutata/core' import cacheManager, {Cache} from 'cache-manager' import os from 'os' import path from 'path' import {TCacheOptions} from './types/TCacheOptions' import RedisStore from 'cache-manager-ioredis' import FsStore from 'cache-manager-fs-hash' import MemcachedStore from 'cache-manager-memcached-store' export {IRedisCacheOptions} from './interfaces/IRedisCacheOptions' export {IMemcachedCacheOptions} from './interfaces/IMemcachedCacheOptions' export {IBaseCacheOptions} from './interfaces/IBaseCacheOptions' export {IMemoryCacheOptions} from './interfaces/IMemoryCacheOptions' export {IFileSystemCacheOptions} from './interfaces/IFileSystemCacheOptions' export {TCacheOptions as CacheOptions} from './types/TCacheOptions' export class CacherComponent extends Component { @Inject(Application) protected readonly app: Application @Configurable() protected readonly prefix: string @Configurable() protected readonly options?: TCacheOptions protected ttl: number = Infinity protected cache: Cache protected async initialize(): Promise<void> { if (!this.options) { //使用memory this.cache = cacheManager.caching({store: 'memory', ttl: this.ttl}) } else { const cacheOptions: TCacheOptions = this.options switch (cacheOptions.type) { case 'memory': { this.ttl = cacheOptions.ttl ? cacheOptions.ttl : this.ttl this.cache = cacheManager.caching({ store: 'memory', ttl: this.ttl }) } break case 'fs': { this.ttl = cacheOptions.ttl ? cacheOptions.ttl : this.ttl this.cache = cacheManager.caching({ store: FsStore, ttl: this.ttl, options: { path: cacheOptions.directory ? cacheOptions.directory : path.resolve(os.tmpdir(), './._LCC_CACHE_'), ttl: this.ttl, subdirs: cacheOptions.subdirectories === undefined ? false : cacheOptions.subdirectories, zip: cacheOptions.compression === undefined ? false : cacheOptions.compression } }) } break case 'memcached': { this.ttl = cacheOptions.ttl ? cacheOptions.ttl : this.ttl const Memcache = require('memcache-plus') this.cache = cacheManager.caching({ store: MemcachedStore, driver: Memcache, options: { hosts: Array.isArray(cacheOptions.hosts) ? cacheOptions.hosts : [cacheOptions.hosts], autodiscover: cacheOptions.autodiscover === undefined ? false : cacheOptions.autodiscover, backoffLimit: cacheOptions.backoffLimit === undefined ? 10000 : cacheOptions.backoffLimit, bufferBeforeError: cacheOptions.bufferBeforeError === undefined ? 1000 : cacheOptions.bufferBeforeError, disabled: cacheOptions.disabled === undefined ? false : cacheOptions.disabled, maxValueSize: cacheOptions.maxValueSize === undefined ? 1048576 : cacheOptions.maxValueSize, queue: cacheOptions.queue === undefined ? true : cacheOptions.queue, netTimeout: cacheOptions.netTimeout === undefined ? 500 : cacheOptions.netTimeout, reconnect: cacheOptions.reconnect === undefined ? true : cacheOptions.reconnect, onNetError: cacheOptions.onNetError === undefined ? (err) => { //do nothing } : cacheOptions.onNetError }, ttl: this.ttl }) } break case 'redis': { this.ttl = cacheOptions.ttl ? cacheOptions.ttl : this.ttl this.cache = cacheManager.caching({ store: RedisStore, host: cacheOptions.host, port: cacheOptions.port, password: cacheOptions.password, db: cacheOptions.db, ttl: this.ttl }) } break default: { this.cache = cacheManager.caching({ store: 'memory', ttl: this.ttl }) } } } } /** * 生成缓存键名 * @param key * @protected */ protected generateCacheKey(key: string): string { if (this.prefix) { return `${this.app.getID()}_${this.prefix.toString()}_${key}` } else { return `${this.app.getID()}_${key}` } } /** * 设置缓存 * @param key * @param value */ @Accept([Validator.String, Validator.Any], {strict: true}) public async set(key: string, value: any): Promise<boolean> { return new Promise(resolve => { this.cache.set(this.generateCacheKey(key), value, {ttl: this.ttl}, error => { if (error) { resolve(false) } else { resolve(true) } }) }) } /** * 读取缓存 * @param key */ @Accept(Validator.String, {strict: true}) public async get<T = any>(key: string): Promise<T | null> { return new Promise<T | null>(resolve => { this.cache.get(this.generateCacheKey(key), (error, result) => { if (error) { resolve(null) } else { if (result === undefined) { resolve(null) } else { resolve(result as T) } } }) }) } /** * 读取缓存(若缓存不存在则设置缓存) * @param key * @param value */ public async getOrSet<T = any>(key: string, value: T): Promise<T> { let cachedValue: T | null = await this.get(key) if (cachedValue === null) { await this.set(key, value) cachedValue = value } return cachedValue } /** * 删除缓存 * @param key */ @Accept(Validator.String, {strict: true}) public async del(key: string): Promise<boolean> { return new Promise(resolve => { this.cache.del(this.generateCacheKey(key), error => { if (error) { resolve(false) } else { resolve(true) } }) }) } /** * 重置 */ public async reset(): Promise<void> { return new Promise<void>(resolve => { this.cache.reset(() => { resolve() }) }) } }