diff --git a/src/portal.js b/src/portal.js index 99cdfa76..2df65ddd 100644 --- a/src/portal.js +++ b/src/portal.js @@ -214,6 +214,42 @@ class Portal { typer.intent.sendTyping(this.roomID, true/*, 5500*/) } + /** + * Add a Telegram user to this room. + * + * This makes the Matrix puppet of that Telegram user join this room. If the Telegram user is also a puppet + * controlled by a Matrix user, that Matrix user is invited as well. + * + * @param {number} userID The Telegram ID of the user to add. + */ + async addUser(userID) { + const matrixUser = await this.app.getMatrixUserByTelegramID(userID) + if (matrixUser) { + matrixUser.join(this) + this.inviteMatrix(matrixUser.userID) + } + const telegramUser = await this.app.getTelegramUser(userID) + await telegramUser.intent.join(this.roomID) + } + + /** + * Remove a Telegram user from this room. + * + * This makes the Matrix puppet of the given Telegram user leave this room. If the Telegram user is also a puppet + * controlled by a Matrix user, that Matrix user is kicked with the message "Left Telegram chat". + * + * @param {number} userID The Telegram ID of the user to remove. + */ + async deleteUser(userID) { + const matrixUser = await this.app.getMatrixUserByTelegramID(userID) + if (matrixUser) { + matrixUser.leave(this) + this.kickMatrix(matrixUser.userID, "Left Telegram chat") + } + const telegramUser = await this.app.getTelegramUser(userID) + telegramUser.intent.leave(this.roomID) + } + /** * Handle a Telegram service message event. * @@ -242,22 +278,18 @@ class Portal { } } this.lastMessageIDs.set(evt.source.userID, evt.id) - let matrixUser, telegramUser switch (evt.action._) { case "messageActionChatCreate": // Portal gets created at beginning if it doesn't exist // Falls through to invite everyone in initial user list case "messageActionChatAddUser": for (const userID of evt.action.users) { - matrixUser = await this.app.getMatrixUserByTelegramID(userID) - if (matrixUser) { - matrixUser.join(this) - this.inviteMatrix(matrixUser.userID) - } - telegramUser = await this.app.getTelegramUser(userID) - telegramUser.intent.join(this.roomID) + await this.addUser(userID) } break + case "messageActionChatJoinedByLink": + await this.addUser(evt.from) + break case "messageActionChannelCreate": // Portal gets created at beginning if it doesn't exist // Channels don't send initial user lists 3:< @@ -276,13 +308,7 @@ class Portal { await sender.sendEmote(this.roomID, "upgraded this group to a supergroup.") break case "messageActionChatDeleteUser": - matrixUser = await this.app.getMatrixUserByTelegramID(evt.action.user_id) - if (matrixUser) { - matrixUser.leave(this) - this.kickMatrix(matrixUser.userID, "Left Telegram chat") - } - telegramUser = await this.app.getTelegramUser(evt.action.user_id) - telegramUser.intent.leave(this.roomID) + await this.deleteUser(evt.action.user_id) break case "messageActionChatEditPhoto": const sizes = evt.action.photo.sizes diff --git a/src/telegram-puppet.js b/src/telegram-puppet.js index c6b96207..81289add 100644 --- a/src/telegram-puppet.js +++ b/src/telegram-puppet.js @@ -386,7 +386,53 @@ class TelegramPuppet { }) } + async receiveUsers(users) { + this.app.debug("green", "Handling received users:", JSON.stringify(users, "", " ")) + for (const user of users) { + const telegramUser = await this.app.getTelegramUser(user.id) + await telegramUser.updateInfo(this, user, true) + } + } + async receiveChats(chats) { + this.app.debug("green", "Handling received chats:", JSON.stringify(chats, "", " ")) + for (const chat of chats) { + const peer = new TelegramPeer(chat._, chat.id, { + accessHash: chat.access_hash, + }) + const portal = await this.app.getPortalByPeer(peer) + await portal.updateInfo(this, chat) + } + } + + async handleUpdatesTooLong() { + this.app.debug("magenta", "Handling updatesTooLong", this.pts, this.date) + const dat = await this.client("updates.getDifference", { + pts: this.pts, + date: this.date, + qts: -1, + }) + if (dat._ === "updates.differenceEmpty") { + this.date = dat.date + return + } + this.app.debug("magenta", `updates.getDifference: ${JSON.stringify(dat, "", " ")}`) + // TODO use dat.users and dat.chats + await this.receiveUsers(dat.users) + await this.receiveChats(dat.chats) + this.pts = dat.state.pts + this.date = dat.state.date + for (const message of dat.new_messages) { + await this.onUpdate({ + _: "updateNewMessage", + pts: this.pts, + message, + }) + } + for (const update of dat.other_updates) { + await this.onUpdate(update) + } + } async handleUpdate(data) { if (!data.update || data.update._ !== "updateUserStatus") { @@ -399,15 +445,12 @@ class TelegramPuppet { await this.onUpdate(data.update) break case "updates": - // TODO use data.users and data.chats - this.app.debug("green", "Received updates users:", JSON.stringify(data.users, "", " ")) - this.app.debug("green", "Received updates chats:", JSON.stringify(data.chats, "", " ")) this.date = data.date - const updateHandlers = [] + await this.receiveUsers(data.users) + await this.receiveChats(data.chats) for (const update of data.updates) { - updateHandlers.push(this.onUpdate(update)) + await this.onUpdate(update) } - await Promise.all(updateHandlers) break case "updateShortMessage": case "updateShortChatMessage": @@ -418,30 +461,7 @@ class TelegramPuppet { this.app.warn("updatesTooLong received, but we don't have a persistent timestamp :(") break } - this.app.debug("magenta", "Handling updatesTooLong", this.pts, this.date) - const dat = await this.client("updates.getDifference", { - pts: this.pts, - date: this.date, - qts: -1, - }) - if (dat._ === "updates.differenceEmpty") { - this.date = dat.date - break - } - this.app.debug("magenta", `updates.getDifference: ${JSON.stringify(dat, "", " ")}`) - // TODO use dat.users and dat.chats - this.pts = dat.state.pts - this.date = dat.state.date - for (const message of dat.new_messages) { - this.onUpdate({ - _: "updateNewMessage", - pts: this.pts, - message, - }) - } - for (const update of dat.other_updates) { - this.onUpdate(update) - } + await this.handleUpdatesTooLong() break default: this.app.warn("Unrecognized update type:", data._)