Initial code
This commit is contained in:
commit
1f20a611da
26 changed files with 1050 additions and 0 deletions
47
src/modules/admin/admin.ts
Normal file
47
src/modules/admin/admin.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { MatrixClient } from "matrix-js-sdk";
|
||||
import type { ICallbackStore } from "../types.js";
|
||||
import { config } from "../../config.js";
|
||||
import { load, save } from "../../store/store.js";
|
||||
|
||||
let client: MatrixClient;
|
||||
|
||||
const registerModuleAdmin = (
|
||||
matrixClient: MatrixClient,
|
||||
callbackStore: ICallbackStore,
|
||||
) => {
|
||||
client = matrixClient;
|
||||
|
||||
callbackStore.messageCallbacks.push({
|
||||
startCondition: `${config.app.triggerPrefix}shutdown`,
|
||||
allowedRoles: ["ADMIN"],
|
||||
callbackFunc: onShutdown,
|
||||
});
|
||||
callbackStore.messageCallbacks.push({
|
||||
startCondition: `${config.app.triggerPrefix}loaddata`,
|
||||
allowedRoles: ["MODERATOR", "ADMIN"],
|
||||
callbackFunc: onLoadData,
|
||||
});
|
||||
callbackStore.messageCallbacks.push({
|
||||
startCondition: `${config.app.triggerPrefix}savedata`,
|
||||
allowedRoles: ["MODERATOR", "ADMIN"],
|
||||
callbackFunc: onSaveData,
|
||||
});
|
||||
};
|
||||
|
||||
const onShutdown = (text: string) => {
|
||||
if (!text.includes("nosave")) {
|
||||
save();
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
const onLoadData = () => {
|
||||
load();
|
||||
};
|
||||
|
||||
const onSaveData = () => {
|
||||
save();
|
||||
};
|
||||
|
||||
export { registerModuleAdmin };
|
||||
1
src/modules/admin/index.ts
Normal file
1
src/modules/admin/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./admin.js";
|
||||
63
src/modules/base/base.ts
Normal file
63
src/modules/base/base.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import { MatrixClient } from "matrix-js-sdk";
|
||||
import type { ICallbackStore } from "../types.js";
|
||||
import { config } from "../../config.js";
|
||||
|
||||
let client: MatrixClient;
|
||||
|
||||
const registerModuleTest = (
|
||||
matrixClient: MatrixClient,
|
||||
callbackStore: ICallbackStore,
|
||||
) => {
|
||||
client = matrixClient;
|
||||
|
||||
callbackStore.messageCallbacks.push({
|
||||
startCondition: `${config.app.triggerPrefix}ping`,
|
||||
callbackFunc: onPing,
|
||||
});
|
||||
callbackStore.messageCallbacks.push({
|
||||
startCondition: `${config.app.triggerPrefix}say `,
|
||||
callbackFunc: onSay,
|
||||
});
|
||||
callbackStore.messageCallbacks.push({
|
||||
startCondition: `${config.app.triggerPrefix}help`,
|
||||
callbackFunc: onHelp,
|
||||
});
|
||||
};
|
||||
|
||||
const onPing = (_text: string, roomId: string) => {
|
||||
client.sendTextMessage(roomId, "Pong!");
|
||||
};
|
||||
|
||||
const onSay = (text: string, roomId: string) => {
|
||||
const trigger = `${config.app.triggerPrefix}say `;
|
||||
|
||||
client.sendTextMessage(roomId, text.replace(trigger, ""));
|
||||
};
|
||||
|
||||
const onHelp = (_text: string, roomId: string) => {
|
||||
client.sendHtmlMessage(
|
||||
roomId,
|
||||
"",
|
||||
`<h3>Role: User</h3>
|
||||
<ul>
|
||||
<li><b>!ping</b> - Pong!</li>
|
||||
<li><b>!say {text}</b> - Repeats your message</li>
|
||||
<li><b>!help</b> - Prints this help message</li>
|
||||
<li><b>!rank</b> - Prints your rank and experience</li>
|
||||
<li><b>!leaderboard</b> - Prints total user ranking</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
<h3>Role: Moderator</h3>
|
||||
<ul>
|
||||
<li><b>!load</b> - Load bot data</li>
|
||||
<li><b>!save</b> - Save bot data</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
<h3>Role: Admin</h3>
|
||||
<ul>
|
||||
<li><b>!shutdown</b> - Shutdown bot</li>
|
||||
</ul>`,
|
||||
);
|
||||
};
|
||||
|
||||
export { registerModuleTest };
|
||||
1
src/modules/base/index.ts
Normal file
1
src/modules/base/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./base.js";
|
||||
55
src/modules/global.ts
Normal file
55
src/modules/global.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import type { MatrixClient } from "matrix-js-sdk";
|
||||
import type { TRole } from "../store/types.js";
|
||||
import { getRank, getUserById } from "../helpers.js";
|
||||
import { config } from "../config.js";
|
||||
import { state } from "../store/store.js";
|
||||
|
||||
const onAnyMessage = (
|
||||
client: MatrixClient,
|
||||
_text: string,
|
||||
roomId: string,
|
||||
sender: string,
|
||||
) => {
|
||||
const date = Date.now();
|
||||
|
||||
const user = getUserById(sender);
|
||||
if (user.id === ":") {
|
||||
state.users.push({
|
||||
id: sender,
|
||||
role: "USER",
|
||||
experience: 0,
|
||||
lastMessageTimestamp: date,
|
||||
});
|
||||
return onAnyMessage(client, _text, roomId, sender);
|
||||
}
|
||||
|
||||
const rankBefore = getRank(user.experience);
|
||||
|
||||
if (date > user.lastMessageTimestamp + config.app.experience.timeout) {
|
||||
user.experience += config.app.experience.gain;
|
||||
}
|
||||
user.lastMessageTimestamp = date;
|
||||
|
||||
const rankAfter = getRank(user.experience);
|
||||
if (rankAfter.rank > rankBefore.rank) {
|
||||
client.sendHtmlMessage(
|
||||
roomId,
|
||||
"",
|
||||
`${sender} - You are now rank <b>${rankAfter.rank}</b>`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const onMissingRole = (
|
||||
client: MatrixClient,
|
||||
userRole: TRole,
|
||||
roomId: string,
|
||||
) => {
|
||||
client.sendHtmlMessage(
|
||||
roomId,
|
||||
"",
|
||||
`You are missing the required role.<br/>Your current role is <b>${userRole}</b>`,
|
||||
);
|
||||
};
|
||||
|
||||
export { onAnyMessage, onMissingRole };
|
||||
102
src/modules/module.ts
Normal file
102
src/modules/module.ts
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
import {
|
||||
MatrixClient,
|
||||
MatrixEvent,
|
||||
RoomEvent,
|
||||
type IContent,
|
||||
} from "matrix-js-sdk";
|
||||
import { registerModuleTest } from "./base/base.js";
|
||||
import type { ICallback, ICallbackStore } from "./types.js";
|
||||
import { registerModuleAdmin } from "./admin/admin.js";
|
||||
import { registerModuleUser } from "./user/user.js";
|
||||
import { checkRoles, getUserById } from "../helpers.js";
|
||||
import { onAnyMessage, onMissingRole } from "./global.js";
|
||||
import { config } from "../config.js";
|
||||
|
||||
const callbacks: ICallbackStore = {
|
||||
messageCallbacks: [],
|
||||
};
|
||||
|
||||
const checkMessageCallback = (
|
||||
client: MatrixClient,
|
||||
text: string,
|
||||
callback: ICallback,
|
||||
roomId: string,
|
||||
sender: string,
|
||||
) => {
|
||||
if (callback.allowedRooms && !callback.allowedRooms.includes(roomId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (callback.startCondition && !text.startsWith(callback.startCondition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
callback.includesCondition &&
|
||||
!text.includes(callback.includesCondition)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (callback.allowedRoles && !checkRoles(callback.allowedRoles, sender)) {
|
||||
onMissingRole(client, getUserById(sender).role, roomId);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const registerModules = (client: MatrixClient) => {
|
||||
const startupTime = Date.now();
|
||||
|
||||
client.on(RoomEvent.Timeline, (event: MatrixEvent) => {
|
||||
const ts = event.getTs();
|
||||
if (ts < startupTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getType() !== "m.room.message") {
|
||||
return;
|
||||
}
|
||||
|
||||
const content = event.getContent<IContent>();
|
||||
const body = content?.body;
|
||||
if (!body || !client) {
|
||||
return;
|
||||
}
|
||||
|
||||
const roomId = event.getRoomId();
|
||||
const sender = event.getSender();
|
||||
if (!roomId || !sender) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender === config.userId) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Message from ${sender} in ${roomId}: ${body}`);
|
||||
|
||||
onAnyMessage(client, body.toString(), roomId, sender);
|
||||
|
||||
callbacks.messageCallbacks.forEach((callback) => {
|
||||
if (
|
||||
checkMessageCallback(
|
||||
client,
|
||||
body.toString(),
|
||||
callback,
|
||||
roomId,
|
||||
sender,
|
||||
)
|
||||
) {
|
||||
callback.callbackFunc(body.toString(), roomId, sender);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
registerModuleTest(client, callbacks);
|
||||
registerModuleAdmin(client, callbacks);
|
||||
registerModuleUser(client, callbacks);
|
||||
};
|
||||
|
||||
export { registerModules };
|
||||
15
src/modules/types.ts
Normal file
15
src/modules/types.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import type { TRole } from "../store/types.js";
|
||||
|
||||
interface ICallbackStore {
|
||||
messageCallbacks: ICallback[];
|
||||
}
|
||||
|
||||
interface ICallback {
|
||||
startCondition?: string;
|
||||
includesCondition?: string;
|
||||
allowedRoles?: TRole[];
|
||||
allowedRooms?: string;
|
||||
callbackFunc: (text: string, roomId: string, sender: string) => void;
|
||||
}
|
||||
|
||||
export { type ICallbackStore, type ICallback };
|
||||
1
src/modules/user/index.ts
Normal file
1
src/modules/user/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./user.js";
|
||||
57
src/modules/user/user.ts
Normal file
57
src/modules/user/user.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import { MatrixClient } from "matrix-js-sdk";
|
||||
import type { ICallbackStore } from "../types.js";
|
||||
import { config } from "../../config.js";
|
||||
import { getRank, getUserById, getUserName } from "../../helpers.js";
|
||||
import { state } from "../../store/store.js";
|
||||
import type { IUser } from "../../store/types.js";
|
||||
let client: MatrixClient;
|
||||
|
||||
const registerModuleUser = (
|
||||
matrixClient: MatrixClient,
|
||||
callbackStore: ICallbackStore,
|
||||
) => {
|
||||
client = matrixClient;
|
||||
|
||||
callbackStore.messageCallbacks.push({
|
||||
startCondition: `${config.app.triggerPrefix}rank`,
|
||||
callbackFunc: onRank,
|
||||
});
|
||||
callbackStore.messageCallbacks.push({
|
||||
startCondition: `${config.app.triggerPrefix}leaderboard`,
|
||||
callbackFunc: onLeaderboard,
|
||||
});
|
||||
};
|
||||
|
||||
const onRank = (_text: string, roomId: string, sender: string) => {
|
||||
const rank = getRank(getUserById(sender).experience);
|
||||
|
||||
client.sendHtmlMessage(
|
||||
roomId,
|
||||
"",
|
||||
`<h3>Your Rank: ${rank.rank}</h3>
|
||||
<i>Next rank progress: ${rank.experienceInRank}/${rank.expToNextRank}exp</i>`,
|
||||
);
|
||||
};
|
||||
|
||||
const onLeaderboard = (_text: string, roomId: string) => {
|
||||
const mapUsersToLeaderboard = (user: IUser): string => {
|
||||
const rank = getRank(user.experience);
|
||||
|
||||
return `<li>${getUserName(user)}: rank ${rank.rank} (${rank.experienceInRank}/${rank.expToNextRank}exp)</li>`;
|
||||
};
|
||||
|
||||
const users = state.users.sort(
|
||||
(userA, userB) => userB.experience - userA.experience,
|
||||
);
|
||||
|
||||
client.sendHtmlMessage(
|
||||
roomId,
|
||||
"",
|
||||
`<h3>Leaderboard</h3>
|
||||
<ul>
|
||||
${users.map(mapUsersToLeaderboard)}
|
||||
</ul>`,
|
||||
);
|
||||
};
|
||||
|
||||
export { registerModuleUser };
|
||||
Loading…
Add table
Add a link
Reference in a new issue