'use strict'; const config = require('config'); const bhttp = require('bhttp'); const WebSocket = require('ws'); const logger = require('simple-node-logger').createSimpleLogger(); const games = config.games.reduce((acc, key) => ({ ...acc, [key]: { ...require(`./games/${key}`) }, key }), {}); const gamesWithListeners = Object.entries(games).filter(([key, game]) => game.onMessage).map(([key, game]) => ({ ...game, key })); async function auth() { const httpSession = bhttp.session(); const res = await httpSession.post(`${config.api}/session`, config.user, { encodeJSON: true, }); if (res.statusCode !== 200) { throw new Error(`Failed to authenticate: ${res.body.toString()}`); } logger.info(`Authenticated with ${config.api}`); return { user: res.body, httpSession, sessionCookie: res.headers['set-cookie'][0], }; } async function getWsId(httpSession) { const res = await httpSession.get(`${config.api}/socket`); if (res.statusCode !== 200) { throw new Error(`Failed to retrieve WebSocket ID: ${res.body.toString()}`); } return res.body; } function connect(wsCreds, sessionCookie) { const ws = new WebSocket(`${config.socket}?${new URLSearchParams({ v: wsCreds.wsId, t: wsCreds.timestamp }).toString()}`, [], { headers: { cookie: sessionCookie, }, }); logger.info(`Connected to ${config.socket}`); return ws; } function onConnect(data, bot) { bot.transmit('joinRooms', { rooms: config.channels }); } function onRooms({ rooms, users }, bot) { logger.info(`Joined ${rooms.map((room) => room.name).join(', ')}`); bot.rooms = rooms; bot.users = { ...bot.users, ...users }; rooms.forEach((room) => { bot.transmit('message', { roomId: room.id, body: `Hi, I am ${config.user.username}, your game host!`, style: config.style, }); }); } function onMessage(message, bot) { const [, command, subcommand] = message.body?.match(new RegExp(`^${config.prefix}(\\w+)(?:\\:(\\w+))?`)) || []; const user = bot.users[message.userId]; const room = bot.rooms.find((room) => room.id === message.roomId); if (command) { const args = message.body.split(/\s+/).slice(1); const game = games[command]; if (game) { const sendMessage = (body, roomId) => { bot.transmit('message', { roomId, body: `[${game.name || command}] ${body}`, style: config.style, }); }; games[command].onCommand(args, { subcommand, bot, message, user, room, sendMessage, logger }); } } gamesWithListeners.forEach((game) => { const sendMessage = (body, roomId) => { bot.transmit('message', { roomId, body: `[${game.name || game.key}] ${body}`, style: config.style, }); }; game.onMessage(message, { bot, message, user, room, sendMessage, logger }); }); } const messageHandlers = { connect: onConnect, rooms: onRooms, message: onMessage, }; async function init() { const { user, httpSession, sessionCookie } = await auth(); const wsCreds = await getWsId(httpSession); const ws = connect(wsCreds, sessionCookie); ws.transmit = (domain, data) => { ws.send(JSON.stringify([domain, data])); }; const bot = { user, ws, httpSession, rooms: [], users: [], transmit: ws.transmit, }; ws.on('message', (msg) => { const [domain, data] = JSON.parse(msg); messageHandlers[domain]?.(data, bot); }); } init();