Restore forgotten channels before sending something into them

This commit is contained in:
Andrew Ferrazzutti 2022-03-21 01:33:22 -04:00
parent b9eb4ce0ac
commit 66262caa63
5 changed files with 79 additions and 24 deletions

View File

@ -49,7 +49,7 @@ from ..types.request import (
CommandResultDoneValue
)
from .types import PortalChannelInfo, UserInfoUnion
from .types import PortalChannelInfo, UserInfoUnion, ChannelProps
from .errors import InvalidAccessToken
from .error_helper import raise_unsuccessful_response
@ -207,34 +207,34 @@ class Client:
)
return profile_req_struct.profile
async def get_portal_channel_info(self, channel_id: Long) -> PortalChannelInfo:
async def get_portal_channel_info(self, channel_props: ChannelProps) -> PortalChannelInfo:
return await self._api_user_request_result(
PortalChannelInfo,
"get_portal_channel_info",
channel_id=channel_id.serialize()
channel_props=channel_props.serialize(),
)
async def get_participants(self, channel_id: Long) -> list[UserInfoUnion]:
async def get_participants(self, channel_props: ChannelProps) -> list[UserInfoUnion]:
return await self._api_user_request_result(
ResultListType(UserInfoUnion),
"get_participants",
channel_id=channel_id.serialize()
channel_props=channel_props.serialize()
)
async def get_chats(self, channel_id: Long, sync_from: Long | None, limit: int | None) -> list[Chatlog]:
async def get_chats(self, channel_props: ChannelProps, sync_from: Long | None, limit: int | None) -> list[Chatlog]:
return await self._api_user_request_result(
ResultListType(Chatlog),
"get_chats",
channel_id=channel_id.serialize(),
channel_props=channel_props.serialize(),
sync_from=sync_from.serialize() if sync_from else None,
limit=limit
)
async def send_message(self, channel_id: Long, text: str) -> Chatlog:
async def send_message(self, channel_props: ChannelProps, text: str) -> Chatlog:
return await self._api_user_request_result(
Chatlog,
"send_message",
channel_id=channel_id.serialize(),
channel_props=channel_props.serialize(),
text=text
)

View File

@ -21,7 +21,9 @@ from attr import dataclass
from mautrix.types import SerializableAttrs, JSON, deserializer
from ..types.bson import Long
from ..types.channel.channel_info import NormalChannelInfo
from ..types.channel.channel_type import ChannelType
from ..types.openlink.open_channel_info import OpenChannelInfo
from ..types.user.channel_user_info import NormalChannelUserInfo, OpenChannelUserInfo
@ -56,3 +58,9 @@ class PortalChannelInfo(SerializableAttrs):
participants: list[UserInfoUnion]
# TODO Image
channel_info: Optional[ChannelInfoUnion] = None # Should be set manually by caller
@dataclass
class ChannelProps(SerializableAttrs):
id: Long
type: ChannelType

View File

