UNPKG

seyfert

Version:

The most advanced framework for discord bots

356 lines (355 loc) 12.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LimitedMemoryAdapter = void 0; const __1 = require("../.."); const common_1 = require("../../common"); class LimitedMemoryAdapter { isAsync = false; storage = new Map(); relationships = new Map(); keyToStorage = new Map(); options; constructor(options) { this.options = (0, common_1.MergeOptions)({ default: { expire: undefined, limit: Number.POSITIVE_INFINITY, }, encode(data) { return data; }, decode(data) { return data; }, }, options); } start() { // } scan(query, keys = false) { const sq = query.split('.'); const values = []; for (const storageEntry of this.storage.values()) { for (const [key, entry] of storageEntry.entries()) { const keySplit = key.split('.'); if (keySplit.length === sq.length && keySplit.every((segment, i) => (sq[i] === '*' ? !!segment : sq[i] === segment))) { values.push(keys ? key : this.options.decode(entry.value)); } } } return values; } bulkGet(keys) { const result = []; for (const key of keys) { const data = this.get(key); if (data !== undefined && data !== null) result.push(data); } return result; } _getKeyResource(key) { const separatorIndex = key.indexOf('.'); return separatorIndex === -1 ? key : key.slice(0, separatorIndex); } _getKeyScope(key) { const separatorIndex = key.indexOf('.'); if (separatorIndex === -1) { return ''; } const scopeStart = separatorIndex + 1; const scopeEnd = key.indexOf('.', scopeStart); return scopeEnd === -1 ? key.slice(scopeStart) : key.slice(scopeStart, scopeEnd); } _supportsNamespaceIndex(resource) { switch (resource) { case 'channel': case 'emoji': case 'presence': case 'role': case 'stage_instance': case 'sticker': case 'overwrite': case 'message': return true; default: return false; } } _setIndexedStorage(resource, key, storageEntry) { if (!this._supportsNamespaceIndex(resource)) { return; } this.keyToStorage.set(key, storageEntry); } _deleteIndexedStorage(resource, key) { if (!this._supportsNamespaceIndex(resource)) { return; } this.keyToStorage.delete(key); } _getIndexedStorage(resource, key) { if (!this._supportsNamespaceIndex(resource)) { return; } return this.keyToStorage.get(key); } _getDerivedNamespace(resource, scope) { switch (resource) { case 'ban': case 'member': case 'voice_state': return scope ? `${resource}.${scope}` : resource; default: return resource; } } _isResourceNamespace(resource, namespace) { return namespace === resource || namespace.startsWith(`${resource}.`); } _findNamespaceByStorage(resource, storageEntry) { for (const [namespace, candidate] of this.storage.entries()) { if (candidate === storageEntry && this._isResourceNamespace(resource, namespace)) { return namespace; } } return undefined; } _getStorageNamespace(resource, data) { const isArray = Array.isArray(data); if (isArray && data.length === 0) { return; } const scope = isArray ? data[0].guild_id : data.guild_id; return `${resource}${scope ? `.${scope}` : ''}`; } _getStorageEntry(key) { const resource = this._getKeyResource(key); const supportsNamespaceIndex = this._supportsNamespaceIndex(resource); const indexedStorage = this._getIndexedStorage(resource, key); if (indexedStorage?.has(key)) { return { resource, storageEntry: indexedStorage, }; } if (indexedStorage) { this._deleteIndexedStorage(resource, key); } if (!supportsNamespaceIndex) { const namespace = this._getDerivedNamespace(resource, this._getKeyScope(key)); const storageEntry = this.storage.get(namespace); if (storageEntry?.has(key)) { return { resource, namespace, storageEntry, }; } } for (const [namespace, storageEntry] of this.storage.entries()) { if (this._isResourceNamespace(resource, namespace) && storageEntry.has(key)) { this._setIndexedStorage(resource, key, storageEntry); return { resource, namespace, storageEntry, }; } } return; } get(key) { const entry = this._getStorageEntry(key); if (!entry) { return null; } return this.options.decode(entry.storageEntry.get(key)); } __set(key, data) { const resource = this._getKeyResource(key); const namespace = this._getStorageNamespace(resource, data); if (!namespace) { return; } let storageEntry = this.storage.get(namespace); if (!storageEntry) { const self = this; storageEntry = new __1.LimitedCollection({ expire: this.options[resource]?.expire ?? this.options.default.expire, limit: this.options[resource]?.limit ?? this.options.default.limit, resetOnDemand: true, onDelete(k, value) { self._deleteIndexedStorage(resource, k); const relationshipNamespace = resource; const existsRelation = self.relationships.has(relationshipNamespace); if (existsRelation) { switch (relationshipNamespace) { case 'message': { const decodedValue = self.options.decode(value); if (decodedValue.channel_id) self.removeToRelationship(`${relationshipNamespace}.${decodedValue.channel_id}`, k.split('.')[1]); } break; case 'ban': case 'member': case 'voice_state': { const split = k.split('.'); self.removeToRelationship(`${namespace}.${split[1]}`, split[2]); } break; case 'channel': case 'emoji': case 'presence': case 'role': case 'stage_instance': case 'sticker': case 'overwrite': self.removeToRelationship(namespace, k.split('.')[1]); break; // case 'guild': // case 'user': default: self.removeToRelationship(namespace, k.split('.')[1]); break; } } }, }); this.storage.set(namespace, storageEntry); } const previousBucket = this._getIndexedStorage(resource, key); if (previousBucket && previousBucket !== storageEntry) { previousBucket?.delete(key); if (previousBucket?.size === 0) { const previousNamespace = this._findNamespaceByStorage(resource, previousBucket); if (previousNamespace) { this.storage.delete(previousNamespace); } } } this._setIndexedStorage(resource, key, storageEntry); storageEntry.set(key, this.options.encode(data)); } bulkSet(keys) { for (const [key, value] of keys) { this.__set(key, value); } } set(keys, data) { this.__set(keys, data); } bulkPatch(keys) { for (const [key, value] of keys) { const oldData = this.get(key); this.__set(key, Array.isArray(value) ? value : { ...(oldData ?? {}), ...value }); } } patch(keys, data) { const oldData = this.get(keys); this.__set(keys, Array.isArray(data) ? data : { ...(oldData ?? {}), ...data }); } values(to) { const array = []; const data = this.keys(to); for (const key of data) { const content = this.get(key); if (content !== undefined && content !== null) { array.push(content); } } return array; } keys(to) { const result = []; for (const id of this._getRelationshipSet(to)) { result.push(`${to}.${id}`); } return result; } count(to) { return this._getRelationshipSet(to).size; } bulkRemove(keys) { for (const i of keys) { this.remove(i); } } remove(key) { const entry = this._getStorageEntry(key); if (!entry) { return; } entry.storageEntry.delete(key); this._deleteIndexedStorage(entry.resource, key); if (entry.storageEntry.size === 0) { const namespace = entry.namespace ?? this._findNamespaceByStorage(entry.resource, entry.storageEntry); if (namespace) { this.storage.delete(namespace); } } } flush() { this.storage.clear(); this.relationships.clear(); this.keyToStorage.clear(); } contains(to, keys) { return this._getRelationshipSet(to).has(keys); } _getRelationshipData(to) { const [key, subrelationKey = '*'] = to.split('.'); return { key, subrelationKey }; } _getRelationshipSet(to) { const { key, subrelationKey } = this._getRelationshipData(to); if (!this.relationships.has(key)) this.relationships.set(key, new Map()); const relation = this.relationships.get(key); if (!relation.has(subrelationKey)) { relation.set(subrelationKey, new Set()); } return relation.get(subrelationKey); } getToRelationship(to) { return [...this._getRelationshipSet(to)]; } bulkAddToRelationShip(data) { for (const i in data) { this.addToRelationship(i, data[i]); } } addToRelationship(to, keys) { const data = this._getRelationshipSet(to); for (const key of Array.isArray(keys) ? keys : [keys]) { data.add(key); } } removeToRelationship(to, keys) { const data = this._getRelationshipSet(to); for (const key of Array.isArray(keys) ? keys : [keys]) { data.delete(key); } } removeRelationship(to) { for (const i of Array.isArray(to) ? to : [to]) { const { key, subrelationKey } = this._getRelationshipData(i); if (subrelationKey === '*') { this.relationships.delete(key); continue; } const relation = this.relationships.get(key); if (!relation) continue; relation.delete(subrelationKey); if (!relation.size) this.relationships.delete(key); } } } exports.LimitedMemoryAdapter = LimitedMemoryAdapter;