@lakutata-component/cacher
Version:
Lakutata Cacher Component
201 lines (186 loc) • 7.44 kB
text/typescript
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 {
protected readonly app: Application
protected readonly prefix: string
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
*/
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
*/
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
*/
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()
})
})
}
}