@ -52,7 +52,7 @@ from .kt.types.channel.channel_info import ChannelInfo
from .kt.types.channel.channel_type import KnownChannelType, ChannelType
from .kt.types.chat.chat import Chatlog
from .kt.client.types import UserInfoUnion, PortalChannelInfo
from .kt.client.types import UserInfoUnion, PortalChannelInfo, ChannelProps
from .kt.client.errors import CommandException
if TYPE_CHECKING:
@ -194,6 +194,13 @@ class Portal(DBPortal, BasePortal):
raise ValueError(f"Non-direct chat portal should have no sender, but has sender {self._kt_sender}")
return self._kt_sender
@property
def channel_props(self) -> ChannelProps:
return ChannelProps(
id=self.ktid,
type=self.kt_type
)
@property
def main_intent(self) -> IntentAPI:
if not self._main_intent:
@ -245,7 +252,7 @@ class Portal(DBPortal, BasePortal):
) -> PortalChannelInfo:
if not info:
self.log.debug("Called update_info with no info, fetching channel info...")
info = await source.client.get_portal_channel_info(self.ktid)
info = await source.client.get_portal_channel_info(self.channel_props)
changed = False
if not self.is_direct:
changed = any(
@ -400,7 +407,7 @@ class Portal(DBPortal, BasePortal):
async def _update_participants(self, source: u.User, participants: list[UserInfoUnion] | None = None) -> bool:
if participants is None:
self.log.debug("Called _update_participants with no participants, fetching them now...")
participants = await source.client.get_participants(self.ktid)
participants = await source.client.get_participants(self.channel_props)
changed = False
if not self._main_intent:
assert self.is_direct, "_main_intent for non-direct chat portal should have been set already"
@ -736,7 +743,7 @@ class Portal(DBPortal, BasePortal):
converted = await matrix_to_kakaotalk(message, self.mxid, self.log)
try:
chatlog = await sender.client.send_message(
self.ktid,
self.channel_props,
text=converted.text,
# TODO
#mentions=converted.mentions,
@ -959,7 +966,7 @@ class Portal(DBPortal, BasePortal):
self.log.debug(f"Backfilling history through {source.mxid}")
self.log.debug(f"Fetching {f'up to {limit}' if limit else 'all'} messages through {source.ktid}")
messages = await source.client.get_chats(
channel_info.channelId,
self.channel_props,
after_log_id,
limit
)
@ -989,7 +996,6 @@ class Portal(DBPortal, BasePortal):
# TODO Save kt_sender in DB instead? Depends on if DM channels are shared...
user = await u.User.get_by_ktid(self.kt_receiver)
assert user, f"Found no user for this portal's receiver of {self.kt_receiver}"
# TODO Should this backfill? Useful for forgotten channels
await self._update_participants(user)
else:
self.log.debug("Not setting _main_intent of new direct chat until after checking participant list")

View File

@ -499,7 +499,7 @@ class User(DBUser, BaseUser):
kt_receiver=self.ktid,
kt_type=channel_info.type
)
portal_info = await self.client.get_portal_channel_info(channel_info.channelId)
portal_info = await self.client.get_portal_channel_info(portal.channel_props)
portal_info.channel_info = channel_info
if not portal.mxid:
await portal.create_matrix_room(self, portal_info)

View File

@ -24,6 +24,8 @@ import {
util,
} from "node-kakao"
/** @typedef {import("node-kakao").OAuthCredential} OAuthCredential */
/** @typedef {import("node-kakao/dist/talk").TalkChannelList} TalkChannelList */
/** @typedef {import("node-kakao").ChannelType} ChannelType */
import chat from "node-kakao/chat"
const { KnownChatType } = chat
@ -68,6 +70,30 @@ class UserClient {
return userClient
}
/**
* @param {Object} channel_props
* @param {Long} channel_props.id
* @param {ChannelType} channel_props.type
*/
async getChannel(channel_props) {
let channel = this.#talkClient.channelList.get(channel_props.id)
if (channel) {
return channel
} else {
const channelList = getChannelListForType(
this.#talkClient.channelList,
channel_props.type
)
const res = await channelList.addChannel({
channelId: channel_props.id,
})
if (!res.success) {
throw new Error(`Unable to add ${channel_props.type} channel ${channel_props.id}`)
}
return res.result
}
}
close() {
this.#talkClient.close()
}
@ -337,11 +363,11 @@ export default class PeerClient {
/**
* @param {Object} req
* @param {string} req.mxid
* @param {Long} req.channel_id
* @param {Object} req.channel_props
*/
getPortalChannelInfo = async (req) => {
const userClient = this.#getUser(req.mxid)
const talkChannel = userClient.talkClient.channelList.get(req.channel_id)
const talkChannel = await userClient.getChannel(req.channel_props)
const res = await talkChannel.updateAll()
if (!res.success) return res
@ -356,24 +382,24 @@ export default class PeerClient {
/**
* @param {Object} req
* @param {string} req.mxid
* @param {Long} req.channel_id
* @param {Object} req.channel_props
*/
getParticipants = async (req) => {
const userClient = this.#getUser(req.mxid)
const talkChannel = userClient.getChannel(req.channel_id)
const talkChannel = await userClient.getChannel(req.channel_props)
return await talkChannel.getAllLatestUserInfo()
}
/**
* @param {Object} req
* @param {string} req.mxid
* @param {Long} req.channel_id
* @param {Object} req.channel_props
* @param {Long?} req.sync_from
* @param {Number?} req.limit
*/
getChats = async (req) => {
const userClient = this.#getUser(req.mxid)
const talkChannel = userClient.talkClient.channelList.get(req.channel_id)
const talkChannel = await userClient.getChannel(req.channel_props)
const res = await talkChannel.getChatListFrom(req.sync_from)
if (res.success && 0 < req.limit && req.limit < res.result.length) {
@ -385,12 +411,12 @@ export default class PeerClient {
/**
* @param {Object} req
* @param {string} req.mxid
* @param {Long} req.channel_id
* @param {Object} req.channel_props
* @param {string} req.text
*/
sendMessage = async (req) => {
const userClient = this.#getUser(req.mxid)
const talkChannel = userClient.talkClient.channelList.get(req.channel_id)
const talkChannel = await userClient.getChannel(req.channel_props)
return await talkChannel.sendChat({
type: KnownChatType.TEXT,
@ -517,3 +543,18 @@ export default class PeerClient {
return value
}
}
/**
* @param {TalkChannelList} channelList
* @param {ChannelType} channelType
*/
function getChannelListForType(channelList, channelType) {
switch (channelType) {
case "OM":
case "OD":
return channelList.open
default:
return channelList.normal
}
}