const fs = require('fs/promises') const path = require('path') const readline = require('readline') const json5 = require('json5') const matrix = require('matrix-js-sdk') const irc = require('matrix-org-irc') const createBot = require('./bot.js') const fileExists = require('./util/file_exists') const Console = require('./util/console') async function main () { // config loading const configPath = process.argv[2] ?? 'config.json5' if (!await fileExists(configPath)) { await fs.copyFile(path.join(__dirname, 'default.json5'), configPath) globalThis.console.info('No config file was found, so a default one was created') } const config = json5.parse(await fs.readFile(configPath, 'utf-8')) // logging const logdir = config.paths?.logs ?? 'logs' if (!await fileExists(logdir)) await fs.mkdir(logdir) const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prefix: '> ' }) const console = new Console({ readline: rl }) await console.createLogFile(logdir) for (const options of config.bots) { // pass through the options to find irc channels if (!options.irc || !config.ircClients || !config.ircClients[options.irc.client]) continue config.ircClients[options.irc.client].channels ??= [] config.ircClients[options.irc.client].channels.push(options.irc.channel) } const matrixClients = {} if (config.matrixClients) { for (const key in config.matrixClients) { const client = matrix.createClient(config.matrixClients[key]) matrixClients[key] = client client.startClient() } } const ircClients = {} if (config.ircClients) { for (const key in config.ircClients) { const options = config.ircClients[key] options.autoRejoin ??= true const client = new irc.Client(options.server, options.nick, options) ircClients[key] = client client.on('motd', () => { if (options.oper) client.send('oper', options.oper[0], options.oper[1]) }) } } const bots = [] for (const options of config.bots) { const mergedOptions = { console, paths: config.paths, ...(config.all ?? {}), ...options } if (mergedOptions.matrix && typeof mergedOptions.matrix.client !== 'object') mergedOptions.matrix.client = matrixClients[mergedOptions.matrix.client] if (mergedOptions.irc && typeof mergedOptions.irc.client !== 'object') mergedOptions.irc.client = ircClients[mergedOptions.irc.client] const bot = createBot(mergedOptions) bots.push(bot) bot.bots = bots bot.on('error', error => bot.console.error(error.stack)) } process.on('uncaughtException', error => { if (error.stack.includes('protodef') || error.code === 'Z_BUF_ERROR') { console.error('Uncaught packet error!\n' + error.stack) return // Ignore packet errors } globalThis.console.error(error) try { console.end() } catch { } try { fs.appendSync(console.filename, 'Crashed due to an uncaught exception!\n' + error.stack) } catch { } process.exit(1) }) } main()