diff --git a/src/bot.js b/src/bot.js index eaa1fcf..143ba99 100644 --- a/src/bot.js +++ b/src/bot.js @@ -11,6 +11,8 @@ import * as matrix from "matrix-js-sdk"; import logger from "./logger"; import encrypt from "./encrypt-attachment"; +const BOT_SIGNAL_END_CHAT = 'END_CHAT' + class OcrccBot { constructor(botConfig) { @@ -217,23 +219,24 @@ class OcrccBot { } handleBotCommand(event) { - try { - const senderId = event.getSender(); - const roomId = event.getRoomId(); - const content = event.getContent(); - const command = content.body.substring("!bot".length).trim(); - - switch (command) { - case "transcript": - this.sendTranscript(senderId, roomId); - break; - case "transcript please": - this.sendTranscript(senderId, roomId); - break; - case "delete transcript": - this.deleteTranscript(senderId, roomId); - break; - case "hi": + const botCommands = [ + { + keyword: 'transcript', + function: (senderId, roomId) => { this.sendTranscript(senderId, roomId) } + }, + { + keyword: 'delete transcript', + function: (senderId, roomId) => { this.deleteTranscript(senderId, roomId) } + }, + { + keyword: 'say', + function: (senderId, roomId, message) => { + this.sendTextMessage(roomId, message, senderId); + } + }, + { + keyword: 'hi', + function: (senderId, roomId) => { const responses = [ "Hi!", "Hello", @@ -241,18 +244,28 @@ class OcrccBot { "Hi there", "Bleep bloop" ]; - const message = - responses[Math.floor(Math.random() * responses.length)]; + const message = responses[Math.floor(Math.random() * responses.length)]; this.sendTextMessage(roomId, message, senderId); - break; - default: - this.sendTextMessage( - roomId, - `Sorry, I don't know that command. I'm not a very smart bot.`, - senderId - ); - break; + } } + ] + try { + const senderId = event.getSender(); + const roomId = event.getRoomId(); + const content = event.getContent(); + const commandText = content.body.substring("!bot".length).trim(); + const command = botCommands.find(c => commandText.startsWith(c.keyword)) + + if (!command) { + this.sendTextMessage( + roomId, + `Sorry, I don't know that command. I'm not a very smart bot.`, + senderId + ); + } + + const args = commandText.substring(command.keyword.length).trim() + command.function(senderId, roomId, args) } catch (err) { logger.log("error", `ERROR EXECUTING BOT COMMAND: ${err}`); } @@ -423,9 +436,9 @@ class OcrccBot { if (!joinedRooms.includes(member.roomId)) { const room = await this.client.joinRoom(member.roomId) logger.log("info", "AUTO JOINED ROOM => " + room.roomId) - const currentDate = new Date() - const chatDate = currentDate.toLocaleDateString() - const chatTime = currentDate.toLocaleTimeString() + const inviteDate = event.getDate() + const chatDate = inviteDate.toLocaleDateString() + const chatTime = inviteDate.toLocaleTimeString() const roomId = room.roomId.split(':')[0] const notification = `Incoming support chat at ${chatTime} (room ID: ${roomId})` this.sendTextMessage(this.config.FACILITATOR_ROOM_ID, notification); @@ -509,17 +522,7 @@ class OcrccBot { const isBotInRoom = joinedRooms.includes(member.roomId) const room = this.client.getRoom(member.roomId) - if (!room) return - - // leave if there is nobody in the room - const memberCount = room.getJoinedMemberCount() - if (memberCount === 1 && isBotInRoom) { // just the bot left - logger.log("info", `LEAVING EMPTY ROOM ==> ${member.roomId}`); - this.deleteTranscript(member.userId, member.roomId); - this.localStorage.removeItem(`${member.roomId}-facilitator`) - this.localStorage.removeItem(`${member.roomId}-transcript`) - return this.client.leave(member.roomId) - } + if (!room) return; // notify room if the facilitator has left const facilitatorId = this.localStorage.getItem(`${member.roomId}-facilitator`) @@ -529,6 +532,41 @@ class OcrccBot { `${member.name} has left the chat.` ); } + + // leave if there is nobody in the room + try { + const memberCount = room.getJoinedMemberCount() + if (memberCount === 1 && isBotInRoom) { // just the bot left + logger.log("info", `LEAVING EMPTY ROOM ==> ${member.roomId}`); + this.deleteTranscript(member.userId, member.roomId); + this.localStorage.removeItem(`${member.roomId}-facilitator`) + this.localStorage.removeItem(`${member.roomId}-transcript`) + return this.client.leave(member.roomId) + } + } catch(err) { + logger.log("error", `ERROR LEAVING EMPTY ROOM ==> ${err}`); + } + + // send signal to close the chat if there are no facilitators in the room + try { + const roomMembers = await room.getJoinedMembers() + const facilitatorRoomMembers = await this.client.getJoinedRoomMembers(this.config.FACILITATOR_ROOM_ID) + const facilitators = facilitatorRoomMembers['joined'] + + let facilitatorInRoom = false; + roomMembers.forEach(member => { + if (member.userId !== this.config.BOT_USERID && Boolean(facilitators[member.userId])) { + facilitatorInRoom = true + } + }) + + if (!facilitatorInRoom) { + this.sendBotSignal(member.roomId, BOT_SIGNAL_END_CHAT) + } + + } catch(err) { + logger.log("error", `ERROR SENDING BOT SIGNAL ==> ${err}`); + } } }) } @@ -563,6 +601,15 @@ class OcrccBot { }) } + async sendBotSignal (roomId, signal, args) { + let content = { + signal: signal, + args: args, + } + + await this.client.sendStateEvent(roomId, 'm.bot.signal', content) + } + async start() { const localStorage = this.createLocalStorage(); this.localStorage = localStorage