diff --git a/deps.ts b/deps.ts index 91097fc..4b47aa2 100644 --- a/deps.ts +++ b/deps.ts @@ -2,11 +2,6 @@ export { EventEmitter } from 'https://deno.land/x/event@0.2.1/mod.ts' export { unzlib } from 'https://denopkg.com/DjDeveloperr/denoflate@1.2/mod.ts' export { fetchAuto } from 'https://deno.land/x/fetchbase64@1.0.0/mod.ts' export { parse } from 'https://deno.land/x/mutil@0.1.2/mod.ts' -export { connect } from 'https://deno.land/x/redis@v0.14.1/mod.ts' -export type { - Redis, - RedisConnectOptions -} from 'https://deno.land/x/redis@v0.14.1/mod.ts' export { walk } from 'https://deno.land/std@0.86.0/fs/walk.ts' export { join } from 'https://deno.land/std@0.86.0/path/mod.ts' export { Mixin } from 'https://esm.sh/ts-mixer@5.4.0' diff --git a/mod.ts b/mod.ts index cdbf8ec..b99a120 100644 --- a/mod.ts +++ b/mod.ts @@ -166,3 +166,4 @@ export type { VoiceStatePayload } from './src/types/voice.ts' export type { WebhookPayload } from './src/types/webhook.ts' export * from './src/models/collectors.ts' export type { Dict } from './src/utils/dict.ts' +export * from './src/models/redisCache.ts' diff --git a/src/models/cacheAdapter.ts b/src/models/cacheAdapter.ts index b9f5193..a04c149 100644 --- a/src/models/cacheAdapter.ts +++ b/src/models/cacheAdapter.ts @@ -1,5 +1,4 @@ import { Collection } from '../utils/collection.ts' -import { connect, Redis, RedisConnectOptions } from '../../deps.ts' /** * ICacheAdapter is the interface to be implemented by Cache Adapters for them to be usable with Harmony. @@ -71,106 +70,3 @@ export class DefaultCacheAdapter implements ICacheAdapter { return delete this.data[cacheName] } } - -/** Redis Cache Adapter for using Redis as a cache-provider. */ -export class RedisCacheAdapter implements ICacheAdapter { - _redis: Promise - redis?: Redis - ready: boolean = false - readonly _expireIntervalTimer: number = 5000 - private _expireInterval?: number - - constructor(options: RedisConnectOptions) { - this._redis = connect(options) - this._redis.then( - (redis) => { - this.redis = redis - this.ready = true - this._startExpireInterval() - }, - () => { - // TODO: Make error for this - } - ) - } - - private _startExpireInterval(): void { - this._expireInterval = setInterval(() => { - this.redis?.scan(0, { pattern: '*:expires' }).then(([_, names]) => { - for (const name of names) { - this.redis?.hvals(name).then((vals) => { - for (const val of vals) { - const expireVal: { - name: string - key: string - at: number - } = JSON.parse(val) - const expired = new Date().getTime() > expireVal.at - if (expired) this.redis?.hdel(expireVal.name, expireVal.key) - } - }) - } - }) - }, this._expireIntervalTimer) - } - - async _checkReady(): Promise { - if (!this.ready) await this._redis - } - - async get(cacheName: string, key: string): Promise { - await this._checkReady() - const cache = await this.redis?.hget(cacheName, key) - if (cache === undefined) return - try { - return JSON.parse(cache) - } catch (e) { - return cache - } - } - - async set( - cacheName: string, - key: string, - value: any, - expire?: number - ): Promise { - await this._checkReady() - const result = await this.redis?.hset( - cacheName, - key, - typeof value === 'object' ? JSON.stringify(value) : value - ) - if (expire !== undefined) { - await this.redis?.hset( - `${cacheName}:expires`, - key, - JSON.stringify({ - name: cacheName, - key, - at: new Date().getTime() + expire - }) - ) - } - return result - } - - async delete(cacheName: string, key: string): Promise { - await this._checkReady() - const exists = await this.redis?.hexists(cacheName, key) - if (exists === 0) return false - await this.redis?.hdel(cacheName, key) - return true - } - - async array(cacheName: string): Promise { - await this._checkReady() - const data = await this.redis?.hvals(cacheName) - return data?.map((e: string) => JSON.parse(e)) - } - - async deleteCache(cacheName: string): Promise { - await this._checkReady() - return (await this.redis?.del(cacheName)) !== 0 - } -} diff --git a/src/models/redisCache.ts b/src/models/redisCache.ts new file mode 100644 index 0000000..0820213 --- /dev/null +++ b/src/models/redisCache.ts @@ -0,0 +1,105 @@ +import { ICacheAdapter } from './cacheAdapter.ts' +import { connect, Redis, RedisConnectOptions } from 'https://deno.land/x/redis@v0.14.1/mod.ts' + +/** Redis Cache Adapter for using Redis as a cache-provider. */ +export class RedisCacheAdapter implements ICacheAdapter { + _redis: Promise + redis?: Redis + ready: boolean = false + readonly _expireIntervalTimer: number = 5000 + private _expireInterval?: number + + constructor(options: RedisConnectOptions) { + this._redis = connect(options) + this._redis.then( + (redis) => { + this.redis = redis + this.ready = true + this._startExpireInterval() + }, + () => { + // TODO: Make error for this + } + ) + } + + private _startExpireInterval(): void { + this._expireInterval = setInterval(() => { + this.redis?.scan(0, { pattern: '*:expires' }).then(([_, names]) => { + for (const name of names) { + this.redis?.hvals(name).then((vals) => { + for (const val of vals) { + const expireVal: { + name: string + key: string + at: number + } = JSON.parse(val) + const expired = new Date().getTime() > expireVal.at + if (expired) this.redis?.hdel(expireVal.name, expireVal.key) + } + }) + } + }) + }, this._expireIntervalTimer) + } + + async _checkReady(): Promise { + if (!this.ready) await this._redis + } + + async get(cacheName: string, key: string): Promise { + await this._checkReady() + const cache = await this.redis?.hget(cacheName, key) + if (cache === undefined) return + try { + return JSON.parse(cache) + } catch (e) { + return cache + } + } + + async set( + cacheName: string, + key: string, + value: any, + expire?: number + ): Promise { + await this._checkReady() + const result = await this.redis?.hset( + cacheName, + key, + typeof value === 'object' ? JSON.stringify(value) : value + ) + if (expire !== undefined) { + await this.redis?.hset( + `${cacheName}:expires`, + key, + JSON.stringify({ + name: cacheName, + key, + at: new Date().getTime() + expire + }) + ) + } + return result + } + + async delete(cacheName: string, key: string): Promise { + await this._checkReady() + const exists = await this.redis?.hexists(cacheName, key) + if (exists === 0) return false + await this.redis?.hdel(cacheName, key) + return true + } + + async array(cacheName: string): Promise { + await this._checkReady() + const data = await this.redis?.hvals(cacheName) + return data?.map((e: string) => JSON.parse(e)) + } + + async deleteCache(cacheName: string): Promise { + await this._checkReady() + return (await this.redis?.del(cacheName)) !== 0 + } +} \ No newline at end of file