Skip to content

Commit

Permalink
In-Memoryなステート管理として切り出し
Browse files Browse the repository at this point in the history
  • Loading branch information
na2na-p committed Feb 7, 2024
1 parent 9c71b8b commit 7a8c646
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 3 deletions.
6 changes: 6 additions & 0 deletions src/features/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ export {
getVoiceInstance,
} from './internal/Voice/index.js';
export type { Voice } from './internal/Voice/index.js';
export {
getInMemoryStoreInstance,
type InMemoryStore,
type Store,
STORE_TYPES,
} from './internal/Store/index.js';
18 changes: 16 additions & 2 deletions src/features/core/internal/Client/internal/Client.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ import { exit } from 'process';

import type { CommandBase } from '@/features/commands/index.js';
import type { getConfig } from '@/features/config/index.js';
import {
getInMemoryStoreInstance,
type Store,
STORE_TYPES,
} from '@/features/core/index.js';
import type { ChatInputCommandInteraction } from '@/features/library/index.js';
import {
chalk,
Client as DiscordJsClient,
GatewayIntentBits,
InteractionType,
chalk,
} from '@/features/library/index.js';
import { log } from '@/features/others/log/index.js';

Expand All @@ -16,8 +21,9 @@ import type { ClassConstructorArgs } from './Client.types.js';
export class Client extends DiscordJsClient {
readonly #config: ReturnType<typeof getConfig>;
private interactionCommands: ReadonlyArray<CommandBase> = [];
#store: Store;

constructor({ config, commands }: ClassConstructorArgs) {
constructor({ config, commands, storeDriver }: ClassConstructorArgs) {
super({
intents: [
GatewayIntentBits.Guilds,
Expand All @@ -34,6 +40,14 @@ export class Client extends DiscordJsClient {
exit(1);
}

switch (storeDriver) {
case STORE_TYPES.IN_MEMORY:
this.#store = getInMemoryStoreInstance();
break;
default:
throw new Error('Invalid store driver');
}

const commandsRegisteredResult = this.#installModules(commands);

this.on('ready', client => {
Expand Down
2 changes: 2 additions & 0 deletions src/features/core/internal/Client/internal/Client.types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { CommandBase } from '@/features/commands/index.js';
import type { getConfig } from '@/features/config/index.js';
import type { STORE_TYPES } from '@/features/core/index.js';

export type ClassConstructorArgs = {
config: ReturnType<typeof getConfig>;
commands: ReadonlyArray<CommandBase>;
storeDriver: keyof typeof STORE_TYPES;
};
11 changes: 11 additions & 0 deletions src/features/core/internal/Store/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { singleton } from '@/features/others/singleton/index.js';

import { InMemoryStore } from './internal/InMemoryStore.class.js';

export type { Store } from './internal/Store.class.js';
export { STORE_TYPES } from './internal/Store.constants.js';
export type { InMemoryStore };

const createInMemoryStoreInstance = () => new InMemoryStore();

export const getInMemoryStoreInstance = singleton(createInMemoryStoreInstance);
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { Store } from '@/features/core/index.js';
import type { AudioPlayer, VoiceConnection } from '@/features/library/index.js';

import { InMemoryStore } from './InMemoryStore.class.js';

describe('InMemoryStore', () => {
let store: Store;
const guildId = 'guildId123';
const voiceConnection = {} as VoiceConnection;
const audioPlayer = {} as AudioPlayer;

beforeEach(() => {
store = new InMemoryStore();
});

describe('getVoiceConnection', () => {
it('should return undefined for a non-existing guildId', () => {
expect(store.getVoiceConnection(guildId)).toBeUndefined();
});

it('should return the correct VoiceConnection for an existing guildId', () => {
store.setVoiceConnection(guildId, voiceConnection);
expect(store.getVoiceConnection(guildId)).toBe(voiceConnection);
});
});

describe('setVoiceConnection', () => {
it('should set the VoiceConnection for a guildId', () => {
store.setVoiceConnection(guildId, voiceConnection);
expect(store.getVoiceConnection(guildId)).toBe(voiceConnection);
});
});

describe('getVoicePlayer', () => {
it('should return undefined for a non-existing guildId', () => {
expect(store.getVoicePlayer(guildId)).toBeUndefined();
});

it('should return the correct AudioPlayer for an existing guildId', () => {
store.setVoicePlayer(guildId, audioPlayer);
expect(store.getVoicePlayer(guildId)).toBe(audioPlayer);
});
});

describe('setVoicePlayer', () => {
it('should set the AudioPlayer for a guildId', () => {
store.setVoicePlayer(guildId, audioPlayer);
expect(store.getVoicePlayer(guildId)).toBe(audioPlayer);
});
});
});
31 changes: 31 additions & 0 deletions src/features/core/internal/Store/internal/InMemoryStore.class.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type {
AudioPlayer,
Guild,
VoiceConnection,
} from '@/features/library/index.js';

import { Store } from './Store.class.js';

export type VoiceConnections = Map<Guild['id'], VoiceConnection>;
export type VoicePlayers = Map<Guild['id'], AudioPlayer | undefined>;

export class InMemoryStore extends Store {
#voiceConnections: VoiceConnections = new Map();
#voicePlayers: VoicePlayers = new Map();

public getVoiceConnection(guildId: Guild['id']) {
return this.#voiceConnections.get(guildId);
}

public setVoiceConnection(guildId: Guild['id'], connection: VoiceConnection) {
this.#voiceConnections.set(guildId, connection);
}

public getVoicePlayer(guildId: Guild['id']) {
return this.#voicePlayers.get(guildId);
}

public setVoicePlayer(guildId: Guild['id'], player: AudioPlayer) {
this.#voicePlayers.set(guildId, player);
}
}
11 changes: 11 additions & 0 deletions src/features/core/internal/Store/internal/Store.class.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { AudioPlayer, VoiceConnection } from '@/features/library/index.js';

export abstract class Store {
abstract getVoiceConnection(guildId: string): VoiceConnection | undefined;
abstract setVoiceConnection(
guildId: string,
connection: VoiceConnection
): void;
abstract getVoicePlayer(guildId: string): AudioPlayer | undefined;
abstract setVoicePlayer(guildId: string, player: AudioPlayer): void;
}
3 changes: 3 additions & 0 deletions src/features/core/internal/Store/internal/Store.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const STORE_TYPES = {
IN_MEMORY: 'IN_MEMORY',
} as const satisfies Record<string, string>;
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import 'dotenv/config';

import { Ping, VoiceChannel, YouTube } from './features/commands/index.js';
import { getConfig } from './features/config/index.js';
import { Client } from './features/core/index.js';
import { Client, STORE_TYPES } from './features/core/index.js';

new Client({
config: getConfig(),
commands: [new Ping(), new VoiceChannel(), new YouTube()],
storeDriver: STORE_TYPES.IN_MEMORY,
});

0 comments on commit 7a8c646

Please sign in to comment.