UNPKG

xmppjs-chat-bot

Version:
267 lines 9.38 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RoomUser = exports.Room = void 0; const logger_1 = require("./logger"); const events_1 = __importDefault(require("events")); const jid_1 = require("@xmpp/jid"); const xml_1 = __importDefault(require("@xmpp/xml")); const user_1 = require("./user"); Object.defineProperty(exports, "RoomUser", { enumerable: true, get: function () { return user_1.RoomUser; } }); const xmppid = require('@xmpp/id'); class Room extends events_1.default { constructor(bot, roomJID) { super(); this.bot = bot; this.roomJID = roomJID; this.state = 'offline'; this.roster = new Map(); this.handlers = {}; this.logger = (0, logger_1.wrapLogger)(this.roomJID.toString(), bot.logger); } reset() { this.state = 'offline'; this.roster.clear(); } isOnline() { return this.state === 'online'; } onlineUserCount() { let count = 0; this.roster.forEach(user => { if (user.isOnline()) { count++; } }); return count; } getOnlineUsers() { const r = []; this.roster.forEach(user => { if (user.isOnline()) { r.push(user); } }); return r; } get myNick() { return this.userJID?.getResource(); } get jid() { return this.roomJID; } async join(nick) { this.userJID = new jid_1.JID(this.roomJID.getLocal(), this.roomJID.getDomain(), nick); this.logger.debug(`Emitting a presence for room ${this.roomJID.toString()}...`); await this.bot.sendStanza('presence', { to: this.userJID.toString() }, (0, xml_1.default)('x', { xmlns: 'http://jabber.org/protocol/muc' })); } async part() { if (!this.userJID) { return; } this.logger.debug(`Emitting a presence=unavailable for room ${this.roomJID.toString()}...`); await this.bot.sendStanza('presence', { to: this.userJID.toString(), type: 'unavailable' }); } async changeNickname(nick) { return this.join(nick); } async sendGroupchat(msg, references) { if (!this.userJID) { return; } this.logger.debug(`Emitting a groupchat message for room ${this.roomJID.toString()}...`); const children = []; children.push((0, xml_1.default)('body', {}, msg)); if (references) { references.forEach(reference => { children.push(reference.toXml()); }); } await this.bot.sendStanza('message', { type: 'groupchat', to: this.roomJID.toString() }, ...children); } async moderateMessage(stanza, reason) { const messageId = stanza.uniqueAndStableStanzaID(); if (!messageId) { this.logger.error('Can\'t emit a retract for a message without uniqueAndStableStanzaID.'); return; } this.logger.debug(`Emitting a retract for room ${this.roomJID.toString()} and message ${messageId}...`); const moderateChildren = [ (0, xml_1.default)('retract', { xmlns: 'urn:xmpp:message-retract:0' }) ]; if (reason) { moderateChildren.push((0, xml_1.default)('reason', {}, reason)); } const applyTo = (0, xml_1.default)('apply-to', { xmlns: 'urn:xmpp:fasten:0', id: messageId }, (0, xml_1.default)('moderate', { xmlns: 'urn:xmpp:message-moderate:0' }, ...moderateChildren)); await this.bot.sendStanza('iq', { type: 'set', to: this.roomJID.toString(), id: xmppid() }, applyTo); } receiveStanza(stanza) { try { if (stanza.stanzaType === 'presence') { this.receivePresenceStanza(stanza); } if (stanza.stanzaType === 'message') { this.receiveMessageStanza(stanza); } } catch (err) { this.logger.error('Error when processing a stanza: ' + err); } } receivePresenceStanza(stanza) { const from = stanza.from; if (!from) { this.logger.debug('[Room:receivePresenceStanza] no from, discard.'); return; } if (!from.getResource()) { this.logger.debug('[Room:receivePresenceStanza] no resource in from, discard.'); return; } if (stanza.type === 'error') { this.logger.error('[Room:receivePresenceStanza] Received error stanza. Dont deal with errors yet, discard'); return; } let user = this.roster.get(from.toString()); const newNickname = stanza.isNickNameChange(); if (newNickname !== false) { if (!user) { this.logger.error('[Room:receivePresenceStanza] Received a nickname change stanza, but the user is not known. Ignoring.'); return; } this.logger.debug('[Room:receivePresenceStanza] Detecting a nickname change, updating the roster'); const oldJID = new jid_1.JID(user.jid.local, user.jid.domain, user.jid.resource); this.roster.delete(from.toString()); user.updateNick(newNickname); this.roster.set(user.jid.toString(), user); this.emit('room_nick_changed', user, oldJID); return; } let updated = false; if (!user) { this.logger.debug('[Room:receivePresenceStanza] user was not in roster, creating it'); user = new user_1.RoomUser(this, stanza); this.roster.set(from.toString(), user); if (this.isOnline()) { updated = true; } } if (user.update(stanza)) { updated = true; } if (user.isMe()) { const previousState = this.state; this.state = user.isOnline() ? 'online' : 'offline'; if (previousState !== 'online' && this.state === 'online') { this.emit('room_roster_initialized', this.getOnlineUsers()); } } if (updated && this.isOnline()) { if (user.isOnline()) { this.logger.debug('[Room:receivePresenceStanza] user was previously not online, emitting room_joined event'); this.emit('room_joined', user); } else { this.logger.debug('[Room:receivePresenceStanza] user was previously online, emitting room_parted event'); this.emit('room_parted', user); } } } receiveMessageStanza(stanza) { const from = stanza.from; if (!from) { return; } if (!this.isOnline()) { return; } if (stanza.type !== 'groupchat') { return; } if (this.userJID && from.equals(this.userJID)) { return; } if (stanza.isDelayed()) { return; } const body = stanza.body(); if (!body) { return; } const user = this.roster.get(from.toString()); if (!user) { this.logger.error(`Cant find user ${from.toString()} in room ${this.roomJID.toString()} roster.`); return; } this.emit('room_message', stanza, user); if (body.startsWith('!')) { const parameters = body.split(/\s+/); const command = parameters.shift()?.substring(1); if (command) { this.emit('room_command', command, parameters, stanza, user); } } if (this.userJID) { const searchJIDs = [this.userJID]; const addr = this.bot.getAddress(); if (addr) { searchJIDs.push(addr); } if (stanza.isMentionned(searchJIDs)) { this.logger.debug('[HandlerRespond] Im mentionned in the message, using XMPP references'); this.emit('room_mentionned', stanza, user); } } } attachHandler(handler) { if (handler.id in this.handlers) { throw new Error('Can\'t attach handler, there is already an handler with the same id: ' + handler.id); } this.handlers[handler.id] = handler; } detachHandlers() { this.logger.debug('Stoping and Detaching all handlers'); for (const id of Object.keys(this.handlers)) { const handler = this.handlers[id]; handler.stop(); delete this.handlers[id]; } } getHandlerById(id) { return this.handlers[id] ?? null; } detachHandlerById(id) { const handler = this.handlers[id]; if (!handler) { return; } this.logger.debug('Stoping and Detaching handler ' + id); handler.stop(); delete this.handlers[id]; } } exports.Room = Room; //# sourceMappingURL=room.js.map