diff --git a/src/cache/adapters/default.ts b/src/cache/adapters/default.ts index 0da75bb..e5217f8 100644 --- a/src/cache/adapters/default.ts +++ b/src/cache/adapters/default.ts @@ -1,11 +1,27 @@ import type { Adapter } from './types'; -export class MemoryAdapter implements Adapter { +export interface MemoryAdapterOptions { + encode(data: any): T; + decode(data: T): unknown; +} + +export class MemoryAdapter implements Adapter { isAsync = false; - readonly storage = new Map(); + readonly storage = new Map(); readonly relationships = new Map(); + constructor( + public options: MemoryAdapterOptions = { + encode(data) { + return JSON.stringify(data) as T; + }, + decode(data) { + return JSON.parse(data as string); + }, + }, + ) {} + scan(query: string, keys?: false): any[]; scan(query: string, keys: true): string[]; scan(query: string, keys = false) { @@ -13,7 +29,7 @@ export class MemoryAdapter implements Adapter { const sq = query.split('.'); for (const [key, value] of this.storage.entries()) { if (key.split('.').every((value, i) => (sq[i] === '*' ? !!value : sq[i] === value))) { - values.push(keys ? key : JSON.parse(value)); + values.push(keys ? key : this.options.decode(value)); } } @@ -24,24 +40,24 @@ export class MemoryAdapter implements Adapter { return keys .map(x => { const data = this.storage.get(x); - return data ? JSON.parse(data) : null; + return data ? this.options.decode(data) : null; }) .filter(x => x); } get(keys: string) { const data = this.storage.get(keys); - return data ? JSON.parse(data) : null; + return data ? this.options.decode(data) : null; } bulkSet(keys: [string, any][]) { for (const [key, value] of keys) { - this.storage.set(key, JSON.stringify(value)); + this.storage.set(key, this.options.encode(value)); } } set(key: string, data: any) { - this.storage.set(key, JSON.stringify(data)); + this.storage.set(key, this.options.encode(data)); } bulkPatch(updateOnly: boolean, keys: [string, any][]) { @@ -52,7 +68,7 @@ export class MemoryAdapter implements Adapter { } this.storage.set( key, - Array.isArray(value) ? JSON.stringify(value) : JSON.stringify({ ...(oldData ?? {}), ...value }), + Array.isArray(value) ? this.options.encode(value) : this.options.encode({ ...(oldData ?? {}), ...value }), ); } } @@ -64,7 +80,7 @@ export class MemoryAdapter implements Adapter { } this.storage.set( keys, - Array.isArray(data) ? JSON.stringify(data) : JSON.stringify({ ...(oldData ?? {}), ...data }), + Array.isArray(data) ? this.options.encode(data) : this.options.encode({ ...(oldData ?? {}), ...data }), ); } diff --git a/src/cache/adapters/limited.ts b/src/cache/adapters/limited.ts index 420b93b..86c6365 100644 --- a/src/cache/adapters/limited.ts +++ b/src/cache/adapters/limited.ts @@ -7,7 +7,7 @@ export interface ResourceLimitedMemoryAdapter { limit?: number; } -export interface LimitedMemoryAdapterOptions { +export interface LimitedMemoryAdapterOptions { default?: ResourceLimitedMemoryAdapter; guild?: ResourceLimitedMemoryAdapter; @@ -26,24 +26,33 @@ export interface LimitedMemoryAdapterOptions { thread?: ResourceLimitedMemoryAdapter; overwrite?: ResourceLimitedMemoryAdapter; message?: ResourceLimitedMemoryAdapter; + + encode(data: any): T; + decode(data: T): unknown; } -export class LimitedMemoryAdapter implements Adapter { +export class LimitedMemoryAdapter implements Adapter { isAsync = false; - readonly storage = new Map>(); + readonly storage = new Map>(); readonly relationships = new Map>(); - options: MakeRequired; + options: MakeRequired, 'default'>; - constructor(options: LimitedMemoryAdapterOptions) { + constructor(options: LimitedMemoryAdapterOptions) { this.options = MergeOptions( { default: { expire: undefined, limit: Number.POSITIVE_INFINITY, }, - } satisfies LimitedMemoryAdapterOptions, + encode(data) { + return JSON.stringify(data) as T; + }, + decode(data) { + return JSON.parse(data as string); + }, + } satisfies LimitedMemoryAdapterOptions, options, ); } @@ -56,7 +65,7 @@ export class LimitedMemoryAdapter implements Adapter { for (const iterator of [...this.storage.values()].flatMap(x => x.entries())) for (const [key, value] of iterator) { if (key.split('.').every((value, i) => (sq[i] === '*' ? !!value : sq[i] === value))) { - values.push(keys ? key : JSON.parse(value.value)); + values.push(keys ? key : this.options.decode(value.value)); } } @@ -68,14 +77,14 @@ export class LimitedMemoryAdapter implements Adapter { return keys .map(key => { const data = iterator.find(x => x.has(key))?.get(key); - return data ? JSON.parse(data) : null; + return data ? this.options.decode(data) : null; }) .filter(x => x); } get(keys: string) { const data = [...this.storage.values()].find(x => x.has(keys))?.get(keys); - return data ? JSON.parse(data) : null; + return data ? this.options.decode(data) : null; } private __set(key: string, data: any) { @@ -87,9 +96,11 @@ export class LimitedMemoryAdapter implements Adapter { namespace, new LimitedCollection({ expire: - this.options[key.split('.')[0] as keyof LimitedMemoryAdapterOptions]?.expire ?? this.options.default.expire, + this.options[key.split('.')[0] as Exclude, 'decode' | 'encode'>] + ?.expire ?? this.options.default.expire, limit: - this.options[key.split('.')[0] as keyof LimitedMemoryAdapterOptions]?.limit ?? this.options.default.limit, + this.options[key.split('.')[0] as Exclude, 'decode' | 'encode'>] + ?.limit ?? this.options.default.limit, resetOnDemand: true, onDelete(k) { const relationshipNamespace = key.split('.')[0]; @@ -126,7 +137,7 @@ export class LimitedMemoryAdapter implements Adapter { ); } - this.storage.get(namespace)!.set(key, JSON.stringify(data)); + this.storage.get(namespace)!.set(key, this.options.encode(data)); } bulkSet(keys: [string, any][]) { diff --git a/src/client/client.ts b/src/client/client.ts index 2d29608..dcdc4cb 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -141,7 +141,7 @@ export class Client extends BaseClient { protected async onPacket(shardId: number, packet: GatewayDispatchPayload) { Promise.allSettled([ this.events?.runEvent('RAW', this, packet, shardId, false), - this.collectors.run('RAW', packet), + this.collectors.run('RAW', packet, this), ]); //ignore promise switch (packet.t) { //// Cases where we must obtain the old data before updating diff --git a/src/client/collectors.ts b/src/client/collectors.ts index 09bb3da..47ede72 100644 --- a/src/client/collectors.ts +++ b/src/client/collectors.ts @@ -2,6 +2,8 @@ import { randomUUID } from 'node:crypto'; import type { Awaitable, CamelCase } from '../common'; import type { CallbackEventHandler, CustomEventsKeys, GatewayEvents } from '../events'; import { error } from 'node:console'; +import * as RawEvents from '../events/hooks'; +import type { UsingClient } from '../commands'; export type AllClientEvents = CustomEventsKeys | GatewayEvents; export type ParseClientEventName = T extends CustomEventsKeys ? T : CamelCase; @@ -98,11 +100,14 @@ export class Collectors { /**@internal */ async run( name: T, - data: Awaited]>[0]>, + raw: Awaited]>[0]>, + client: UsingClient, ) { const collectors = this.values.get(name); if (!collectors) return; + const data = RawEvents[name]?.(client, raw as never) ?? raw; + for (const i of collectors) { if (await i.options.filter(data as never)) { i.idle?.refresh(); diff --git a/src/client/workerclient.ts b/src/client/workerclient.ts index b7d35ea..60b305b 100644 --- a/src/client/workerclient.ts +++ b/src/client/workerclient.ts @@ -357,7 +357,7 @@ export class WorkerClient extends BaseClient { protected async onPacket(packet: GatewayDispatchPayload, shardId: number) { Promise.allSettled([ this.events?.runEvent('RAW', this, packet, shardId, false), - this.collectors.run('RAW', packet), + this.collectors.run('RAW', packet, this), ]); //ignore promise switch (packet.t) { //// Cases where we must obtain the old data before updating diff --git a/src/events/handler.ts b/src/events/handler.ts index f2c4766..2eb1cf4 100644 --- a/src/events/handler.ts +++ b/src/events/handler.ts @@ -111,7 +111,7 @@ export class EventHandler extends BaseHandler { await Promise.all([ this.runEvent(args[0].t as never, args[1], args[0].d, args[2]), - this.client.collectors.run(args[0].t as never, args[0].d as never), + this.client.collectors.run(args[0].t as never, args[0].d as never, this.client), ]); } @@ -150,15 +150,15 @@ export class EventHandler extends BaseHandler { async runCustom(name: T, ...args: Parameters) { const Event = this.values[name]; if (!Event) { - return this.client.collectors.run(name, args as never); + return this.client.collectors.run(name, args as never, this.client); } try { if (Event.data.once && Event.fired) { - return this.client.collectors.run(name, args as never); + return this.client.collectors.run(name, args as never, this.client); } Event.fired = true; this.logger.debug(`executed a custom event [${name}]`, Event.data.once ? 'once' : ''); - await Promise.all([Event.run(args, this.client), this.client.collectors.run(name, args as never)]); + await Promise.all([Event.run(args, this.client), this.client.collectors.run(name, args as never, this.client)]); } catch (e) { await this.onFail(name, e); }