mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-01 20:46:08 +00:00
cache preview version alpha
This commit is contained in:
parent
04b856818c
commit
0daec51769
@ -16,6 +16,8 @@ ignorePatterns:
|
||||
- 'coverage'
|
||||
- '**/*.js'
|
||||
- '**/*.d.ts'
|
||||
- '__tests__'
|
||||
- '__test__'
|
||||
|
||||
parser: '@typescript-eslint/parser'
|
||||
|
||||
|
34
packages/cache/README.md
vendored
34
packages/cache/README.md
vendored
@ -1,13 +1,39 @@
|
||||
# @biscuitland/cache
|
||||
|
||||
In progress.
|
||||
## Most importantly, biscuit's cache is:
|
||||
|
||||
A resource control cache layer, based on carriers and resource-intensive policies
|
||||
|
||||
[<img src="https://img.shields.io/badge/GitHub-100000?style=for-the-badge&logo=github&logoColor=white">](https://github.com/oasisjs/biscuit)
|
||||
[<img src="https://img.shields.io/badge/Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white">](https://discord.gg/XNw2RZFzaP)
|
||||
|
||||
<img align="right" src="https://raw.githubusercontent.com/oasisjs/biscuit/main/assets/icon.svg" alt="biscuit"/>
|
||||
|
||||
## Install (for [node18](https://nodejs.org/en/download/))
|
||||
|
||||
```sh-session
|
||||
npm install @biscuitland/cache
|
||||
```
|
||||
|
||||
## Example (Basic)
|
||||
|
||||
```ts
|
||||
import { Cache, MemoryCacheAdapter } from '@biscuitland/cache';
|
||||
|
||||
const bootstrap = async () => {
|
||||
const cache = new Cache({
|
||||
adapter: new MemoryCacheAdapter(),
|
||||
});
|
||||
|
||||
// You can listen to the raw biscuit event
|
||||
|
||||
cache.start(<payloads>);
|
||||
};
|
||||
|
||||
bootstrap();
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
- [Website](https://biscuitjs.com/)
|
||||
- [Documentation](https://docs.biscuitjs.com/)
|
||||
- [Discord](https://discord.gg/XNw2RZFzaP)
|
||||
- [core](https://www.npmjs.com/package/@biscuitland/core) | [api-types](https://www.npmjs.com/package/@biscuitland/api-types) | [rest](https://www.npmjs.com/package/@biscuitland/rest) | [ws](https://www.npmjs.com/package/@biscuitland/ws) | [helpers](https://www.npmjs.com/package/@biscuitland/helpers)
|
||||
- [Website](https://biscuitjs.com/)
|
||||
|
50
packages/cache/src/adapters/cache-adapter.ts
vendored
50
packages/cache/src/adapters/cache-adapter.ts
vendored
@ -1,50 +0,0 @@
|
||||
export interface CacheAdapter {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
get(id: string): any | Promise<any>;
|
||||
get(id: string, guild?: string): string | Promise<string>;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
set(id: string, data: any, expire?: number): void | Promise<void>;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
count(to: string): number | Promise<number>;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
remove(id: string): void | Promise<void>;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
contains(to: string, id: string): boolean | Promise<boolean>;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
getToRelationship(to: string): string[] | Promise<string[]>;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
addToRelationship(to: string, id: string): void | Promise<void>;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
removeToRelationship(to: string, id: string): void | Promise<void>;
|
||||
}
|
121
packages/cache/src/adapters/redis-cache-adapter.ts
vendored
121
packages/cache/src/adapters/redis-cache-adapter.ts
vendored
@ -1,121 +0,0 @@
|
||||
import type { CacheAdapter } from './cache-adapter';
|
||||
|
||||
import type { RedisOptions } from 'ioredis';
|
||||
import type Redis from 'ioredis';
|
||||
import IORedis from 'ioredis';
|
||||
|
||||
interface BaseOptions {
|
||||
namespace: string;
|
||||
expire?: number;
|
||||
}
|
||||
|
||||
interface BuildOptions extends BaseOptions, RedisOptions { }
|
||||
|
||||
interface ClientOptions extends BaseOptions {
|
||||
client: Redis;
|
||||
}
|
||||
|
||||
type Options = BuildOptions | ClientOptions;
|
||||
|
||||
export class RedisCacheAdapter implements CacheAdapter {
|
||||
private static readonly DEFAULTS = {
|
||||
namespace: 'biscuitland'
|
||||
};
|
||||
|
||||
private readonly client: Redis;
|
||||
|
||||
readonly options: Options;
|
||||
|
||||
constructor(options?: Options) {
|
||||
this.options = Object.assign(RedisCacheAdapter.DEFAULTS, options);
|
||||
|
||||
if ((this.options as ClientOptions).client) {
|
||||
this.client = (this.options as ClientOptions).client;
|
||||
} else {
|
||||
const { ...redisOpt } = this.options as BuildOptions;
|
||||
this.client = new IORedis(redisOpt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async get(id: string): Promise<any> {
|
||||
const data = await this.client.get(this.composite(id));
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return JSON.parse(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async set(id: string, data: unknown, expire = this.options.expire): Promise<void> {
|
||||
if (expire) {
|
||||
await this.client.set(this.composite(id), JSON.stringify(data), 'EX', expire);
|
||||
} else {
|
||||
await this.client.set(this.composite(id), JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async count(_to: string): Promise<number> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
await this.client.del(this.composite(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async contains(_to: string, _id: string): Promise<boolean> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async getToRelationship(_to: string): Promise<string[]> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async addToRelationship(_to: string, _id: string): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async removeToRelationship(_to: string, _id: string): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
composite(id: string): string {
|
||||
return `${this.options.namespace}:${id}`;
|
||||
}
|
||||
}
|
184
packages/cache/src/cache.ts
vendored
184
packages/cache/src/cache.ts
vendored
@ -1,6 +1,8 @@
|
||||
/* eslint-disable no-case-declarations */
|
||||
import { MemoryCacheAdapter } from './adapters/memory-cache-adapter';
|
||||
// import { RedisCacheAdapter } from './adapters/redis-cache-adapter';
|
||||
import type { CacheOptions, CO } from './types';
|
||||
|
||||
import type { CacheAdapter } from './scheme/adapters/cache-adapter';
|
||||
import { MemoryCacheAdapter } from './scheme/adapters/memory-cache-adapter';
|
||||
|
||||
import {
|
||||
ChannelResource,
|
||||
@ -9,26 +11,23 @@ import {
|
||||
GuildResource,
|
||||
GuildRoleResource,
|
||||
GuildStickerResource,
|
||||
GuildVoiceResource,
|
||||
PresenceResource,
|
||||
UserResource,
|
||||
VoiceResource
|
||||
} from './resources';
|
||||
|
||||
/**
|
||||
* add options and adaptor passable by options
|
||||
* @default MemoryCacheAdapter
|
||||
*/
|
||||
import { Options } from './utils/options';
|
||||
|
||||
/**
|
||||
* Add more adapters and options
|
||||
* Allow passing customizable resources and deleting resources
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add presence system (disabled by default)
|
||||
* Add TTL option (default 7 days)
|
||||
* Add permissions resource (accessible as a subResource)
|
||||
*/
|
||||
export class Cache {
|
||||
static readonly DEFAULTS = {
|
||||
adapter: new MemoryCacheAdapter(),
|
||||
};
|
||||
|
||||
readonly options: CO;
|
||||
#adapter: CacheAdapter;
|
||||
|
||||
// move to resources assigned
|
||||
|
||||
readonly channels: ChannelResource;
|
||||
|
||||
readonly emojis: GuildEmojiResource;
|
||||
@ -36,61 +35,64 @@ export class Cache {
|
||||
readonly guilds: GuildResource;
|
||||
readonly roles: GuildRoleResource;
|
||||
readonly stickers: GuildStickerResource;
|
||||
readonly voices: GuildVoiceResource;
|
||||
|
||||
readonly presences: PresenceResource;
|
||||
readonly users: UserResource;
|
||||
readonly voices: VoiceResource;
|
||||
|
||||
ready: boolean;
|
||||
constructor(options: CacheOptions) {
|
||||
this.options = Options({}, Cache.DEFAULTS, options);
|
||||
this.#adapter = this.options.adapter;
|
||||
|
||||
constructor() {
|
||||
this.ready = false;
|
||||
this.channels = new ChannelResource(this.#adapter);
|
||||
|
||||
/** this change to memory */
|
||||
const adapter = new MemoryCacheAdapter();
|
||||
this.emojis = new GuildEmojiResource(this.#adapter);
|
||||
this.members = new GuildMemberResource(this.#adapter);
|
||||
|
||||
this.channels = new ChannelResource(adapter);
|
||||
this.guilds = new GuildResource(this.#adapter);
|
||||
this.roles = new GuildRoleResource(this.#adapter);
|
||||
|
||||
this.emojis = new GuildEmojiResource(adapter);
|
||||
this.members = new GuildMemberResource(adapter);
|
||||
this.stickers = new GuildStickerResource(this.#adapter);
|
||||
this.voices = new GuildVoiceResource(this.#adapter);
|
||||
|
||||
this.guilds = new GuildResource(adapter);
|
||||
this.roles = new GuildRoleResource(adapter);
|
||||
this.stickers = new GuildStickerResource(adapter);
|
||||
|
||||
this.users = new UserResource(adapter);
|
||||
this.voices = new VoiceResource(adapter);
|
||||
this.presences = new PresenceResource(this.#adapter);
|
||||
this.users = new UserResource(this.#adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async start(event: { t: string; d: any }) {
|
||||
async start(event: any) {
|
||||
let resources: any[] = [];
|
||||
|
||||
let contents: any[] = [];
|
||||
|
||||
switch (event.t) {
|
||||
case 'READY':
|
||||
resources = [];
|
||||
|
||||
await this.users.set(event.d.user.id, event.d.user);
|
||||
|
||||
const guilds: (Promise<any> | undefined)[] = [];
|
||||
|
||||
for (const guild of event.d.guilds) {
|
||||
guilds.push(this.guilds.set(guild.id, guild));
|
||||
resources.push(this.guilds.set(guild.id, guild));
|
||||
}
|
||||
|
||||
await Promise.all(guilds);
|
||||
await Promise.all(resources);
|
||||
|
||||
this.ready = true;
|
||||
break;
|
||||
|
||||
case 'USER_UPDATE':
|
||||
await this.users.set(event.d.id, event.d);
|
||||
break;
|
||||
case 'PRESENCE_UPDATE':
|
||||
await this.presences.set(event.d.user?.id, event.d);
|
||||
|
||||
case 'GUILD_CREATE':
|
||||
await this.guilds.set(event.d.id, event.d);
|
||||
break;
|
||||
|
||||
case 'GUILD_CREATE':
|
||||
case 'GUILD_UPDATE':
|
||||
this.guilds.set(event.d.id, event.d);
|
||||
await this.guilds.set(event.d.id, event.d);
|
||||
break;
|
||||
|
||||
case 'GUILD_DELETE':
|
||||
@ -102,10 +104,6 @@ export class Cache {
|
||||
break;
|
||||
|
||||
case 'CHANNEL_CREATE':
|
||||
// modify [Add elimination system]
|
||||
await this.channels.set(event.d.id, event.d);
|
||||
break;
|
||||
|
||||
case 'CHANNEL_UPDATE':
|
||||
// modify [Add elimination system]
|
||||
await this.channels.set(event.d.id, event.d);
|
||||
@ -116,14 +114,18 @@ export class Cache {
|
||||
await this.channels.remove(event.d.id);
|
||||
break;
|
||||
|
||||
case 'GUILD_ROLE_CREATE':
|
||||
await this.roles.set(
|
||||
event.d.role.id,
|
||||
event.d.guild_id,
|
||||
event.d.role
|
||||
);
|
||||
case 'MESSAGE_CREATE':
|
||||
if (event.d.webhook_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.d.author) {
|
||||
await this.users.set(event.d.author.id, event.d.author);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'GUILD_ROLE_CREATE':
|
||||
case 'GUILD_ROLE_UPDATE':
|
||||
await this.roles.set(
|
||||
event.d.role.id,
|
||||
@ -137,27 +139,62 @@ export class Cache {
|
||||
break;
|
||||
|
||||
case 'GUILD_EMOJIS_UPDATE':
|
||||
// modify [Add elimination system]
|
||||
for (const v of event.d.emojis) {
|
||||
await this.emojis?.set(v.id, event.d.guild_id, v);
|
||||
contents = [];
|
||||
contents = await this.emojis.items(event.d.guild_id);
|
||||
|
||||
for (const emoji of event.d.emojis) {
|
||||
const emote = contents.find(o => o?.id === emoji.id);
|
||||
|
||||
if (!emote || emote !== emoji) {
|
||||
await this.emojis.set(
|
||||
emoji.id,
|
||||
event.d.guild_id,
|
||||
emoji
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const emoji of contents) {
|
||||
const emote = event.d.emojis.find(
|
||||
(o: any) => o.id === emoji?.id
|
||||
);
|
||||
|
||||
if (!emote) {
|
||||
await this.emojis.remove(emote.id, event.d.guild_id);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'GUILD_STICKERS_UPDATE':
|
||||
// modify [Add elimination system]
|
||||
for (const v of event.d.stickers) {
|
||||
await this.stickers?.set(v.id, event.d.guild_id, v);
|
||||
contents = [];
|
||||
contents = await this.stickers.items(event.d.guild_id);
|
||||
|
||||
for (const sticker of event.d.stickers) {
|
||||
const stick = contents.find(o => o?.id === sticker.id);
|
||||
|
||||
if (!stick || stick !== sticker) {
|
||||
await this.stickers.set(
|
||||
sticker.id,
|
||||
event.d.guild_id,
|
||||
sticker
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const sticker of contents) {
|
||||
const stick = event.d.stickers.find(
|
||||
(o: any) => o.id === sticker?.id
|
||||
);
|
||||
|
||||
if (!stick) {
|
||||
await this.stickers.remove(stick.id, event.d.guild_id);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'GUILD_MEMBER_ADD':
|
||||
await this.members.set(
|
||||
event.d.user.id,
|
||||
event.d.guild_id,
|
||||
event.d
|
||||
);
|
||||
break;
|
||||
|
||||
case 'GUILD_MEMBER_UPDATE':
|
||||
await this.members.set(
|
||||
event.d.user.id,
|
||||
@ -171,10 +208,10 @@ export class Cache {
|
||||
break;
|
||||
|
||||
case 'GUILD_MEMBERS_CHUNK':
|
||||
const members: (Promise<any> | undefined)[] = [];
|
||||
resources = [];
|
||||
|
||||
for (const member of event.d.members) {
|
||||
members.push(
|
||||
resources.push(
|
||||
this.members.set(
|
||||
member.user.id,
|
||||
event.d.guild_id,
|
||||
@ -183,7 +220,7 @@ export class Cache {
|
||||
);
|
||||
}
|
||||
|
||||
await Promise.all(members);
|
||||
await Promise.all(resources);
|
||||
|
||||
break;
|
||||
|
||||
@ -192,16 +229,15 @@ export class Cache {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.d.user_id && event.d.member) {
|
||||
await this.members.set(
|
||||
event.d.user_id,
|
||||
event.d.guild_id,
|
||||
event.d.member
|
||||
);
|
||||
if (event.d.guild_id && event.d.member && event.d.user_id) {
|
||||
await this.members.set(event.d.user_id, event.d.guild_id, {
|
||||
guild_id: event.d.guild_id,
|
||||
...event.d.member,
|
||||
});
|
||||
}
|
||||
|
||||
if (event.d.channel_id != null) {
|
||||
await this.voices.set(
|
||||
await this.members.set(
|
||||
event.d.user_id,
|
||||
event.d.guild_id,
|
||||
event.d
|
||||
|
7
packages/cache/src/index.ts
vendored
7
packages/cache/src/index.ts
vendored
@ -1,6 +1,7 @@
|
||||
export { CacheAdapter } from './adapters/cache-adapter';
|
||||
export { MemoryCacheAdapter } from './scheme/adapters/memory-cache-adapter';
|
||||
export { RedisCacheAdapter } from './scheme/adapters/redis-cache-adapter';
|
||||
|
||||
export { MemoryCacheAdapter } from './adapters/memory-cache-adapter';
|
||||
export { RedisCacheAdapter } from './adapters/redis-cache-adapter';
|
||||
export { CacheAdapter } from './scheme/adapters/cache-adapter';
|
||||
|
||||
export { RedisOptions, MemoryOptions, CacheOptions } from './types';
|
||||
export { Cache } from './cache';
|
||||
|
112
packages/cache/src/resources/base-resource.ts
vendored
112
packages/cache/src/resources/base-resource.ts
vendored
@ -1,63 +1,117 @@
|
||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||
|
||||
export class BaseResource {
|
||||
namespace = 'base';
|
||||
/**
|
||||
* Base class for all resources
|
||||
* All Methods from BaseResource are also available on every class extends
|
||||
*/
|
||||
|
||||
adapter!: CacheAdapter; // replace
|
||||
class Base<T> {
|
||||
/**
|
||||
* Resource name
|
||||
*/
|
||||
|
||||
#namespace = 'base';
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Adapter for storage processes and operations
|
||||
*/
|
||||
|
||||
#adapter: CacheAdapter;
|
||||
|
||||
/**
|
||||
* Guild linked and assigned to the current entity (resource)
|
||||
*/
|
||||
|
||||
parent?: string;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
||||
constructor(namespace: string, adapter: CacheAdapter) {
|
||||
this.#namespace = namespace;
|
||||
this.#adapter = adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entity linked
|
||||
*/
|
||||
|
||||
setEntity(entity: T): void {
|
||||
Object.assign(this, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parent linked
|
||||
*/
|
||||
|
||||
setParent(parent: string): void {
|
||||
// rename
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count how many resources there are in the relationships
|
||||
*/
|
||||
|
||||
async count(to: string): Promise<number> {
|
||||
return await this.adapter.count(this.hashId(to));
|
||||
return await this.#adapter.count(this.hashId(to));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Check if the resource is in the relationships
|
||||
*/
|
||||
|
||||
async contains(to: string, id: string): Promise<boolean> {
|
||||
return await this.adapter.contains(this.hashId(to), id);
|
||||
async contains(
|
||||
id: string,
|
||||
guild: string = this.parent as string
|
||||
): Promise<boolean> {
|
||||
return await this.#adapter.contains(this.hashId(guild), id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Gets the resource relationships
|
||||
*/
|
||||
|
||||
async getToRelationship(to: string): Promise<string[]> {
|
||||
return await this.adapter.getToRelationship(this.hashId(to));
|
||||
async getToRelationship(
|
||||
id: string = this.parent as string
|
||||
): Promise<string[]> {
|
||||
return await this.#adapter.getToRelationship(this.hashId(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Adds the resource to relationships
|
||||
*/
|
||||
|
||||
async addToRelationship(to: string, id: string): Promise<void> {
|
||||
await this.adapter.addToRelationship(this.hashId(to), id);
|
||||
async addToRelationship(
|
||||
id: string,
|
||||
guild: string = this.parent as string
|
||||
): Promise<void> {
|
||||
await this.#adapter.addToRelationship(this.hashId(guild), id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc // to-do replace
|
||||
* Removes the relationship resource
|
||||
*/
|
||||
|
||||
async removeToRelationship(to: string, id: string): Promise<void> {
|
||||
await this.adapter.removeToRelationship(this.hashId(to), id);
|
||||
async removeToRelationship(
|
||||
id: string,
|
||||
guild: string = this.parent as string
|
||||
): Promise<void> {
|
||||
await this.#adapter.removeToRelationship(this.hashId(guild), id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Construct an id consisting of namespace.id
|
||||
*/
|
||||
|
||||
hashId(id: string): string {
|
||||
return `${this.namespace}.${id}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
hashGuildId(id: string, guild: string): string {
|
||||
return `${this.namespace}.${guild}.${id}`;
|
||||
protected hashId(id: string): string {
|
||||
return `${this.#namespace}.${id}`;
|
||||
}
|
||||
}
|
||||
|
||||
export const BaseResource = Base as new <T>(
|
||||
data: string,
|
||||
adapter: CacheAdapter
|
||||
) => Base<T> & T;
|
||||
|
94
packages/cache/src/resources/channel-resource.ts
vendored
94
packages/cache/src/resources/channel-resource.ts
vendored
@ -1,42 +1,92 @@
|
||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
||||
/**
|
||||
* refactor
|
||||
*/
|
||||
|
||||
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||
import type { DiscordChannel } from '@biscuitland/api-types';
|
||||
|
||||
import { BaseResource } from './base-resource';
|
||||
import { UserResource } from './user-resource';
|
||||
|
||||
export class ChannelResource extends BaseResource {
|
||||
namespace = 'channel' as const;
|
||||
/**
|
||||
* Resource represented by an channel of discord
|
||||
*/
|
||||
|
||||
adapter: CacheAdapter;
|
||||
export class ChannelResource extends BaseResource<DiscordChannel> {
|
||||
#namespace = 'channel';
|
||||
|
||||
constructor(adapter: CacheAdapter) {
|
||||
super();
|
||||
#adapter: CacheAdapter;
|
||||
|
||||
this.adapter = adapter;
|
||||
#users: UserResource;
|
||||
|
||||
constructor(adapter: CacheAdapter, entity?: DiscordChannel | null) {
|
||||
super('channel', adapter);
|
||||
|
||||
this.#adapter = adapter;
|
||||
this.#users = new UserResource(adapter);
|
||||
|
||||
if (entity) {
|
||||
this.setEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async get(id: string): Promise<DiscordChannel | null> {
|
||||
const kv = await this.adapter.get(this.hashId(id));
|
||||
async get(id: string): Promise<ChannelResource | null> {
|
||||
if (this.parent) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const kv = await this.#adapter.get(this.hashId(id));
|
||||
|
||||
if (kv) {
|
||||
return kv;
|
||||
return new ChannelResource(this.#adapter, kv);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc // to-do rework
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async set(id: string, data: any, expire?: number): Promise<void> {
|
||||
async set(id: string, data: any): Promise<void> {
|
||||
if (data.recipients) {
|
||||
const recipients = [];
|
||||
|
||||
for (const recipient of data.recipients) {
|
||||
recipients.push(this.#users.set(recipient.id, recipient));
|
||||
}
|
||||
|
||||
await Promise.all(recipients);
|
||||
}
|
||||
|
||||
delete data.recipients;
|
||||
delete data.permission_overwrites;
|
||||
|
||||
await this.addToRelationship(id);
|
||||
await this.adapter.set(this.hashId(id), data, expire);
|
||||
await this.#adapter.set(this.hashId(id), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async items(): Promise<ChannelResource[]> {
|
||||
const data = await this.#adapter.items(this.#namespace);
|
||||
|
||||
if (data) {
|
||||
return data.map(dt => {
|
||||
const resource = new ChannelResource(this.#adapter, dt);
|
||||
resource.setParent(resource.id);
|
||||
|
||||
return resource;
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,7 +94,7 @@ export class ChannelResource extends BaseResource {
|
||||
*/
|
||||
|
||||
async count(): Promise<number> {
|
||||
return await this.adapter.count(this.namespace);
|
||||
return await this.#adapter.count(this.#namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,7 +102,7 @@ export class ChannelResource extends BaseResource {
|
||||
*/
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
await this.adapter.remove(this.hashId(id));
|
||||
await this.#adapter.remove(this.hashId(id));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,7 +110,7 @@ export class ChannelResource extends BaseResource {
|
||||
*/
|
||||
|
||||
async contains(id: string): Promise<boolean> {
|
||||
return await this.adapter.contains(this.namespace, id);
|
||||
return await this.#adapter.contains(this.#namespace, id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,7 +118,7 @@ export class ChannelResource extends BaseResource {
|
||||
*/
|
||||
|
||||
async getToRelationship(): Promise<string[]> {
|
||||
return await this.adapter.getToRelationship(this.namespace);
|
||||
return await this.#adapter.getToRelationship(this.#namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,6 +126,14 @@ export class ChannelResource extends BaseResource {
|
||||
*/
|
||||
|
||||
async addToRelationship(id: string): Promise<void> {
|
||||
await this.adapter.addToRelationship(this.namespace, id);
|
||||
await this.#adapter.addToRelationship(this.#namespace, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async removeToRelationship(id: string): Promise<void> {
|
||||
await this.#adapter.removeToRelationship(this.#namespace, id);
|
||||
}
|
||||
}
|
||||
|
109
packages/cache/src/resources/guild-emoji-resource.ts
vendored
109
packages/cache/src/resources/guild-emoji-resource.ts
vendored
@ -1,28 +1,55 @@
|
||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
||||
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||
import type { DiscordEmoji } from '@biscuitland/api-types';
|
||||
|
||||
import { BaseResource } from './base-resource';
|
||||
import { UserResource } from './user-resource';
|
||||
|
||||
export class GuildEmojiResource extends BaseResource {
|
||||
namespace = 'emoji' as const;
|
||||
/**
|
||||
* Resource represented by an emoji of discord
|
||||
*/
|
||||
|
||||
adapter: CacheAdapter;
|
||||
export class GuildEmojiResource extends BaseResource<DiscordEmoji> {
|
||||
#namespace = 'emoji' as const;
|
||||
|
||||
constructor(adapter: CacheAdapter) {
|
||||
super();
|
||||
#adapter: CacheAdapter;
|
||||
|
||||
this.adapter = adapter;
|
||||
#users: UserResource;
|
||||
|
||||
constructor(
|
||||
adapter: CacheAdapter,
|
||||
entity?: DiscordEmoji | null,
|
||||
parent?: string
|
||||
) {
|
||||
super('emoji', adapter);
|
||||
|
||||
this.#adapter = adapter;
|
||||
this.#users = new UserResource(adapter);
|
||||
|
||||
if (entity) {
|
||||
this.setEntity(entity);
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
this.setParent(parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async get(id: string, guild: string): Promise<DiscordEmoji | null> {
|
||||
const kv = await this.adapter.get(this.hashGuildId(id, guild));
|
||||
async get(
|
||||
id: string,
|
||||
guild: string | undefined = this.parent
|
||||
): Promise<GuildEmojiResource | null> {
|
||||
if (this.parent) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const kv = await this.#adapter.get(this.hashGuildId(id, guild));
|
||||
|
||||
if (kv) {
|
||||
return kv;
|
||||
return new GuildEmojiResource(this.#adapter, kv, guild);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -34,18 +61,68 @@ export class GuildEmojiResource extends BaseResource {
|
||||
|
||||
async set(
|
||||
id: string,
|
||||
guild: string,
|
||||
data: any,
|
||||
expire?: number
|
||||
guild: string | undefined = this.parent,
|
||||
data: any
|
||||
): Promise<void> {
|
||||
await this.adapter.set(this.hashGuildId(id, guild), data, expire);
|
||||
if (data.user) {
|
||||
await this.#users.set(data.user.id, data.user);
|
||||
}
|
||||
|
||||
delete data.user;
|
||||
delete data.roles;
|
||||
|
||||
if (this.parent) {
|
||||
this.setEntity(data);
|
||||
}
|
||||
|
||||
await this.addToRelationship(id, guild);
|
||||
await this.#adapter.set(this.hashGuildId(id, guild), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async remove(id: string, guild: string): Promise<void> {
|
||||
await this.adapter.remove(this.hashGuildId(id, guild));
|
||||
async items(to: string): Promise<GuildEmojiResource[]> {
|
||||
if (!to && this.parent) {
|
||||
to = this.parent;
|
||||
}
|
||||
|
||||
const data = await this.#adapter.items(this.hashId(to));
|
||||
|
||||
if (data) {
|
||||
return data.map(dt => {
|
||||
const resource = new GuildEmojiResource(this.#adapter, dt);
|
||||
resource.setParent(to);
|
||||
|
||||
return resource;
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async remove(
|
||||
id: string,
|
||||
guild: string | undefined = this.parent
|
||||
): Promise<void> {
|
||||
await this.removeToRelationship(id, guild);
|
||||
await this.#adapter.remove(this.hashGuildId(id, guild));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
protected hashGuildId(id: string, guild?: string): string {
|
||||
if (!guild) {
|
||||
return this.hashId(id);
|
||||
}
|
||||
|
||||
return `${this.#namespace}.${guild}.${id}`;
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,37 @@
|
||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
||||
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||
import type { DiscordMember } from '@biscuitland/api-types';
|
||||
|
||||
import { BaseResource } from './base-resource';
|
||||
import { UserResource } from './user-resource';
|
||||
|
||||
export class GuildMemberResource extends BaseResource {
|
||||
namespace = 'member' as const;
|
||||
/**
|
||||
* Resource represented by an member of discord
|
||||
*/
|
||||
|
||||
adapter: CacheAdapter;
|
||||
users: UserResource;
|
||||
export class GuildMemberResource extends BaseResource<DiscordMember> {
|
||||
#namespace = 'member' as const;
|
||||
|
||||
constructor(adapter: CacheAdapter) {
|
||||
super();
|
||||
#adapter: CacheAdapter;
|
||||
|
||||
this.adapter = adapter;
|
||||
this.users = new UserResource(adapter);
|
||||
#users: UserResource;
|
||||
|
||||
constructor(
|
||||
adapter: CacheAdapter,
|
||||
entity?: DiscordMember | null,
|
||||
parent?: string
|
||||
) {
|
||||
super('member', adapter);
|
||||
|
||||
this.#adapter = adapter;
|
||||
this.#users = new UserResource(adapter);
|
||||
|
||||
if (entity) {
|
||||
this.setEntity(entity);
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
this.setParent(parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -23,12 +40,16 @@ export class GuildMemberResource extends BaseResource {
|
||||
|
||||
async get(
|
||||
id: string,
|
||||
guild: string
|
||||
): Promise<(DiscordMember & { id: string }) | null> {
|
||||
const kv = await this.adapter.get(this.hashGuildId(id, guild));
|
||||
guild: string | undefined = this.parent
|
||||
): Promise<GuildMemberResource | null> {
|
||||
if (this.parent) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const kv = await this.#adapter.get(this.hashGuildId(id, guild));
|
||||
|
||||
if (kv) {
|
||||
return kv;
|
||||
return new GuildMemberResource(this.#adapter, kv, guild);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -40,33 +61,68 @@ export class GuildMemberResource extends BaseResource {
|
||||
|
||||
async set(
|
||||
id: string,
|
||||
guild: string,
|
||||
data: any,
|
||||
expire?: number
|
||||
guild: string | undefined = this.parent,
|
||||
data: any
|
||||
): Promise<void> {
|
||||
if (!data.id) {
|
||||
data.id = id;
|
||||
}
|
||||
|
||||
if (data.user) {
|
||||
await this.users.set(data.user.id, data.user);
|
||||
}
|
||||
|
||||
if (!data.guild_id) {
|
||||
data.guild_id = guild;
|
||||
await this.#users.set(data.user.id, data.user);
|
||||
}
|
||||
|
||||
delete data.user;
|
||||
delete data.roles;
|
||||
|
||||
if (this.parent) {
|
||||
this.setEntity(data);
|
||||
}
|
||||
|
||||
await this.addToRelationship(id, guild);
|
||||
await this.adapter.set(this.hashGuildId(id, guild), data, expire);
|
||||
await this.#adapter.set(this.hashGuildId(id, guild), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async remove(id: string, guild: string): Promise<void> {
|
||||
await this.adapter.remove(this.hashGuildId(id, guild));
|
||||
async items(to: string): Promise<GuildMemberResource[]> {
|
||||
if (!to && this.parent) {
|
||||
to = this.parent;
|
||||
}
|
||||
|
||||
const data = await this.#adapter.items(this.hashId(to));
|
||||
|
||||
if (data) {
|
||||
return data.map(dt => {
|
||||
const resource = new GuildMemberResource(this.#adapter, dt);
|
||||
resource.setParent(to);
|
||||
|
||||
return resource;
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async remove(
|
||||
id: string,
|
||||
guild: string | undefined = this.parent
|
||||
): Promise<void> {
|
||||
await this.removeToRelationship(id, guild);
|
||||
await this.#adapter.remove(this.hashGuildId(id, guild));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
protected hashGuildId(id: string, guild?: string): string {
|
||||
if (!guild) {
|
||||
return this.hashId(id);
|
||||
}
|
||||
|
||||
return `${this.#namespace}.${guild}.${id}`;
|
||||
}
|
||||
}
|
||||
|
275
packages/cache/src/resources/guild-resource.ts
vendored
275
packages/cache/src/resources/guild-resource.ts
vendored
@ -1,4 +1,8 @@
|
||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
||||
/**
|
||||
* refactor
|
||||
*/
|
||||
|
||||
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||
import type { DiscordGuild } from '@biscuitland/api-types';
|
||||
|
||||
import { ChannelResource } from './channel-resource';
|
||||
@ -6,44 +10,90 @@ import { GuildEmojiResource } from './guild-emoji-resource';
|
||||
import { GuildMemberResource } from './guild-member-resource';
|
||||
import { GuildRoleResource } from './guild-role-resource';
|
||||
import { GuildStickerResource } from './guild-sticker-resource';
|
||||
import { VoiceResource } from './voice-resource';
|
||||
import { GuildVoiceResource } from './guild-voice-resource';
|
||||
|
||||
import { PresenceResource } from './presence-resource';
|
||||
import { BaseResource } from './base-resource';
|
||||
|
||||
export class GuildResource extends BaseResource {
|
||||
namespace = 'guild' as const;
|
||||
/**
|
||||
* Resource represented by an guild of discord
|
||||
*/
|
||||
|
||||
adapter: CacheAdapter;
|
||||
export class GuildResource extends BaseResource<DiscordGuild> {
|
||||
#namespace = 'guild' as const;
|
||||
|
||||
private channels: ChannelResource;
|
||||
private emojis: GuildEmojiResource;
|
||||
private members: GuildMemberResource;
|
||||
private roles: GuildRoleResource;
|
||||
private stickers: GuildStickerResource;
|
||||
private voices: VoiceResource;
|
||||
#adapter: CacheAdapter;
|
||||
|
||||
constructor(adapter: CacheAdapter) {
|
||||
super();
|
||||
#channels: ChannelResource;
|
||||
#emojis: GuildEmojiResource;
|
||||
#members: GuildMemberResource;
|
||||
#roles: GuildRoleResource;
|
||||
#stickers: GuildStickerResource;
|
||||
#voices: GuildVoiceResource;
|
||||
|
||||
this.adapter = adapter;
|
||||
#presences: PresenceResource;
|
||||
|
||||
this.channels = new ChannelResource(adapter);
|
||||
this.emojis = new GuildEmojiResource(adapter);
|
||||
this.members = new GuildMemberResource(adapter);
|
||||
this.roles = new GuildRoleResource(adapter);
|
||||
this.stickers = new GuildStickerResource(adapter);
|
||||
this.voices = new VoiceResource(adapter);
|
||||
constructor(
|
||||
adapter: CacheAdapter,
|
||||
entity?: DiscordGuild | null,
|
||||
parent?: string,
|
||||
channels?: ChannelResource,
|
||||
emojis?: GuildEmojiResource,
|
||||
members?: GuildMemberResource,
|
||||
roles?: GuildRoleResource,
|
||||
stickers?: GuildStickerResource,
|
||||
voices?: GuildVoiceResource,
|
||||
presences?: PresenceResource
|
||||
) {
|
||||
super('guild', adapter);
|
||||
|
||||
this.#adapter = adapter;
|
||||
|
||||
this.#channels = channels ?? new ChannelResource(adapter);
|
||||
|
||||
this.#emojis = emojis ?? new GuildEmojiResource(adapter);
|
||||
this.#members = members ?? new GuildMemberResource(adapter);
|
||||
|
||||
this.#roles = roles ?? new GuildRoleResource(adapter);
|
||||
|
||||
this.#stickers = stickers ?? new GuildStickerResource(adapter);
|
||||
|
||||
this.#voices = voices ?? new GuildVoiceResource(adapter);
|
||||
this.#presences = presences ?? new PresenceResource(adapter);
|
||||
|
||||
if (entity) {
|
||||
this.setEntity(entity);
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
this.setParent(parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async get(id: string): Promise<DiscordGuild | null> {
|
||||
const kv = await this.adapter.get(this.hashId(id));
|
||||
async get(id: string): Promise<GuildResource | null> {
|
||||
if (this.parent) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const kv = await this.#adapter.get(this.hashId(id));
|
||||
|
||||
if (kv) {
|
||||
return kv;
|
||||
return new GuildResource(
|
||||
this.#adapter,
|
||||
kv,
|
||||
id,
|
||||
new ChannelResource(this.#adapter),
|
||||
new GuildEmojiResource(this.#adapter, null, id),
|
||||
new GuildMemberResource(this.#adapter, null, id),
|
||||
new GuildRoleResource(this.#adapter, null, id),
|
||||
new GuildStickerResource(this.#adapter, null, id),
|
||||
new GuildVoiceResource(this.#adapter, null, id),
|
||||
new PresenceResource(this.#adapter)
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -53,83 +103,125 @@ export class GuildResource extends BaseResource {
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async set(id: string, data: any, expire?: number): Promise<void> {
|
||||
async set(id: string, data: any): Promise<void> {
|
||||
if (data.channels) {
|
||||
const channels: (Promise<any> | undefined)[] = [];
|
||||
const channels: unknown[] = [];
|
||||
|
||||
for (const channel of data.channels) {
|
||||
await this.channels.set(channel.id, channel);
|
||||
channel.guild_id = id;
|
||||
|
||||
await this.#channels.set(channel.id, channel);
|
||||
}
|
||||
|
||||
await Promise.all(channels);
|
||||
}
|
||||
|
||||
if (data.emojis) {
|
||||
const emojis: unknown[] = [];
|
||||
|
||||
for (const emoji of data.emojis) {
|
||||
emoji.guild_id = id;
|
||||
|
||||
await this.#emojis.set(emoji.id, id, emoji);
|
||||
}
|
||||
|
||||
await Promise.all(emojis);
|
||||
}
|
||||
|
||||
if (data.members) {
|
||||
const members: (Promise<any> | undefined)[] = [];
|
||||
const members: unknown[] = [];
|
||||
|
||||
for (const member of data.members) {
|
||||
await this.members.set(member.user.id, id, member);
|
||||
member.guild_id = id;
|
||||
|
||||
await this.#members.set(member.user.id, id, member);
|
||||
}
|
||||
|
||||
await Promise.all(members);
|
||||
}
|
||||
|
||||
if (data.roles) {
|
||||
const roles: (Promise<any> | undefined)[] = [];
|
||||
const roles: unknown[] = [];
|
||||
|
||||
for (const role of data.roles) {
|
||||
await this.roles.set(role.id, id, role);
|
||||
role.guild_id = id;
|
||||
|
||||
await this.#roles.set(role.id, id, role);
|
||||
}
|
||||
|
||||
await Promise.all(roles);
|
||||
}
|
||||
|
||||
if (data.stickers) {
|
||||
const stickers: (Promise<any> | undefined)[] = [];
|
||||
const stickers: unknown[] = [];
|
||||
|
||||
for (const sticker of data.stickers) {
|
||||
await this.stickers.set(sticker.id, id, sticker);
|
||||
sticker.guild_id = id;
|
||||
|
||||
await this.#stickers.set(sticker.id, id, sticker);
|
||||
}
|
||||
|
||||
await Promise.all(stickers);
|
||||
}
|
||||
|
||||
if (data.emojis) {
|
||||
const emojis: (Promise<any> | undefined)[] = [];
|
||||
|
||||
for (const emoji of data.emojis) {
|
||||
await this.emojis.set(emoji.id, id, emoji);
|
||||
}
|
||||
|
||||
await Promise.all(emojis);
|
||||
}
|
||||
|
||||
if (data.voice_states) {
|
||||
const voices: Promise<any>[] = [];
|
||||
const voices: unknown[] = [];
|
||||
|
||||
for (const voice of data.voice_states) {
|
||||
if (!voice.guild_id) {
|
||||
voice.guild_id = id;
|
||||
}
|
||||
voice.guild_id = id;
|
||||
|
||||
voices.push(this.voices.set(voice.user_id, id, voice));
|
||||
voices.push(this.#voices.set(voice.user_id, id, voice));
|
||||
}
|
||||
|
||||
await Promise.all(voices);
|
||||
}
|
||||
|
||||
if (data.presences) {
|
||||
const presences: unknown[] = [];
|
||||
|
||||
for (const presence of data.presences) {
|
||||
await this.#presences.set(presence.user.id, presence);
|
||||
}
|
||||
|
||||
await Promise.all(presences);
|
||||
}
|
||||
|
||||
delete data.channels;
|
||||
delete data.emojis;
|
||||
delete data.members;
|
||||
delete data.roles;
|
||||
delete data.stickers;
|
||||
delete data.emojis;
|
||||
|
||||
delete data.voice_states;
|
||||
delete data.guild_hashes;
|
||||
|
||||
delete data.presences;
|
||||
|
||||
delete data.voice_states;
|
||||
if (this.parent) {
|
||||
this.setEntity(data);
|
||||
}
|
||||
|
||||
await this.addToRelationship(id);
|
||||
await this.adapter.set(this.hashId(id), data, expire);
|
||||
await this.#adapter.set(this.hashId(id), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async items(): Promise<GuildResource[]> {
|
||||
const data = await this.#adapter.items(this.#namespace);
|
||||
|
||||
if (data) {
|
||||
return data.map(dt => {
|
||||
const resource = new GuildResource(this.#adapter, dt);
|
||||
resource.setParent(resource.id);
|
||||
|
||||
return resource;
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,7 +229,7 @@ export class GuildResource extends BaseResource {
|
||||
*/
|
||||
|
||||
async count(): Promise<number> {
|
||||
return await this.adapter.count(this.namespace);
|
||||
return await this.#adapter.count(this.#namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,7 +237,32 @@ export class GuildResource extends BaseResource {
|
||||
*/
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
await this.adapter.remove(this.hashId(id));
|
||||
const members = await this.#members.getToRelationship(id);
|
||||
|
||||
for (const member of members) {
|
||||
await this.#members.remove(member, id);
|
||||
}
|
||||
|
||||
const roles = await this.#roles.getToRelationship(id);
|
||||
|
||||
for (const role of roles) {
|
||||
await this.#roles.remove(role, id);
|
||||
}
|
||||
|
||||
const emojis = await this.#emojis.getToRelationship(id);
|
||||
|
||||
for (const emoji of emojis) {
|
||||
await this.#emojis.remove(emoji, id);
|
||||
}
|
||||
|
||||
const stickers = await this.#stickers.getToRelationship(id);
|
||||
|
||||
for (const sticker of stickers) {
|
||||
await this.#stickers.remove(sticker, id);
|
||||
}
|
||||
|
||||
await this.removeToRelationship(id);
|
||||
await this.#adapter.remove(this.hashId(id));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,7 +270,7 @@ export class GuildResource extends BaseResource {
|
||||
*/
|
||||
|
||||
async contains(id: string): Promise<boolean> {
|
||||
return await this.adapter.contains(this.namespace, id);
|
||||
return await this.#adapter.contains(this.#namespace, id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -161,7 +278,7 @@ export class GuildResource extends BaseResource {
|
||||
*/
|
||||
|
||||
async getToRelationship(): Promise<string[]> {
|
||||
return await this.adapter.getToRelationship(this.namespace);
|
||||
return await this.#adapter.getToRelationship(this.#namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,6 +286,54 @@ export class GuildResource extends BaseResource {
|
||||
*/
|
||||
|
||||
async addToRelationship(id: string): Promise<void> {
|
||||
await this.adapter.addToRelationship(this.namespace, id);
|
||||
await this.#adapter.addToRelationship(this.#namespace, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async removeToRelationship(id: string): Promise<void> {
|
||||
await this.#adapter.removeToRelationship(this.#namespace, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async getEmojis(): Promise<GuildEmojiResource[]> {
|
||||
return await this.#emojis.items(this.parent as string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async getMembers(): Promise<GuildMemberResource[]> {
|
||||
return await this.#members.items(this.parent as string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async getRoles(): Promise<GuildRoleResource[]> {
|
||||
return await this.#roles.items(this.parent as string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async getStickers(): Promise<GuildStickerResource[]> {
|
||||
return await this.#stickers.items(this.parent as string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async getVoiceStates(): Promise<GuildVoiceResource[]> {
|
||||
return await this.#voices.items(this.parent as string);
|
||||
}
|
||||
}
|
||||
|
106
packages/cache/src/resources/guild-role-resource.ts
vendored
106
packages/cache/src/resources/guild-role-resource.ts
vendored
@ -1,28 +1,51 @@
|
||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
||||
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||
import type { DiscordRole } from '@biscuitland/api-types';
|
||||
|
||||
import { BaseResource } from './base-resource';
|
||||
|
||||
export class GuildRoleResource extends BaseResource {
|
||||
namespace = 'role' as const;
|
||||
/**
|
||||
* Resource represented by an role of discord
|
||||
*/
|
||||
|
||||
adapter: CacheAdapter;
|
||||
export class GuildRoleResource extends BaseResource<DiscordRole> {
|
||||
#namespace = 'role' as const;
|
||||
|
||||
constructor(adapter: CacheAdapter) {
|
||||
super();
|
||||
#adapter: CacheAdapter;
|
||||
|
||||
this.adapter = adapter;
|
||||
constructor(
|
||||
adapter: CacheAdapter,
|
||||
entity?: DiscordRole | null,
|
||||
parent?: string
|
||||
) {
|
||||
super('role', adapter);
|
||||
|
||||
this.#adapter = adapter;
|
||||
|
||||
if (entity) {
|
||||
this.setEntity(entity);
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
this.setParent(parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async get(id: string, guild: string): Promise<DiscordRole | null> {
|
||||
const kv = await this.adapter.get(this.hashGuildId(id, guild));
|
||||
async get(
|
||||
id: string,
|
||||
guild: string | undefined = this.parent
|
||||
): Promise<GuildRoleResource | null> {
|
||||
if (this.parent) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const kv = await this.#adapter.get(this.hashGuildId(id, guild));
|
||||
|
||||
if (kv) {
|
||||
return kv;
|
||||
return new GuildRoleResource(this.#adapter, kv, guild);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -34,9 +57,8 @@ export class GuildRoleResource extends BaseResource {
|
||||
|
||||
async set(
|
||||
id: string,
|
||||
guild: string,
|
||||
data: any,
|
||||
expire?: number
|
||||
guild: string | undefined = this.parent,
|
||||
data: any
|
||||
): Promise<void> {
|
||||
if (!data.id) {
|
||||
data.id = id;
|
||||
@ -46,14 +68,66 @@ export class GuildRoleResource extends BaseResource {
|
||||
data.guild_id = guild;
|
||||
}
|
||||
|
||||
await this.adapter.set(this.hashGuildId(id, guild), data, expire);
|
||||
if (this.parent) {
|
||||
this.setEntity(data);
|
||||
}
|
||||
|
||||
await this.addToRelationship(id, guild);
|
||||
await this.#adapter.set(this.hashGuildId(id, guild), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async remove(id: string, guild: string): Promise<void> {
|
||||
await this.adapter.remove(this.hashGuildId(id, guild));
|
||||
async count(): Promise<number> {
|
||||
return await this.#adapter.count(this.#namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async items(to: string): Promise<GuildRoleResource[]> {
|
||||
if (!to && this.parent) {
|
||||
to = this.parent;
|
||||
}
|
||||
|
||||
const data = await this.#adapter.items(this.hashId(to));
|
||||
|
||||
if (data) {
|
||||
return data.map(dt => {
|
||||
const resource = new GuildRoleResource(this.#adapter, dt);
|
||||
resource.setParent(to);
|
||||
|
||||
return resource;
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async remove(
|
||||
id: string,
|
||||
guild: string | undefined = this.parent
|
||||
): Promise<void> {
|
||||
await this.removeToRelationship(id, guild);
|
||||
await this.#adapter.remove(this.hashGuildId(id, guild));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
protected hashGuildId(id: string, guild?: string): string {
|
||||
if (!guild) {
|
||||
return this.hashId(id);
|
||||
}
|
||||
|
||||
return `${this.#namespace}.${guild}.${id}`;
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,52 @@
|
||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
||||
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||
import type { DiscordSticker } from '@biscuitland/api-types';
|
||||
|
||||
import { BaseResource } from './base-resource';
|
||||
import { UserResource } from './user-resource';
|
||||
|
||||
export class GuildStickerResource extends BaseResource {
|
||||
namespace = 'sticker' as const;
|
||||
/**
|
||||
* Resource represented by an sticker of discord
|
||||
*/
|
||||
|
||||
adapter: CacheAdapter;
|
||||
export class GuildStickerResource extends BaseResource<DiscordSticker> {
|
||||
#namespace = 'sticker' as const;
|
||||
|
||||
constructor(adapter: CacheAdapter) {
|
||||
super();
|
||||
#adapter: CacheAdapter;
|
||||
|
||||
this.adapter = adapter;
|
||||
#users: UserResource;
|
||||
|
||||
constructor(
|
||||
adapter: CacheAdapter,
|
||||
entity?: DiscordSticker | null,
|
||||
parent?: string
|
||||
) {
|
||||
super('sticker', adapter);
|
||||
|
||||
this.#adapter = adapter;
|
||||
this.#users = new UserResource(adapter);
|
||||
|
||||
if (entity) {
|
||||
this.setEntity(entity);
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
this.setParent(parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async get(id: string, guild: string): Promise<DiscordSticker | null> {
|
||||
const kv = await this.adapter.get(this.hashGuildId(id, guild));
|
||||
async get(id: string, guild: string): Promise<GuildStickerResource | null> {
|
||||
if (this.parent) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const kv = await this.#adapter.get(this.hashGuildId(id, guild));
|
||||
|
||||
if (kv) {
|
||||
return kv;
|
||||
return new GuildStickerResource(this.#adapter, kv, guild);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -34,26 +58,67 @@ export class GuildStickerResource extends BaseResource {
|
||||
|
||||
async set(
|
||||
id: string,
|
||||
guild: string,
|
||||
data: any,
|
||||
expire?: number
|
||||
guild: string | undefined = this.parent,
|
||||
data: any
|
||||
): Promise<void> {
|
||||
if (!data.id) {
|
||||
data.id = id;
|
||||
if (data.user) {
|
||||
await this.#users.set(data.user.id, data.user);
|
||||
}
|
||||
|
||||
if (!data.guild_id) {
|
||||
data.guild_id = guild;
|
||||
delete data.user;
|
||||
|
||||
if (this.parent) {
|
||||
this.setEntity(data);
|
||||
}
|
||||
|
||||
await this.adapter.set(this.hashGuildId(id, guild), data, expire);
|
||||
await this.addToRelationship(id, guild);
|
||||
await this.#adapter.set(this.hashGuildId(id, guild), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async remove(id: string, guild: string): Promise<void> {
|
||||
await this.adapter.remove(this.hashGuildId(id, guild));
|
||||
async items(to: string): Promise<GuildStickerResource[]> {
|
||||
if (!to && this.parent) {
|
||||
to = this.parent;
|
||||
}
|
||||
|
||||
const data = await this.#adapter.items(this.hashId(to));
|
||||
|
||||
if (data) {
|
||||
return data.map(dt => {
|
||||
const resource = new GuildStickerResource(this.#adapter, dt);
|
||||
resource.setParent(to);
|
||||
|
||||
return resource;
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async remove(
|
||||
id: string,
|
||||
guild: string | undefined = this.parent
|
||||
): Promise<void> {
|
||||
await this.removeToRelationship(id, guild);
|
||||
await this.#adapter.remove(this.hashGuildId(id, guild));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
protected hashGuildId(id: string, guild?: string): string {
|
||||
if (!guild) {
|
||||
return this.hashId(id);
|
||||
}
|
||||
|
||||
return `${this.#namespace}.${guild}.${id}`;
|
||||
}
|
||||
}
|
||||
|
127
packages/cache/src/resources/guild-voice-resource.ts
vendored
Normal file
127
packages/cache/src/resources/guild-voice-resource.ts
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
/**
|
||||
* refactor
|
||||
*/
|
||||
|
||||
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||
import type { DiscordVoiceState } from '@biscuitland/api-types';
|
||||
|
||||
import { BaseResource } from './base-resource';
|
||||
|
||||
/**
|
||||
* Resource represented by an voice state of discord
|
||||
*/
|
||||
|
||||
export class GuildVoiceResource extends BaseResource<DiscordVoiceState> {
|
||||
#namespace = 'voice' as const;
|
||||
|
||||
#adapter: CacheAdapter;
|
||||
|
||||
constructor(
|
||||
adapter: CacheAdapter,
|
||||
entity?: DiscordVoiceState | null,
|
||||
parent?: string
|
||||
) {
|
||||
super('voice', adapter);
|
||||
|
||||
this.#adapter = adapter;
|
||||
|
||||
if (entity) {
|
||||
this.setEntity(entity);
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
this.setParent(parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async get(
|
||||
id: string,
|
||||
guild: string | undefined = this.parent
|
||||
): Promise<GuildVoiceResource | null> {
|
||||
if (this.parent) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const kv = await this.#adapter.get(this.hashGuildId(id, guild));
|
||||
|
||||
if (kv) {
|
||||
return new GuildVoiceResource(this.#adapter, kv, guild);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async set(
|
||||
id: string,
|
||||
guild: string | undefined = this.parent,
|
||||
data: any
|
||||
): Promise<void> {
|
||||
if (!data.guild_id) {
|
||||
data.guild_id = guild;
|
||||
}
|
||||
|
||||
delete data.member;
|
||||
|
||||
if (this.parent) {
|
||||
this.setEntity(data);
|
||||
}
|
||||
|
||||
await this.addToRelationship(id, guild);
|
||||
await this.#adapter.set(this.hashGuildId(id, guild), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async items(to: string): Promise<GuildVoiceResource[]> {
|
||||
if (!to && this.parent) {
|
||||
to = this.parent;
|
||||
}
|
||||
|
||||
const data = await this.#adapter.items(this.hashId(to));
|
||||
|
||||
if (data) {
|
||||
return data.map(dt => {
|
||||
const resource = new GuildVoiceResource(this.#adapter, dt);
|
||||
resource.setParent(to);
|
||||
|
||||
return resource;
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async remove(
|
||||
id: string,
|
||||
guild: string | undefined = this.parent
|
||||
): Promise<void> {
|
||||
await this.removeToRelationship(id, guild);
|
||||
await this.#adapter.remove(this.hashGuildId(id, guild));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
protected hashGuildId(id: string, guild?: string): string {
|
||||
if (!guild) {
|
||||
return this.hashId(id);
|
||||
}
|
||||
|
||||
return `${this.#namespace}.${guild}.${id}`;
|
||||
}
|
||||
}
|
6
packages/cache/src/resources/index.ts
vendored
6
packages/cache/src/resources/index.ts
vendored
@ -7,7 +7,9 @@ export { GuildMemberResource } from './guild-member-resource';
|
||||
export { GuildResource } from './guild-resource';
|
||||
|
||||
export { GuildRoleResource } from './guild-role-resource';
|
||||
export { GuildStickerResource } from './guild-sticker-resource';
|
||||
|
||||
export { GuildStickerResource } from './guild-sticker-resource';
|
||||
export { GuildVoiceResource } from './guild-voice-resource';
|
||||
|
||||
export { PresenceResource } from './presence-resource';
|
||||
export { UserResource } from './user-resource';
|
||||
export { VoiceResource } from './voice-resource';
|
||||
|
135
packages/cache/src/resources/presence-resource.ts
vendored
Normal file
135
packages/cache/src/resources/presence-resource.ts
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
/**
|
||||
* refactor
|
||||
*/
|
||||
|
||||
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||
import type { DiscordPresenceUpdate } from '@biscuitland/api-types';
|
||||
|
||||
import { BaseResource } from './base-resource';
|
||||
import { UserResource } from './user-resource';
|
||||
|
||||
/**
|
||||
* Resource represented by an presence of discord
|
||||
*/
|
||||
|
||||
export class PresenceResource extends BaseResource<DiscordPresenceUpdate> {
|
||||
#namespace = 'presence' as const;
|
||||
|
||||
#adapter: CacheAdapter;
|
||||
|
||||
#users: UserResource;
|
||||
|
||||
constructor(adapter: CacheAdapter, entity?: DiscordPresenceUpdate | null) {
|
||||
super('presence', adapter);
|
||||
|
||||
this.#adapter = adapter;
|
||||
this.#users = new UserResource(this.#adapter);
|
||||
|
||||
if (entity) {
|
||||
this.setEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async get(id: string): Promise<PresenceResource | null> {
|
||||
if (this.parent) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const kv = await this.#adapter.get(this.hashId(id));
|
||||
|
||||
if (kv) {
|
||||
return new PresenceResource(this.#adapter, kv);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async set(id: string, data: any): Promise<void> {
|
||||
if (data.user) {
|
||||
await this.#users.set(data.user.id, data.user);
|
||||
}
|
||||
|
||||
delete data.user;
|
||||
delete data.roles;
|
||||
|
||||
delete data.guild_id;
|
||||
|
||||
if (this.parent) {
|
||||
this.setEntity(data);
|
||||
}
|
||||
|
||||
await this.addToRelationship(id);
|
||||
await this.#adapter.set(this.hashId(id), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async items(): Promise<PresenceResource[]> {
|
||||
const data = await this.#adapter.items(this.#namespace);
|
||||
|
||||
if (data) {
|
||||
return data.map(dt => new PresenceResource(this.#adapter, dt));
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async count(): Promise<number> {
|
||||
return await this.#adapter.count(this.#namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
await this.removeToRelationship(id);
|
||||
await this.#adapter.remove(this.hashId(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async contains(id: string): Promise<boolean> {
|
||||
return await this.#adapter.contains(this.#namespace, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async getToRelationship(): Promise<string[]> {
|
||||
return await this.#adapter.getToRelationship(this.#namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async addToRelationship(id: string): Promise<void> {
|
||||
await this.#adapter.addToRelationship(this.#namespace, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async removeToRelationship(id: string): Promise<void> {
|
||||
await this.#adapter.removeToRelationship(this.#namespace, id);
|
||||
}
|
||||
}
|
102
packages/cache/src/resources/user-resource.ts
vendored
102
packages/cache/src/resources/user-resource.ts
vendored
@ -1,28 +1,44 @@
|
||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
||||
/**
|
||||
* refactor
|
||||
*/
|
||||
|
||||
import type { CacheAdapter } from '../scheme/adapters/cache-adapter';
|
||||
import type { DiscordUser } from '@biscuitland/api-types';
|
||||
|
||||
import { BaseResource } from './base-resource';
|
||||
|
||||
export class UserResource extends BaseResource {
|
||||
namespace = 'user' as const;
|
||||
/**
|
||||
* Resource represented by an user of discord
|
||||
*/
|
||||
|
||||
adapter: CacheAdapter;
|
||||
export class UserResource extends BaseResource<DiscordUser> {
|
||||
#namespace = 'user' as const;
|
||||
|
||||
constructor(adapter: CacheAdapter) {
|
||||
super();
|
||||
#adapter: CacheAdapter;
|
||||
|
||||
this.adapter = adapter;
|
||||
constructor(adapter: CacheAdapter, entity?: DiscordUser | null) {
|
||||
super('user', adapter);
|
||||
|
||||
this.#adapter = adapter;
|
||||
|
||||
if (entity) {
|
||||
this.setEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async get(id: string): Promise<DiscordUser | null> {
|
||||
const kv = await this.adapter.get(this.hashId(id));
|
||||
async get(id: string): Promise<UserResource | null> {
|
||||
if (this.parent) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const kv = await this.#adapter.get(this.hashId(id));
|
||||
|
||||
if (kv) {
|
||||
return kv;
|
||||
return new UserResource(this.#adapter, kv);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -32,8 +48,35 @@ export class UserResource extends BaseResource {
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async set(id: string, data: any, expire?: number): Promise<void> {
|
||||
await this.adapter.set(this.hashId(id), data, expire);
|
||||
async set(id: string, data: any): Promise<void> {
|
||||
if (this.parent) {
|
||||
this.setEntity(data);
|
||||
}
|
||||
|
||||
await this.addToRelationship(id);
|
||||
await this.#adapter.set(this.hashId(id), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async items(): Promise<UserResource[]> {
|
||||
const data = await this.#adapter.items(this.#namespace);
|
||||
|
||||
if (data) {
|
||||
return data.map(dt => new UserResource(this.#adapter, dt));
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async count(): Promise<number> {
|
||||
return await this.#adapter.count(this.#namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -41,6 +84,39 @@ export class UserResource extends BaseResource {
|
||||
*/
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
await this.adapter.remove(this.hashId(id));
|
||||
await this.removeToRelationship(id);
|
||||
await this.#adapter.remove(this.hashId(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async contains(id: string): Promise<boolean> {
|
||||
return await this.#adapter.contains(this.#namespace, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async getToRelationship(): Promise<string[]> {
|
||||
return await this.#adapter.getToRelationship(this.#namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async addToRelationship(id: string): Promise<void> {
|
||||
await this.#adapter.addToRelationship(this.#namespace, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async removeToRelationship(id: string): Promise<void> {
|
||||
await this.#adapter.removeToRelationship(this.#namespace, id);
|
||||
}
|
||||
}
|
||||
|
57
packages/cache/src/resources/voice-resource.ts
vendored
57
packages/cache/src/resources/voice-resource.ts
vendored
@ -1,57 +0,0 @@
|
||||
import type { CacheAdapter } from '../adapters/cache-adapter';
|
||||
import type { DiscordVoiceState } from '@biscuitland/api-types';
|
||||
|
||||
import { BaseResource } from './base-resource';
|
||||
|
||||
export class VoiceResource extends BaseResource {
|
||||
namespace = 'voice' as const;
|
||||
|
||||
adapter: CacheAdapter;
|
||||
|
||||
constructor(adapter: CacheAdapter) {
|
||||
super();
|
||||
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async get(id: string, guild: string): Promise<DiscordVoiceState | null> {
|
||||
const kv = await this.adapter.get(this.hashGuildId(id, guild));
|
||||
|
||||
if (kv) {
|
||||
return kv;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async set(
|
||||
id: string,
|
||||
guild: string,
|
||||
data: any,
|
||||
expire?: number
|
||||
): Promise<void> {
|
||||
if (!data.guild_id) {
|
||||
data.guild_id = guild;
|
||||
}
|
||||
|
||||
delete data.member;
|
||||
|
||||
await this.adapter.set(this.hashGuildId(id, guild), data, expire);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async remove(id: string, guild: string): Promise<void> {
|
||||
await this.adapter.remove(this.hashGuildId(id, guild));
|
||||
}
|
||||
}
|
63
packages/cache/src/scheme/adapters/cache-adapter.ts
vendored
Normal file
63
packages/cache/src/scheme/adapters/cache-adapter.ts
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Base class for all adapters
|
||||
* All Methods from CacheAdapter are also available on every class extends
|
||||
*/
|
||||
|
||||
export interface CacheAdapter {
|
||||
/**
|
||||
* Gets the resource to adapter
|
||||
*/
|
||||
|
||||
get(id: string): any | Promise<any>;
|
||||
get(id: string, guild: string): string | Promise<string>;
|
||||
|
||||
/**
|
||||
* Sets the resource to adapter
|
||||
*/
|
||||
|
||||
set(id: string, data: any): void | Promise<void>;
|
||||
set(id: string, guild: string, data: any): void | Promise<void>;
|
||||
|
||||
/**
|
||||
* Get the items of a relationship
|
||||
*/
|
||||
|
||||
items(to?: string): any[] | Promise<any[]>;
|
||||
|
||||
/**
|
||||
* Count how many resources there are in the relationships
|
||||
*/
|
||||
|
||||
count(to: string): number | Promise<number>;
|
||||
|
||||
/**
|
||||
* Removes the adapter resource
|
||||
*/
|
||||
|
||||
remove(id: string): void | Promise<void>;
|
||||
remove(id: string, guild: string): void | Promise<void>;
|
||||
|
||||
/**
|
||||
* Check if the resource is in the relationships
|
||||
*/
|
||||
|
||||
contains(to: string, id: string): boolean | Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Gets the resource relationships
|
||||
*/
|
||||
|
||||
getToRelationship(to: string): string[] | Promise<string[]>;
|
||||
|
||||
/**
|
||||
* Adds the resource to relationships
|
||||
*/
|
||||
|
||||
addToRelationship(to: string, id: string): void | Promise<void>;
|
||||
|
||||
/**
|
||||
* Removes the relationship resource
|
||||
*/
|
||||
|
||||
removeToRelationship(to: string, id: string): void | Promise<void>;
|
||||
}
|
@ -1,20 +1,24 @@
|
||||
import type { CacheAdapter } from './cache-adapter';
|
||||
/**
|
||||
* refactor
|
||||
*/
|
||||
|
||||
interface Options {
|
||||
expire?: number;
|
||||
}
|
||||
import type { CacheAdapter } from './cache-adapter';
|
||||
import type { MemoryOptions, MO } from '../../types';
|
||||
|
||||
import { Options } from '../../utils/options';
|
||||
|
||||
export class MemoryCacheAdapter implements CacheAdapter {
|
||||
private static readonly DEFAULTS = {
|
||||
static readonly DEFAULTS = {
|
||||
expire: 3600000,
|
||||
};
|
||||
|
||||
private readonly relationships = new Map<string, string[]>();
|
||||
private readonly storage = new Map<string, { data: any; expire?: number }>();
|
||||
readonly relationships = new Map<string, string[]>();
|
||||
readonly storage = new Map<string, { data: any; expire?: number }>();
|
||||
|
||||
readonly options: Options;
|
||||
readonly options: MO;
|
||||
|
||||
constructor(options?: Options) {
|
||||
this.options = Object.assign(MemoryCacheAdapter.DEFAULTS, options);
|
||||
constructor(options?: MemoryOptions) {
|
||||
this.options = Options({}, MemoryCacheAdapter.DEFAULTS, options);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -39,14 +43,40 @@ export class MemoryCacheAdapter implements CacheAdapter {
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
set(id: string, data: any, expire = this.options.expire): void {
|
||||
set(id: string, data: any): void {
|
||||
const expire = this.options.expire;
|
||||
|
||||
if (expire) {
|
||||
this.storage.set(id, { data: JSON.stringify(data), expire: Date.now() + expire });
|
||||
this.storage.set(id, {
|
||||
data: JSON.stringify(data),
|
||||
expire: Date.now() + expire,
|
||||
});
|
||||
} else {
|
||||
this.storage.set(id, { data: JSON.stringify(data) });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
items(to: string): any[] {
|
||||
const array: unknown[] = [];
|
||||
let data = this.getToRelationship(to);
|
||||
|
||||
data = data.map(id => `${to}.${id}`);
|
||||
|
||||
for (const key of data) {
|
||||
const content = this.get(key);
|
||||
|
||||
if (content) {
|
||||
array.push(content);
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
195
packages/cache/src/scheme/adapters/redis-cache-adapter.ts
vendored
Normal file
195
packages/cache/src/scheme/adapters/redis-cache-adapter.ts
vendored
Normal file
@ -0,0 +1,195 @@
|
||||
/**
|
||||
* refactor
|
||||
*/
|
||||
|
||||
import type { CacheAdapter } from './cache-adapter';
|
||||
|
||||
import type { RedisOptions } from 'ioredis';
|
||||
import type Redis from 'ioredis';
|
||||
import IORedis from 'ioredis';
|
||||
|
||||
interface BaseOptions {
|
||||
namespace: string;
|
||||
expire?: number;
|
||||
}
|
||||
|
||||
interface BuildOptions extends BaseOptions, RedisOptions {}
|
||||
|
||||
interface ClientOptions extends BaseOptions {
|
||||
client: Redis;
|
||||
}
|
||||
|
||||
type Options = BuildOptions | ClientOptions;
|
||||
|
||||
export class RedisCacheAdapter implements CacheAdapter {
|
||||
static readonly DEFAULTS = {
|
||||
namespace: 'biscuitland',
|
||||
};
|
||||
|
||||
readonly options: Options;
|
||||
|
||||
readonly client: Redis;
|
||||
|
||||
constructor(options?: Options) {
|
||||
this.options = Object.assign(RedisCacheAdapter.DEFAULTS, options);
|
||||
|
||||
if ((this.options as ClientOptions).client) {
|
||||
this.client = (this.options as ClientOptions).client;
|
||||
} else {
|
||||
const { ...redisOpt } = this.options as BuildOptions;
|
||||
this.client = new IORedis(redisOpt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async get(id: string): Promise<any> {
|
||||
const data = await this.client.get(this.build(id));
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return JSON.parse(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async set(id: string, data: unknown): Promise<void> {
|
||||
const expire = this.options.expire;
|
||||
|
||||
if (expire) {
|
||||
await this.client.set(
|
||||
this.build(id),
|
||||
JSON.stringify(data),
|
||||
'EX',
|
||||
expire
|
||||
);
|
||||
} else {
|
||||
await this.client.set(this.build(id), JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async items(to: string): Promise<any[]> {
|
||||
const array: unknown[] = [];
|
||||
|
||||
let data = await this.getToRelationship(to);
|
||||
data = data.map(id => this.build(`${to}.${id}`));
|
||||
|
||||
if (data && data.length > 0) {
|
||||
const items = await this.client.mget(data);
|
||||
|
||||
for (const item of items) {
|
||||
if (item) {
|
||||
array.push(JSON.parse(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async count(to: string): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.client.scard(this.build(to), (err, result) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return resolve(result || 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async remove(id: string): Promise<void> {
|
||||
await this.client.del(this.build(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async contains(to: string, id: string): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.client.sismember(this.build(to), id, (err, result) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return resolve(result === 1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async getToRelationship(to: string): Promise<string[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.client.smembers(this.build(to), (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
resolve(result || []);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async addToRelationship(to: string, id: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.client.sadd(this.build(to), id, err => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
async removeToRelationship(to: string, id: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.client.srem(this.build(to), id, err => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
protected build(id: string): string {
|
||||
return `${this.options.namespace}:${id}`;
|
||||
}
|
||||
}
|
7
packages/cache/src/scheme/transporters/base-transporter.ts
vendored
Normal file
7
packages/cache/src/scheme/transporters/base-transporter.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* future update
|
||||
*/
|
||||
|
||||
export interface BaseTransporter {
|
||||
//
|
||||
}
|
3
packages/cache/src/scheme/transporters/redis-transporter.ts
vendored
Normal file
3
packages/cache/src/scheme/transporters/redis-transporter.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
import type { BaseTransporter } from './base-transporter';
|
||||
|
||||
export class RedisTransporter implements BaseTransporter {}
|
3
packages/cache/src/scheme/transporters/tcp-transporter.ts
vendored
Normal file
3
packages/cache/src/scheme/transporters/tcp-transporter.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
import type { BaseTransporter } from './base-transporter';
|
||||
|
||||
export class TcpTransporter implements BaseTransporter {}
|
55
packages/cache/src/types.ts
vendored
Normal file
55
packages/cache/src/types.ts
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
import type { Cache } from './cache';
|
||||
import type { CacheAdapter } from './scheme/adapters/cache-adapter';
|
||||
|
||||
import type { MemoryCacheAdapter } from './scheme/adapters/memory-cache-adapter';
|
||||
|
||||
//
|
||||
|
||||
export type CacheOptions = Pick<
|
||||
CO,
|
||||
Exclude<keyof CO, keyof typeof Cache.DEFAULTS>
|
||||
> &
|
||||
Partial<CO>;
|
||||
|
||||
export interface CO {
|
||||
/**
|
||||
* Adapter to be used for storing resources
|
||||
* @default MemoryCacheAdapter
|
||||
*/
|
||||
|
||||
adapter: CacheAdapter;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
export type MemoryOptions = Pick<
|
||||
MO,
|
||||
Exclude<keyof MO, keyof typeof MemoryCacheAdapter.DEFAULTS>
|
||||
> &
|
||||
Partial<MO>;
|
||||
|
||||
export interface MO {
|
||||
/**
|
||||
* Time the resource will be stored
|
||||
* @default 3600000
|
||||
*/
|
||||
|
||||
expire: number;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
export type RedisOptions = Pick<
|
||||
RO,
|
||||
Exclude<keyof RO, keyof typeof MemoryCacheAdapter.DEFAULTS>
|
||||
> &
|
||||
Partial<RO>;
|
||||
|
||||
export interface RO {
|
||||
/**
|
||||
* Time the resource will be stored
|
||||
* @default 300
|
||||
*/
|
||||
|
||||
expire: number;
|
||||
}
|
48
packages/cache/src/utils/options.ts
vendored
Normal file
48
packages/cache/src/utils/options.ts
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Needs to be moved to a common location
|
||||
* refactor
|
||||
*/
|
||||
|
||||
const isPlainObject = (value: any) => {
|
||||
return (
|
||||
(value !== null &&
|
||||
typeof value === 'object' &&
|
||||
typeof value.constructor === 'function' &&
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
(value.constructor.prototype.hasOwnProperty('isPrototypeOf') ||
|
||||
Object.getPrototypeOf(value.constructor.prototype) === null)) ||
|
||||
(value && Object.getPrototypeOf(value) === null)
|
||||
);
|
||||
};
|
||||
|
||||
const isObject = (o: any) => {
|
||||
return !!o && typeof o === 'object' && !Array.isArray(o);
|
||||
};
|
||||
|
||||
export const Options = (defaults: any, ...options: any[]): any => {
|
||||
if (!options.length) {
|
||||
return defaults;
|
||||
}
|
||||
|
||||
const source = options.shift();
|
||||
|
||||
if (isObject(defaults) && isPlainObject(source)) {
|
||||
Object.entries(source).forEach(([key, value]) => {
|
||||
if (typeof value === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPlainObject(value)) {
|
||||
if (!(key in defaults)) {
|
||||
Object.assign(defaults, { [key]: {} });
|
||||
}
|
||||
|
||||
Options(defaults[key], value);
|
||||
} else {
|
||||
Object.assign(defaults, { [key]: value });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Options(defaults, ...options);
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user