import { ComponentBot, ComponentConnectionConfig } from './component' import { XMPPStanza } from './types' import { logger } from '../logger' interface RoomComponentBotRoomDescription { jid: string nick: string users: Map } abstract class RoomComponentBot extends ComponentBot { protected readonly rooms: {[jid: string]: RoomComponentBotRoomDescription} = {} constructor ( botName: string, connectionConfig: ComponentConnectionConfig, roomIds: string[], protected readonly nick: string ) { super(botName, connectionConfig) for (const roomId of roomIds) { this.rooms[roomId] = { jid: roomId, nick: nick, users: new Map() } } } async onOnline (): Promise { for (const roomId in this.rooms) { const room = this.rooms[roomId] logger.debug(`Connecting to room ${room.jid}...`) const presence = this.xml( 'presence', { from: this.address?.toString(), to: room.jid + '/' + room.nick }, this.xml('x', { xmlns: 'http://jabber.org/protocol/muc' }) ) await this.xmpp?.send(presence) } await super.onOnline() } protected async onPresence (stanza: XMPPStanza): Promise { const [stanzaRoomId, stanzaNick] = stanza.attrs?.from.split('/') if (this.rooms[stanzaRoomId]) { await this.onRoomPresence(stanzaRoomId, stanza, stanzaNick) } } public async sendGroupchat (roomId: string, msg: string): Promise { const room = this.rooms[roomId] if (!room) { logger.error('Trying to send a groupchat on an unknown room: ' + roomId) return } const message = this.xml( 'message', { type: 'groupchat', to: room.jid, from: this.address?.toString() }, this.xml('body', {}, msg) ) logger.debug('Sending message...: ' + (message.toString() as string)) await this.xmpp?.send(message) } public async stop (): Promise { for (const roomId in this.rooms) { const room = this.rooms[roomId] logger.debug(`Leaving room ${room.jid}...`) const presence = this.xml( 'presence', { from: this.address?.toString(), to: room.jid + '/' + room.nick, type: 'unavailable' } ) // FIXME: should wait for a presence stanza from the server. await this.xmpp?.send(presence) } await super.stop() } protected async onRoomPresence ( roomId: string, stanza: XMPPStanza, nick?: string ): Promise { const room = this.rooms[roomId] if (!room) { return } if (!nick) { return } const isPresent = stanza.attrs?.type !== 'unavailable' // FIXME: selfPresence should better be tested by searching status=110 const selfPresence = room.nick === nick if (!isPresent) { room.users.delete(nick) if (!selfPresence) { await this.onRoomPart(roomId, nick) } return } room.users.set(nick, { nick }) if (!selfPresence) { await this.onRoomJoin(roomId, nick) } } protected async onRoomJoin (_roomId: string, _nick: string): Promise {} protected async onRoomPart (_roomId: string, _nick: string): Promise {} } export { RoomComponentBot }