refactor water me service
remove "text-based-feature" improve messages service interface implement more features for fluxer
This commit is contained in:
@@ -3,5 +3,5 @@ import { logger } from "lib/common-logger";
|
|||||||
|
|
||||||
export const handleShutdown = async () => {
|
export const handleShutdown = async () => {
|
||||||
logger.info("bot is shutting down...");
|
logger.info("bot is shutting down...");
|
||||||
await logChannelService.sendLogMessage("bot is shutting down...");
|
await logChannelService.sendLogMessage("ich geh schlafen...");
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import type { MessagesServiceInterface } from "@avocadi/bot-core/entities/messages/messages.service";
|
import type { MessagesServiceInterface } from "@avocadi/bot-core/entities/messages/messages.service";
|
||||||
import { createLogger } from "@avocadi/bot-core/lib/logger";
|
import { createLogger } from "@avocadi/bot-core/lib/logger";
|
||||||
import {
|
import {
|
||||||
|
type Channel,
|
||||||
ChannelType,
|
ChannelType,
|
||||||
type DMChannel,
|
type DMChannel,
|
||||||
type Message,
|
type Message,
|
||||||
|
type MessagePayload,
|
||||||
type PartialDMChannel,
|
type PartialDMChannel,
|
||||||
type User,
|
type User,
|
||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
@@ -11,11 +13,11 @@ import { logChannelService } from "features/log-channel/log-channel.service";
|
|||||||
import client from "lib/client";
|
import client from "lib/client";
|
||||||
|
|
||||||
export class MessagesService
|
export class MessagesService
|
||||||
implements MessagesServiceInterface<User, Message>
|
implements MessagesServiceInterface<User, Message, Channel, MessagePayload>
|
||||||
{
|
{
|
||||||
private logger = createLogger("MessagesService");
|
private logger = createLogger("MessagesService");
|
||||||
|
|
||||||
async sendToUser(userInput: User, message: string): Promise<void> {
|
async sendToUser(userInput: User, message: MessagePayload): Promise<void> {
|
||||||
const user = await client.users.fetch(userInput.id);
|
const user = await client.users.fetch(userInput.id);
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
@@ -47,6 +49,23 @@ export class MessagesService
|
|||||||
|
|
||||||
await logChannelService.sendLogMessage(logMessage);
|
await logChannelService.sendLogMessage(logMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async sendToChannel(
|
||||||
|
channel: Channel,
|
||||||
|
createMessageInput: MessagePayload,
|
||||||
|
): Promise<void> {
|
||||||
|
const fetchedChannel = await client.channels.fetch(channel.id);
|
||||||
|
|
||||||
|
if (fetchedChannel?.isTextBased() && fetchedChannel.isSendable()) {
|
||||||
|
await fetchedChannel.send(createMessageInput);
|
||||||
|
} else {
|
||||||
|
this.logger.error(
|
||||||
|
`Channel with ID ${channel.id} not found or is not text-based.`,
|
||||||
|
);
|
||||||
|
|
||||||
|
throw new Error("Channel not found or is not text-based.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const messagesService = new MessagesService();
|
export const messagesService = new MessagesService();
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import {
|
|||||||
ButtonBuilder,
|
ButtonBuilder,
|
||||||
type ButtonInteraction,
|
type ButtonInteraction,
|
||||||
ButtonStyle,
|
ButtonStyle,
|
||||||
type CacheType,
|
|
||||||
type ChatInputCommandInteraction,
|
type ChatInputCommandInteraction,
|
||||||
type Interaction,
|
|
||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
import { waterMeService } from "./water-me.service";
|
import { waterMeService } from "./water-me.service";
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
import { WaterMeService } from "@avocadi/bot-core/features/water-me/water-me.service";
|
import { WaterMeService } from "@avocadi/bot-core/features/water-me/water-me.service";
|
||||||
|
import { messagesService } from "entitites/messages/messages.service";
|
||||||
|
|
||||||
export const waterMeService = new WaterMeService({
|
export const waterMeService = new WaterMeService(messagesService);
|
||||||
channelId: "123",
|
|
||||||
handleMessageSend: async (message, channelId) => {
|
|
||||||
console.log(`Sending message to channel ${channelId}: ${message}`);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
7
adapters/fluxer/src/actions/shutdown.ts
Normal file
7
adapters/fluxer/src/actions/shutdown.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { logChannelService } from "features/log-channel/log-channel.service";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
export const handleShutdown = async () => {
|
||||||
|
logger.info("bot is shutting down...");
|
||||||
|
await logChannelService.sendLogMessage("ich geh schlafen...");
|
||||||
|
};
|
||||||
@@ -13,6 +13,7 @@ export const ConfigSchema = z.object({
|
|||||||
roleMapping: z.record(Roles, z.string()),
|
roleMapping: z.record(Roles, z.string()),
|
||||||
serverId: z.string(),
|
serverId: z.string(),
|
||||||
version: z.number(),
|
version: z.number(),
|
||||||
|
commandPrefix: z.string().default("!"),
|
||||||
fluxer: z.object({
|
fluxer: z.object({
|
||||||
token: z.string(),
|
token: z.string(),
|
||||||
applicationId: z.string(),
|
applicationId: z.string(),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type z from "zod";
|
import type z from "zod";
|
||||||
import type { ConfigSchema } from "./config.schema";
|
import { ConfigSchema } from "./config.schema";
|
||||||
import env from "./env";
|
import env from "./env";
|
||||||
|
|
||||||
export const config: z.output<typeof ConfigSchema> = {
|
const configInput: z.input<typeof ConfigSchema> = {
|
||||||
channelMapping: {
|
channelMapping: {
|
||||||
text: {
|
text: {
|
||||||
bot: "1473270893617315899",
|
bot: "1473270893617315899",
|
||||||
@@ -42,3 +42,5 @@ export const config: z.output<typeof ConfigSchema> = {
|
|||||||
applicationId: env.FLUXER_APPLICATION_ID,
|
applicationId: env.FLUXER_APPLICATION_ID,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const config = ConfigSchema.parse(configInput);
|
||||||
|
|||||||
56
adapters/fluxer/src/entities/messages/messages.service.ts
Normal file
56
adapters/fluxer/src/entities/messages/messages.service.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import type { MessagesServiceInterface } from "@avocadi/bot-core/entities/messages/messages.service";
|
||||||
|
import { createLogger } from "@avocadi/bot-core/lib/logger";
|
||||||
|
import type {
|
||||||
|
Channel,
|
||||||
|
Message,
|
||||||
|
MessageSendOptions,
|
||||||
|
User,
|
||||||
|
} from "@fluxerjs/core";
|
||||||
|
|
||||||
|
import { logChannelService } from "features/log-channel/log-channel.service";
|
||||||
|
import client from "lib/client";
|
||||||
|
|
||||||
|
export class MessagesService
|
||||||
|
implements
|
||||||
|
MessagesServiceInterface<User, Message, Channel, MessageSendOptions>
|
||||||
|
{
|
||||||
|
private logger = createLogger("MessagesService");
|
||||||
|
|
||||||
|
async sendToUser(
|
||||||
|
userInput: User,
|
||||||
|
createMessageInput: MessageSendOptions,
|
||||||
|
): Promise<void> {
|
||||||
|
const user = await client.users.fetch(userInput.id);
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
await user.send(createMessageInput);
|
||||||
|
} else {
|
||||||
|
this.logger.error(`User with ID ${userInput.id} not found.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendToChannel(
|
||||||
|
channel: Channel,
|
||||||
|
createMessageInput: MessageSendOptions,
|
||||||
|
): Promise<void> {
|
||||||
|
const fetchedChannel = await client.channels.fetch(channel.id);
|
||||||
|
|
||||||
|
if (fetchedChannel?.isSendable()) {
|
||||||
|
await fetchedChannel.send(createMessageInput);
|
||||||
|
} else {
|
||||||
|
this.logger.error(
|
||||||
|
`Channel with ID ${channel.id} not found or is not text-based.`,
|
||||||
|
);
|
||||||
|
|
||||||
|
throw new Error("Channel not found or is not text-based.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async logMessage(message: Message): Promise<void> {
|
||||||
|
const logMessage = `<@${message.author.id}> sent a message:\n"${message.content}"`;
|
||||||
|
|
||||||
|
await logChannelService.sendLogMessage(logMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const messagesService = new MessagesService();
|
||||||
@@ -1,18 +1,22 @@
|
|||||||
|
import { createLogger } from "@avocadi/bot-core/lib/logger";
|
||||||
import { config } from "config";
|
import { config } from "config";
|
||||||
import client from "lib/client";
|
import client from "lib/client";
|
||||||
import { logger } from "lib/common-logger";
|
|
||||||
|
|
||||||
export class LogChannelService {
|
export class LogChannelService {
|
||||||
|
private logger = createLogger("LogChannelService");
|
||||||
|
|
||||||
private logChannelId = config.channelMapping.text.log;
|
private logChannelId = config.channelMapping.text.log;
|
||||||
|
|
||||||
async getLogChannel() {
|
async getLogChannel() {
|
||||||
|
this.logger.debug(`fetching log channel with ID: ${this.logChannelId}`);
|
||||||
|
|
||||||
const logChannel = await client.channels.fetch(this.logChannelId);
|
const logChannel = await client.channels.fetch(this.logChannelId);
|
||||||
|
|
||||||
if (logChannel.isSendable()) {
|
if (logChannel.isSendable()) {
|
||||||
return logChannel;
|
return logChannel;
|
||||||
} else {
|
} else {
|
||||||
logger.fatal("Log channel not found or is not text-based.");
|
this.logger.fatal("log channel not found or is not text-based.");
|
||||||
throw new Error("Log channel not found or is not text-based");
|
throw new Error("log channel not found or is not text-based");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { WaterMeService } from "@avocadi/bot-core/features/water-me/water-me.service";
|
||||||
|
import { messagesService } from "entities/messages/messages.service";
|
||||||
|
|
||||||
|
export const waterMeService = new WaterMeService(messagesService);
|
||||||
0
adapters/fluxer/src/fluxer.controller.ts
Normal file
0
adapters/fluxer/src/fluxer.controller.ts
Normal file
@@ -1,2 +1,3 @@
|
|||||||
import "./ready.listener";
|
import "./ready.listener";
|
||||||
import "./stop.listener";
|
import "./stop.listener";
|
||||||
|
import "./messages/messages.listener";
|
||||||
|
|||||||
37
adapters/fluxer/src/listeners/messages/messages.listener.ts
Normal file
37
adapters/fluxer/src/listeners/messages/messages.listener.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { CommandKeys } from "@avocadi/bot-core/entities/commands/commands.schema";
|
||||||
|
import { Events, type Message } from "@fluxerjs/core";
|
||||||
|
import { config } from "config";
|
||||||
|
import { messagesService } from "entities/messages/messages.service";
|
||||||
|
import client from "lib/client";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
client.on(Events.MessageCreate, async (message: Message) => {
|
||||||
|
if (
|
||||||
|
message.channel?.id !== config.channelMapping.text.log &&
|
||||||
|
message.channel?.id !== config.channelMapping.text.bot
|
||||||
|
) {
|
||||||
|
await messagesService.logMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.content?.startsWith(config.commandPrefix)) {
|
||||||
|
await messagesService.logMessage(message);
|
||||||
|
logger.info(
|
||||||
|
`Command received: ${message.content} from user ${message.author.id}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const command = message.content
|
||||||
|
.slice(config.commandPrefix.length)
|
||||||
|
.trim()
|
||||||
|
.split(" ")[0];
|
||||||
|
|
||||||
|
logger.info(`Parsed command: ${command}`);
|
||||||
|
|
||||||
|
const result = CommandKeys.safeParse(command);
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
logger.info(`Command ${command} is valid.`);
|
||||||
|
} else {
|
||||||
|
logger.warn(`Command ${command} is not recognized.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -1,3 +1,15 @@
|
|||||||
import { Events } from "@fluxerjs/core";
|
import { handleShutdown } from "actions/shutdown";
|
||||||
import client from "lib/client";
|
|
||||||
import { logger } from "lib/common-logger";
|
process.on("exit", async () => {
|
||||||
|
await handleShutdown();
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGINT", async () => {
|
||||||
|
await handleShutdown();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGTERM", async () => {
|
||||||
|
await handleShutdown();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|||||||
@@ -43,9 +43,8 @@
|
|||||||
"./features/dynamic-voice-channels/dynamic-voice-channels.schema": "./dist/features/dynamic-voice-channels/dynamic-voice-channels.schema.js",
|
"./features/dynamic-voice-channels/dynamic-voice-channels.schema": "./dist/features/dynamic-voice-channels/dynamic-voice-channels.schema.js",
|
||||||
"./features/dynamic-voice-channels/dynamic-voice-channels.service": "./dist/features/dynamic-voice-channels/dynamic-voice-channels.service.js",
|
"./features/dynamic-voice-channels/dynamic-voice-channels.service": "./dist/features/dynamic-voice-channels/dynamic-voice-channels.service.js",
|
||||||
"./features/greeting/greeting.service": "./dist/features/greeting/greeting.service.js",
|
"./features/greeting/greeting.service": "./dist/features/greeting/greeting.service.js",
|
||||||
"./features/text-based-feature/text-based-feature": "./dist/features/text-based-feature/text-based-feature.js",
|
|
||||||
"./features/text-based-feature/text-based-feature.schema": "./dist/features/text-based-feature/text-based-feature.schema.js",
|
|
||||||
"./features/water-me/water-me.service": "./dist/features/water-me/water-me.service.js",
|
"./features/water-me/water-me.service": "./dist/features/water-me/water-me.service.js",
|
||||||
|
"./lib/common": "./dist/lib/common.js",
|
||||||
"./lib/logger": "./dist/lib/logger.js",
|
"./lib/logger": "./dist/lib/logger.js",
|
||||||
"./lib/utils": "./dist/lib/utils.js",
|
"./lib/utils": "./dist/lib/utils.js",
|
||||||
"./lib/utils.test": "./dist/lib/utils.test.js",
|
"./lib/utils.test": "./dist/lib/utils.test.js",
|
||||||
|
|||||||
@@ -1,5 +1,19 @@
|
|||||||
export interface MessagesServiceInterface<U = unknown, M = unknown> {
|
import type {
|
||||||
sendToUser(user: U, message: string): Promise<void>;
|
BaseChannel,
|
||||||
|
BaseCreateMessage,
|
||||||
|
BaseMessage,
|
||||||
|
BaseUser,
|
||||||
|
} from "lib/common";
|
||||||
|
|
||||||
|
export interface MessagesServiceInterface<
|
||||||
|
U extends BaseUser = BaseUser,
|
||||||
|
M extends BaseMessage = BaseMessage,
|
||||||
|
C extends BaseChannel = BaseChannel,
|
||||||
|
CM extends BaseCreateMessage = BaseCreateMessage,
|
||||||
|
> {
|
||||||
|
sendToUser(user: U, createMessageInput: CM): Promise<void>;
|
||||||
|
|
||||||
|
sendToChannel(channel: C, createMessageInput: CM): Promise<void>;
|
||||||
|
|
||||||
logMessage(message: M): Promise<void>;
|
logMessage(message: M): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
export type TextBasedFeatureHandleMessageSend = (
|
|
||||||
message: string,
|
|
||||||
channelId: string,
|
|
||||||
) => void | Promise<void>;
|
|
||||||
|
|
||||||
export type TextBasedFeatureInput = {
|
|
||||||
channelId: string;
|
|
||||||
messagesService: TextBasedFeatureHandleMessageSend;
|
|
||||||
};
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import type {
|
|
||||||
TextBasedFeatureHandleMessageSend,
|
|
||||||
TextBasedFeatureInput,
|
|
||||||
} from "./text-based-feature.schema";
|
|
||||||
|
|
||||||
export class TextBasedFeature {
|
|
||||||
channelId: string;
|
|
||||||
handleMessageSend: TextBasedFeatureHandleMessageSend;
|
|
||||||
|
|
||||||
constructor(input: TextBasedFeatureInput) {
|
|
||||||
this.channelId = input.channelId;
|
|
||||||
this.handleMessageSend = input.handleMessageSend;
|
|
||||||
}
|
|
||||||
|
|
||||||
async sendMessage(input: { content: string }) {
|
|
||||||
this.handleMessageSend(input.content, this.channelId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
import { TextBasedFeature } from "features/text-based-feature/text-based-feature";
|
import type { MessagesServiceInterface } from "entities/messages/messages.service";
|
||||||
import type { TextBasedFeatureInput } from "features/text-based-feature/text-based-feature.schema";
|
|
||||||
import { createLogger } from "lib/logger";
|
import { createLogger } from "lib/logger";
|
||||||
import { getRandomInt } from "lib/utils";
|
import { getRandomInt } from "lib/utils";
|
||||||
|
|
||||||
export class WaterMeService extends TextBasedFeature {
|
export class WaterMeService {
|
||||||
waterLevel: number;
|
waterLevel: number;
|
||||||
|
|
||||||
private logger = createLogger("WaterMeService");
|
private logger = createLogger("WaterMeService");
|
||||||
|
|
||||||
private thirsty = 3 as const;
|
private thirsty = 3 as const;
|
||||||
private enough = 10 as const;
|
private enough = 10 as const;
|
||||||
|
messagesService: MessagesServiceInterface;
|
||||||
|
|
||||||
constructor(input: TextBasedFeatureInput) {
|
constructor(messagesService: MessagesServiceInterface) {
|
||||||
super(input);
|
|
||||||
this.waterLevel = 0;
|
this.waterLevel = 0;
|
||||||
|
this.messagesService = messagesService;
|
||||||
}
|
}
|
||||||
|
|
||||||
getReply() {
|
getReply() {
|
||||||
@@ -47,7 +47,10 @@ export class WaterMeService extends TextBasedFeature {
|
|||||||
|
|
||||||
async notifyIfThirsty() {
|
async notifyIfThirsty() {
|
||||||
if (this.waterLevel <= this.thirsty) {
|
if (this.waterLevel <= this.thirsty) {
|
||||||
await this.sendMessage({ content: "ich brauche wasser :(" });
|
await this.messagesService.sendToChannel(
|
||||||
|
{ id: "channelId" },
|
||||||
|
{ content: "ich brauche wasser :(" },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
20
core/src/lib/common.ts
Normal file
20
core/src/lib/common.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
export type BaseMessage = {
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BaseChannel = {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BaseUser = {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BaseCreateMessage =
|
||||||
|
| {
|
||||||
|
content?: string;
|
||||||
|
embeds?: unknown[] | null;
|
||||||
|
attachments?: unknown[] | null;
|
||||||
|
files?: unknown[] | null;
|
||||||
|
}
|
||||||
|
| string;
|
||||||
Reference in New Issue
Block a user