From 53d3170c04dca5b62a0772c2752b2594df8de0bf Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Tue, 10 May 2022 21:33:11 -0400 Subject: [PATCH] Fixes to leaves and DM creation Fixes -203 error for MemoChats, and automatically retries channel creation when it fails the first time --- .../commands/kakaotalk.py | 5 +++- matrix_appservice_kakaotalk/portal.py | 27 ++++++++++--------- matrix_appservice_kakaotalk/user.py | 9 ++++++- node/src/client.js | 24 ++++++++++++----- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/matrix_appservice_kakaotalk/commands/kakaotalk.py b/matrix_appservice_kakaotalk/commands/kakaotalk.py index c2d7b44..fe2b01a 100644 --- a/matrix_appservice_kakaotalk/commands/kakaotalk.py +++ b/matrix_appservice_kakaotalk/commands/kakaotalk.py @@ -311,4 +311,7 @@ async def leave(evt: CommandEvent) -> None: await evt.reply("This command may only be used in a KakaoTalk channel portal room") return await evt.mark_read() - await evt.portal.leave_kakaotalk_channel() + try: + await evt.sender.leave_channel(evt.portal) + except CommandException as e: + await evt.reply(f"Error from KakaoTalk: {e}") diff --git a/matrix_appservice_kakaotalk/portal.py b/matrix_appservice_kakaotalk/portal.py index b71d0aa..e7be31f 100644 --- a/matrix_appservice_kakaotalk/portal.py +++ b/matrix_appservice_kakaotalk/portal.py @@ -1386,10 +1386,6 @@ class Portal(DBPortal, BasePortal): else: self.log.debug(f"{user.mxid} left portal to {self.ktid}") - async def leave_kakaotalk_channel(self, user: u.User) -> None: - await user.client.leave_channel(self.channel_props) - await user.on_channel_left(self.ktid, self.kt_type) - # endregion # region KakaoTalk event handling @@ -1762,19 +1758,20 @@ class Portal(DBPortal, BasePortal): self, source: u.User, sender: p.Puppet | None, removed: p.Puppet ) -> None: sender_intent = sender.intent_for(self) if sender else self.main_intent + removed_user = await u.User.get_by_ktid(removed.ktid) if sender == removed: - removed_intent = removed.intent_for(self) - if removed_intent != self.main_intent: - await removed_intent.leave_room(self.mxid) - if not removed.is_real_user: - user = await u.User.get_by_ktid(removed.ktid) - if user: - await self.main_intent.kick_user(self.mxid, user.mxid, "Left channel from KakaoTalk") + if not removed.is_real_user and removed_user: + try: + await sender_intent.kick_user(self.mxid, removed_user.mxid, "Left channel from KakaoTalk") + except MForbidden: + pass + await removed.intent_for(self).leave_room(self.mxid) else: for removed_mxid in (r.mxid for r in ( removed, - await u.User.get_by_ktid(removed.ktid) if not removed.is_real_user else None + removed_user if not removed.is_real_user else None ) if r): + # NOTE KakaoTalk kick = Matrix ban try: await sender_intent.ban_user( self.mxid, removed_mxid, None if sender else "Kicked by channel admin" @@ -1785,7 +1782,11 @@ class Portal(DBPortal, BasePortal): await self.main_intent.ban_user( self.mxid, removed_mxid, reason=f"Kicked by {sender.name}" ) - # TODO Clean and delete if removed is real user and portal is direct / not open + if self.is_direct and removed.ktid == self.kt_receiver: + self.log.info( + f"{removed.ktid} was the recipient puppet of this portal. Cleaning up and deleting..." + ) + await self.cleanup_and_delete() # TODO Find when or if there is a listener for this # TODO Confirm whether this can refer to any user that was kicked, or only to the current user diff --git a/matrix_appservice_kakaotalk/user.py b/matrix_appservice_kakaotalk/user.py index cd60d10..937aa5a 100644 --- a/matrix_appservice_kakaotalk/user.py +++ b/matrix_appservice_kakaotalk/user.py @@ -685,7 +685,7 @@ class User(DBUser, BaseUser): kt_type = KnownChannelType.MemoChat memo_ids = await self.client.get_memo_ids() if not memo_ids: - ktid = Long(0) + ktid = None else: ktid = memo_ids[0] if len(memo_ids) > 1: @@ -702,6 +702,13 @@ class User(DBUser, BaseUser): ktid, kt_receiver=self.ktid, create=create, kt_type=kt_type ) if ktid else None + # region Matrix->KakaoTalk commands + + async def leave_channel(self, portal: po.Portal) -> None: + await self.client.leave_channel(portal.channel_props) + await self.on_channel_left(portal.ktid, portal.kt_type) + + # endregion # region KakaoTalk event handling async def on_connect(self, force_sync: bool) -> bool: diff --git a/node/src/client.js b/node/src/client.js index abba74f..7849224 100644 --- a/node/src/client.js +++ b/node/src/client.js @@ -1138,15 +1138,27 @@ export default class PeerClient { const userClient = this.#getUser(req.mxid) const channelList = userClient.talkClient.channelList.normal - const res = - req.user_id != userClient.userId - ? await channelList.createChannel({ + const createChannel = + !req.user_id.equals(userClient.userId) + ? channelList.createChannel.bind(channelList, { userList: [{ userId: req.user_id }], }) - : await channelList.createMemoChannel() + : channelList.createMemoChannel.bind(channelList) - if (!res.success) return res - return makeCommandResult(res.result.channelId) + const retry_delay = 2000 + let retries_left = 1 + let res + do { + res = await createChannel() + if (res.success) { + return makeCommandResult(res.result.channelId) + } + this.error(`Failed to create direct chat, try again in ${retry_delay} ms (${retries_left - 1} tries remaining)`) + await new Promise(resolve => setTimeout(resolve, retry_delay)) + } while (retries_left--) + + this.error(`Failed to create direct chat, not retrying`) + return res } /**