Compare commits

..

No commits in common. "79fe8748b1ceca8c128b83ae0f208db2d8e0b937" and "36598c34f6ed451ebb84d7d578aba6f346f7b2c9" have entirely different histories.

4 changed files with 28 additions and 70 deletions

View File

@ -65,13 +65,9 @@ async def whoami(evt: CommandEvent) -> None:
await evt.reply(f"Error from KakaoTalk: {e}") await evt.reply(f"Error from KakaoTalk: {e}")
return return
if own_info: if own_info:
puppet = await pu.Puppet.get_by_ktid(evt.sender.ktid)
uuid = f"`{own_info.more.uuid}` ({'searchable' if own_info.more.uuidSearchable else 'hidden'})" if own_info.more.uuid else "_none_" uuid = f"`{own_info.more.uuid}` ({'searchable' if own_info.more.uuidSearchable else 'hidden'})" if own_info.more.uuid else "_none_"
await evt.reply( await evt.reply(
f"You're logged in as **{own_info.more.nickName}**" f"You're logged in as **{own_info.more.nickName}** (KakaoTalk ID: {uuid}, internal ID: `{evt.sender.ktid}`)"
f"\n* KakaoTalk ID: {uuid}"
f"\n* Internal ID: `{evt.sender.ktid}`"
f"\n* Matrix user: [{puppet.name}](https://matrix.to/#/{puppet.default_mxid})"
) )
else: else:
await evt.reply( await evt.reply(
@ -157,13 +153,13 @@ async def _set_id_searchable(evt: CommandEvent, searchable: bool) -> None:
else: else:
await evt.reply(f"Successfully made KakaoTalk ID {'searchable' if searchable else 'hidden'}") await evt.reply(f"Successfully made KakaoTalk ID {'searchable' if searchable else 'hidden'}")
async def _get_search_result_puppet(source: u.User, friend_struct: FriendStruct) -> pu.Puppet: async def _get_search_result_puppet(source: u.User, friend_struct: FriendStruct) -> pu.Puppet:
puppet = await pu.Puppet.get_by_ktid(friend_struct.userId) puppet = await pu.Puppet.get_by_ktid(friend_struct.userId)
if not puppet.name_set: if not puppet.name_set:
await puppet.update_info_from_friend(source, friend_struct) await puppet.update_info_from_friend(source, friend_struct)
return puppet return puppet
@command_handler( @command_handler(
needs_auth=True, needs_auth=True,
management_only=False, management_only=False,
@ -315,7 +311,4 @@ async def leave(evt: CommandEvent) -> None:
await evt.reply("This command may only be used in a KakaoTalk channel portal room") await evt.reply("This command may only be used in a KakaoTalk channel portal room")
return return
await evt.mark_read() await evt.mark_read()
try: await evt.portal.leave_kakaotalk_channel()
await evt.sender.leave_channel(evt.portal)
except CommandException as e:
await evt.reply(f"Error from KakaoTalk: {e}")

View File

@ -1386,6 +1386,10 @@ class Portal(DBPortal, BasePortal):
else: else:
self.log.debug(f"{user.mxid} left portal to {self.ktid}") 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 # endregion
# region KakaoTalk event handling # region KakaoTalk event handling
@ -1758,20 +1762,19 @@ class Portal(DBPortal, BasePortal):
self, source: u.User, sender: p.Puppet | None, removed: p.Puppet self, source: u.User, sender: p.Puppet | None, removed: p.Puppet
) -> None: ) -> None:
sender_intent = sender.intent_for(self) if sender else self.main_intent 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: if sender == removed:
if not removed.is_real_user and removed_user: removed_intent = removed.intent_for(self)
try: if removed_intent != self.main_intent:
await sender_intent.kick_user(self.mxid, removed_user.mxid, "Left channel from KakaoTalk") await removed_intent.leave_room(self.mxid)
except MForbidden: if not removed.is_real_user:
pass user = await u.User.get_by_ktid(removed.ktid)
await removed.intent_for(self).leave_room(self.mxid) if user:
await self.main_intent.kick_user(self.mxid, user.mxid, "Left channel from KakaoTalk")
else: else:
for removed_mxid in (r.mxid for r in ( for removed_mxid in (r.mxid for r in (
removed, removed,
removed_user if not removed.is_real_user else None await u.User.get_by_ktid(removed.ktid) if not removed.is_real_user else None
) if r): ) if r):
# NOTE KakaoTalk kick = Matrix ban
try: try:
await sender_intent.ban_user( await sender_intent.ban_user(
self.mxid, removed_mxid, None if sender else "Kicked by channel admin" self.mxid, removed_mxid, None if sender else "Kicked by channel admin"
@ -1782,11 +1785,7 @@ class Portal(DBPortal, BasePortal):
await self.main_intent.ban_user( await self.main_intent.ban_user(
self.mxid, removed_mxid, reason=f"Kicked by {sender.name}" self.mxid, removed_mxid, reason=f"Kicked by {sender.name}"
) )
if self.is_direct and removed.ktid == self.kt_receiver: # TODO Clean and delete if removed is real user and portal is direct / not open
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 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 # TODO Confirm whether this can refer to any user that was kicked, or only to the current user

View File

@ -685,7 +685,7 @@ class User(DBUser, BaseUser):
kt_type = KnownChannelType.MemoChat kt_type = KnownChannelType.MemoChat
memo_ids = await self.client.get_memo_ids() memo_ids = await self.client.get_memo_ids()
if not memo_ids: if not memo_ids:
ktid = None ktid = Long(0)
else: else:
ktid = memo_ids[0] ktid = memo_ids[0]
if len(memo_ids) > 1: if len(memo_ids) > 1:
@ -702,13 +702,6 @@ class User(DBUser, BaseUser):
ktid, kt_receiver=self.ktid, create=create, kt_type=kt_type ktid, kt_receiver=self.ktid, create=create, kt_type=kt_type
) if ktid else None ) 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 # region KakaoTalk event handling
async def on_connect(self, force_sync: bool) -> bool: async def on_connect(self, force_sync: bool) -> bool:

View File

@ -155,19 +155,10 @@ class UserClient {
}) })
this.#talkClient.on("chat_read", (chat, channel, reader) => { this.#talkClient.on("chat_read", (chat, channel, reader) => {
let senderId this.log(`Chat ${chat.logId} read in channel ${channel.channelId} by ${reader.userId}`)
if (reader) {
senderId = reader.userId
} else if (channel.info.type == "MemoChat") {
senderId = channel.clientUser.userId
} else {
this.error(`Chat ${chat.logId} read in channel ${channel.channelId} by unknown reader (channel type: ${channel.info.type || "none"})`)
return
}
this.log(`Chat ${chat.logId} read in channel ${channel.channelId} by ${senderId}`)
this.write("chat_read", { this.write("chat_read", {
chatId: chat.logId, chatId: chat.logId,
senderId: senderId, senderId: reader.userId,
channelId: channel.channelId, channelId: channel.channelId,
channelType: channel.info.type, channelType: channel.info.type,
}) })
@ -307,7 +298,7 @@ class UserClient {
} }
}) })
this.#talkClient.on("disconnected", reason => { this.#talkClient.on("disconnected", (reason) => {
this.log(`Disconnected (reason=${reason})`) this.log(`Disconnected (reason=${reason})`)
this.disconnect() this.disconnect()
this.write("disconnected", { this.write("disconnected", {
@ -322,7 +313,7 @@ class UserClient {
}) })
}) })
this.#talkClient.on("error", err => { this.#talkClient.on("error", (err) => {
this.log(`Client error: ${err}`) this.log(`Client error: ${err}`)
this.write("error", { this.write("error", {
error: err, error: err,
@ -1081,7 +1072,7 @@ export default class PeerClient {
if (!talkChannel.getUserInfo(user)) { if (!talkChannel.getUserInfo(user)) {
throw new ProtocolError("Cannot set permission level of a user that is not a channel participant") throw new ProtocolError("Cannot set permission level of a user that is not a channel participant")
} }
if (req.user_id.equals(talkChannel.clientUser.userId)) { if (req.user_id == talkChannel.clientUser.userId) {
throw new ProtocolError("Cannot change own permission level") throw new ProtocolError("Cannot change own permission level")
} }
return await talkChannel.setUserPerm(user, req.perm) return await talkChannel.setUserPerm(user, req.perm)
@ -1144,31 +1135,13 @@ export default class PeerClient {
* @param {Long} req.user_id * @param {Long} req.user_id
*/ */
createDirectChat = async (req) => { createDirectChat = async (req) => {
const userClient = this.#getUser(req.mxid) const channelList = this.#getUser(req.mxid).talkClient.channelList.normal
const channelList = userClient.talkClient.channelList.normal const res = await channelList.createChannel({
const createChannel =
!req.user_id.equals(userClient.userId)
? channelList.createChannel.bind(channelList, {
userList: [{ userId: req.user_id }], userList: [{ userId: req.user_id }],
}) })
: channelList.createMemoChannel.bind(channelList) if (!res.success) return res
const retry_delay = 2000
let retries_left = 1
let res
do {
res = await createChannel()
if (res.success) {
return makeCommandResult(res.result.channelId) 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
}
/** /**
* @param {Object} req * @param {Object} req