mirror of
https://github.com/qwerinope/qweribot.git
synced 2025-12-18 15:41:38 +01:00
implement a basic alerts template
This commit is contained in:
13
src/web/alerts/serverFunctions.ts
Normal file
13
src/web/alerts/serverFunctions.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import server from "web";
|
||||
import type { alert, alertEventData } from "./types";
|
||||
|
||||
export async function sendAlertEvent(event: alertEventData) {
|
||||
server.publish('alerts', JSON.stringify(event));
|
||||
};
|
||||
|
||||
export async function playAlert(alert: alert) {
|
||||
await sendAlertEvent({
|
||||
function: 'playAlert',
|
||||
alert
|
||||
});
|
||||
};
|
||||
37
src/web/alerts/types.ts
Normal file
37
src/web/alerts/types.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { serverNotificationEvent } from "web/serverTypes";
|
||||
|
||||
type alertBase<name extends string> = {
|
||||
name: name;
|
||||
user: string;
|
||||
};
|
||||
|
||||
export type userBlastAlert = alertBase<'userBlast'> & {
|
||||
target: string;
|
||||
};
|
||||
|
||||
export type userExecutionAlert = alertBase<'userExecution'> & {
|
||||
target: string;
|
||||
};
|
||||
|
||||
export type grenadeExplosionAlert = alertBase<'grenadeExplosion'> & {
|
||||
target: string;
|
||||
};
|
||||
|
||||
export type tntExplosionAlert = alertBase<'tntExplosion'> & {
|
||||
targets: string[];
|
||||
};
|
||||
|
||||
export type alert =
|
||||
| userBlastAlert
|
||||
| userExecutionAlert
|
||||
| grenadeExplosionAlert
|
||||
| tntExplosionAlert;
|
||||
|
||||
type playAlertEvent = {
|
||||
function: 'playAlert';
|
||||
alert: alert;
|
||||
};
|
||||
|
||||
export type alertEventData =
|
||||
| playAlertEvent
|
||||
| serverNotificationEvent;
|
||||
12
src/web/alerts/www/index.html
Normal file
12
src/web/alerts/www/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>qwerinope's alert server</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="./src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
30
src/web/alerts/www/src/alerts/alertManager.ts
Normal file
30
src/web/alerts/www/src/alerts/alertManager.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { alert } from "web/alerts/types";
|
||||
import alerts from "./index";
|
||||
|
||||
class AlertManager {
|
||||
#busy: boolean;
|
||||
#alertQueue: alert[];
|
||||
|
||||
constructor() {
|
||||
this.#busy = false;
|
||||
this.#alertQueue = [];
|
||||
};
|
||||
|
||||
private async playAlert(alert: alert) {
|
||||
this.#busy = true;
|
||||
|
||||
await alerts[alert.name](alert);
|
||||
|
||||
const nextAlert = this.#alertQueue.shift();
|
||||
if (!nextAlert) { this.#busy = false; return; }; // if .shift has no results, we done and return
|
||||
|
||||
this.playAlert(nextAlert);
|
||||
};
|
||||
|
||||
async queueAlert(alert: alert) {
|
||||
if (this.#busy) { this.#alertQueue.push(alert); return; };
|
||||
await this.playAlert(alert);
|
||||
};
|
||||
};
|
||||
|
||||
export default new AlertManager();
|
||||
14
src/web/alerts/www/src/alerts/index.ts
Normal file
14
src/web/alerts/www/src/alerts/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export function delay(time: number) {
|
||||
return new Promise(function(resolve) {
|
||||
setTimeout(resolve, time)
|
||||
});
|
||||
};
|
||||
|
||||
import userBlast from "./userBlast";
|
||||
|
||||
export default {
|
||||
'userBlast': userBlast,
|
||||
'userExecute': userBlast,
|
||||
'grenadeExplosion': userBlast,
|
||||
'tntExplosion': userBlast
|
||||
}
|
||||
18
src/web/alerts/www/src/alerts/userBlast.ts
Normal file
18
src/web/alerts/www/src/alerts/userBlast.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { userBlastAlert } from "web/alerts/types";
|
||||
import { delay } from "./index";
|
||||
|
||||
export default async function execute(alert: userBlastAlert) {
|
||||
const parentDiv = document.createElement('div');
|
||||
const textElement = document.createElement('span');
|
||||
textElement.textContent = `${alert.user} just blasted ${alert.target} for 60 seconds! Rip bozo!`;
|
||||
parentDiv.appendChild(textElement);
|
||||
Object.assign(textElement.style, {
|
||||
position: 'fixed',
|
||||
top: '20px',
|
||||
left: '20px',
|
||||
zIndex: 1000
|
||||
});
|
||||
document.querySelector("#app").appendChild(parentDiv);
|
||||
await delay(10000);
|
||||
parentDiv.remove();
|
||||
};
|
||||
25
src/web/alerts/www/src/main.ts
Normal file
25
src/web/alerts/www/src/main.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { serverInstruction } from "web/serverTypes";
|
||||
import { alertEventData } from "web/alerts/types";
|
||||
import alertManager from "./alerts/alertManager";
|
||||
|
||||
const socket = new WebSocket(`ws://${location.host}`);
|
||||
|
||||
socket.onopen = () => {
|
||||
const instruction: serverInstruction = {
|
||||
type: 'subscribe',
|
||||
target: 'alerts'
|
||||
};
|
||||
socket.send(JSON.stringify(instruction));
|
||||
};
|
||||
|
||||
socket.onmessage = event => {
|
||||
const data: alertEventData = JSON.parse(event.data);
|
||||
switch (data.function) {
|
||||
case "playAlert":
|
||||
alertManager.queueAlert(data.alert);
|
||||
break;
|
||||
case 'serverNotification':
|
||||
console.log(data.message);
|
||||
break;
|
||||
};
|
||||
};
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { serverNotificationEvent } from "web/serverTypes";
|
||||
|
||||
export type createMessageEvent = {
|
||||
function: 'createMessage';
|
||||
messageParts: EventSubChatMessagePart[];
|
||||
@@ -12,17 +14,14 @@ export type deleteMessageEvent = {
|
||||
function: 'deleteMessage';
|
||||
messageId: string;
|
||||
};
|
||||
|
||||
export type userBanEvent = {
|
||||
function: 'userBan';
|
||||
chatterId: string;
|
||||
};
|
||||
export type serverNotificationEvent = {
|
||||
function: 'serverNotification';
|
||||
message: string;
|
||||
};
|
||||
|
||||
export type twitchEventData =
|
||||
createMessageEvent
|
||||
| createMessageEvent
|
||||
| deleteMessageEvent
|
||||
| userBanEvent
|
||||
| serverNotificationEvent;
|
||||
@@ -32,44 +31,44 @@ export type twitchEventData =
|
||||
export interface EventSubChatMessageTextPart {
|
||||
type: 'text';
|
||||
text: string;
|
||||
}
|
||||
};
|
||||
|
||||
export interface EventSubChatMessageCheermote {
|
||||
prefix: string;
|
||||
bits: number;
|
||||
tier: number;
|
||||
}
|
||||
};
|
||||
|
||||
export interface EventSubChatMessageCheermotePart {
|
||||
type: 'cheermote';
|
||||
text: string;
|
||||
cheermote: EventSubChatMessageCheermote;
|
||||
}
|
||||
};
|
||||
|
||||
export interface EventSubChatMessageEmote {
|
||||
id: string;
|
||||
emote_set_id: string;
|
||||
owner_id: string;
|
||||
format: string[];
|
||||
}
|
||||
};
|
||||
|
||||
export interface EventSubChatMessageEmotePart {
|
||||
type: 'emote';
|
||||
text: string;
|
||||
emote: EventSubChatMessageEmote;
|
||||
}
|
||||
};
|
||||
|
||||
export interface EventSubChatMessageMention {
|
||||
user_id: string;
|
||||
user_name: string;
|
||||
user_login: string;
|
||||
}
|
||||
};
|
||||
|
||||
export interface EventSubChatMessageMentionPart {
|
||||
type: 'mention';
|
||||
text: string;
|
||||
mention: EventSubChatMessageMention;
|
||||
}
|
||||
};
|
||||
|
||||
export type EventSubChatMessagePart =
|
||||
| EventSubChatMessageTextPart
|
||||
|
||||
@@ -84,5 +84,5 @@ import server from "web";
|
||||
import type { twitchEventData } from "web/chatWidget/websockettypes";
|
||||
|
||||
export async function sendTwitchChatEvent(event: twitchEventData) {
|
||||
server.publish('twitchchat', JSON.stringify(event));
|
||||
server.publish('twitch.chat', JSON.stringify(event));
|
||||
};
|
||||
|
||||
@@ -3,14 +3,16 @@ import '@fontsource/jersey-15';
|
||||
|
||||
import { type twitchEventData } from "web/chatWidget/websockettypes";
|
||||
import { parseMessage } from './createMessage';
|
||||
import { serverInstruction } from 'web/serverTypes';
|
||||
|
||||
const socket = new WebSocket(`ws://${location.host}`);
|
||||
|
||||
socket.onopen = () => {
|
||||
socket.send(JSON.stringify({
|
||||
const instruction: serverInstruction = {
|
||||
type: 'subscribe',
|
||||
target: 'twitchchat'
|
||||
}));
|
||||
target: 'twitch.chat'
|
||||
};
|
||||
socket.send(JSON.stringify(instruction));
|
||||
};
|
||||
|
||||
socket.onmessage = event => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import logger from "lib/logger";
|
||||
import { getBadges, getExternalEmotes } from "web/chatWidget/widgetServerFunctions";
|
||||
import chatWidget from "web/chatWidget/www/index.html";
|
||||
import { sendTwitchChatEvent } from "web/chatWidget/widgetServerFunctions";
|
||||
import { getBadges, getExternalEmotes } from "web/chatWidget/widgetServerFunctions";
|
||||
import alerts from "web/alerts/www/index.html";
|
||||
import type { serverInstruction, serverNotificationEvent } from "web/serverTypes";
|
||||
|
||||
const port = Number(process.env.WEB_PORT);
|
||||
if (isNaN(port)) { logger.enverr("WEB_PORT"); process.exit(1); };
|
||||
@@ -15,26 +16,23 @@ export default Bun.serve({
|
||||
routes: {
|
||||
"/chat": chatWidget,
|
||||
"/chat/getBadges": getBadges,
|
||||
"/chat/getEmotes": getExternalEmotes
|
||||
"/chat/getEmotes": getExternalEmotes,
|
||||
|
||||
"/alerts": alerts
|
||||
},
|
||||
websocket: {
|
||||
open(_ws) {
|
||||
sendTwitchChatEvent({
|
||||
function: 'serverNotification',
|
||||
message: 'Sucessfully opened websocket connection'
|
||||
});
|
||||
},
|
||||
message(ws, omessage) {
|
||||
const message = JSON.parse(omessage.toString());
|
||||
const message = JSON.parse(omessage.toString()) as serverInstruction;
|
||||
if (!message.type) return;
|
||||
switch (message.type) {
|
||||
case 'subscribe':
|
||||
if (!message.target) return;
|
||||
const target = message.target.toLowerCase();
|
||||
ws.subscribe(message.target);
|
||||
sendTwitchChatEvent({
|
||||
ws.send(JSON.stringify({
|
||||
function: 'serverNotification',
|
||||
message: `Successfully subscribed to all ${message.target} events`
|
||||
});
|
||||
message: `Successfully subscribed to ${target} events`
|
||||
} as serverNotificationEvent)); // Both alerts and chatwidget eventsub subscriptions have the notification field
|
||||
break;
|
||||
};
|
||||
},
|
||||
|
||||
13
src/web/serverTypes.ts
Normal file
13
src/web/serverTypes.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
type subscribe = {
|
||||
type: 'subscribe',
|
||||
target: string;
|
||||
};
|
||||
|
||||
export type serverInstruction =
|
||||
| subscribe;
|
||||
|
||||
// This event is found on all listeners, so it should be placed here
|
||||
export type serverNotificationEvent = {
|
||||
function: 'serverNotification';
|
||||
message: string;
|
||||
};
|
||||
@@ -19,5 +19,5 @@
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["src/web/chatWidget/www/**/*"]
|
||||
"exclude": ["src/web/chatWidget/www/**/*", "src/web/alerts/www/**/*"]
|
||||
}
|
||||
|
||||
@@ -15,6 +15,6 @@
|
||||
},
|
||||
"references": [
|
||||
{ "path": "./tsconfig.bot.json" },
|
||||
{ "path": "./tsconfig.chatwidget.json" }
|
||||
{ "path": "./tsconfig.web.json" }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"lib": ["DOM", "ES2020"],
|
||||
"types": []
|
||||
"lib": ["DOM", "ES2020"]
|
||||
},
|
||||
"include": ["src/web/chatWidget/www/**/*"]
|
||||
"include": ["src/web/chatWidget/www/**/*", "src/web/alerts/www/**/*"]
|
||||
}
|
||||
Reference in New Issue
Block a user