xmppjs-chat-bot
Version:
Server-side XMPP chat bot
211 lines • 8.23 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Bot = void 0;
const read_1 = require("./config/read");
const stanza_1 = require("./stanza");
const jid_1 = require("@xmpp/jid");
const xml_1 = __importDefault(require("@xmpp/xml"));
const logger_1 = require("./logger");
const room_1 = require("./room");
const listen_1 = require("./config/listen");
const handlers_directory_1 = require("./handlers_directory");
require('./handlers');
class Bot {
constructor(botName, xmpp, logger) {
this.rooms = new Map();
this.dirListeners = new Map();
this.botName = botName;
this.xmpp = xmpp;
this.logger = (0, logger_1.wrapLogger)(botName, logger ?? new logger_1.DefaultLogger());
}
static async loadsFromConfigFile(filepath) {
const bot = await (0, read_1.getBotFromConfig)(filepath);
return bot;
}
async connect() {
this.xmpp.on('error', (err) => {
this.logger.error(err);
});
this.xmpp.on('offline', () => {
this.logger.info(`${this.botName} is now offline.`);
});
this.xmpp.on('stanza', (xmppElement) => {
const stanza = stanza_1.Stanza.parseIncoming(xmppElement);
if (!stanza) {
this.logger.error('Failed to initiate a Stanza object from: ' + xmppElement.toString());
return;
}
this.logger.debug('stanza received: ' + stanza.toString());
if (!stanza.from) {
return;
}
const roomJid = stanza.from.bare();
const room = this.rooms.get(roomJid.toString());
room?.receiveStanza(stanza);
});
this.xmpp.on('online', (address) => {
this.logger.debug('Online with address ' + address.toString());
this.address = address;
this.rooms.forEach(room => {
room.reset();
room.join(room.myNick ?? this.botName).then(() => { }, () => { });
});
});
await this.xmpp.start();
}
async disconnect() {
for (const [dir, callback] of this.dirListeners) {
this.logger.debug('Stop listening the configuration directory ' + dir);
callback();
}
for (const [roomId, room] of this.rooms) {
this.logger.debug(`Leaving room ${roomId}...`);
await room.detachHandlers();
try {
await room.part();
}
catch (err) {
this.logger.error(err);
}
}
try {
await this.xmpp.stop();
}
catch (err) {
this.logger.error(err);
}
}
async waitOnline() {
if (this.xmpp.status === 'online') {
this.logger.debug('waitOnline: The bot is already online');
return Promise.resolve();
}
this.logger.debug('waitOnline: The bot is not online, waiting...');
const p = new Promise(resolve => {
this.xmpp.once('online', () => {
this.logger.debug('waitOnline: online event triggered, waitOnline can resolve.');
resolve();
});
});
return p;
}
async sendStanza(type, attrs, ...children) {
if (type !== 'iq') {
attrs = Object.assign({
from: this.address?.toString()
}, attrs);
}
const stanza = (0, xml_1.default)(type, attrs, ...children);
this.logger.debug('stanza to emit: ' + stanza.toString());
await this.xmpp.send(stanza);
}
async joinRoom(local, domain, nick) {
const roomJID = new jid_1.JID(local, domain);
const roomJIDstr = roomJID.toString();
let room = this.rooms.get(roomJIDstr);
if (!room) {
room = new room_1.Room(this, roomJID);
this.rooms.set(roomJIDstr, room);
}
this.logger.debug('Joining room ' + roomJID.toString());
await room.join(nick);
return room;
}
async partRoom(local, mucDomain) {
const roomJID = (new jid_1.JID(local, mucDomain)).toString();
const room = this.rooms.get(roomJID);
if (!room) {
return;
}
await room.detachHandlers();
await room.part();
this.rooms.delete(roomJID);
}
getAddress() {
return this.address;
}
async loadRoomConfDir(dir) {
if (this.dirListeners.has(dir)) {
this.logger.error('There is already a listener for the dir ' + dir);
return;
}
this.logger.info('Loading and listening conf directory ' + dir + '...');
const w = await (0, listen_1.listenRoomConfDir)(this.logger, dir, async (conf) => {
this.logger.debug('(re)Loading a room configuration');
await this.loadRoomConf(conf);
});
if (w) {
this.dirListeners.set(dir, w);
}
else {
this.logger.error('Failed loading conf directory ' + dir);
}
}
async loadRoomConf(conf) {
if (!conf) {
return;
}
const enabled = !!(conf.enabled ?? true);
const roomJID = (new jid_1.JID(conf.local, conf.domain)).toString();
this.logger.info('(re)Loading conf for room ' + roomJID + '...');
if (!enabled) {
this.logger.debug('Room ' + roomJID + ' is disabled');
if (this.rooms.has(roomJID)) {
this.logger.info('Room ' + roomJID + ' disabled, Must leave room ' + roomJID);
await this.partRoom(conf.local, conf.domain);
}
else {
this.logger.debug('Room ' + roomJID + ' was not loaded');
}
return;
}
this.logger.debug('Room ' + roomJID + ' is enabled');
const nickname = conf.nick ?? this.botName;
if (!this.rooms.has(roomJID)) {
this.logger.info('Room enabled, Joining room ' + roomJID);
await this.joinRoom(conf.local, conf.domain, nickname);
}
const room = this.rooms.get(roomJID);
if (!room) {
this.logger.error('Failed getting the freshly joined room');
return;
}
const currentNickname = room.myNick;
if (currentNickname && nickname !== currentNickname) {
this.logger.info('Changing nickname for room ' + roomJID);
await room.changeNickname(nickname);
}
for (const handlerConf of (conf.handlers ?? [])) {
const loadedHandler = room.getHandlerById(handlerConf.id);
const handlerEnabled = !!(handlerConf.enabled ?? true);
if (loadedHandler) {
if (handlerEnabled) {
this.logger.info('The handler ' + loadedHandler.id + ' was already loaded, reloading its configuration for room ' + roomJID);
loadedHandler.loadOptions(handlerConf.options);
}
else {
this.logger.info('The handler ' + loadedHandler.id + ' must be detached for room ' + roomJID);
room.detachHandlerById(loadedHandler.id);
}
continue;
}
if (!handlerEnabled) {
this.logger.debug('The handler ' + handlerConf.id + ' is disabled, and was not loaded for room ' + roomJID);
continue;
}
const HandlerClass = handlers_directory_1.HandlersDirectory.singleton().getClass(handlerConf.type);
if (!HandlerClass) {
this.logger.error('Can\'t find class for handler type ' + handlerConf.type);
continue;
}
this.logger.info('The handler ' + handlerConf.id + ' must be created and started for room ' + roomJID);
const handler = new HandlerClass(handlerConf.id, room, handlerConf.options);
await handler.start();
}
}
}
exports.Bot = Bot;
//# sourceMappingURL=bot.js.map