Restore forgotten channels before sending something into them
This commit is contained in:
parent
b9eb4ce0ac
commit
66262caa63
|
@ -49,7 +49,7 @@ from ..types.request import (
|
||||||
CommandResultDoneValue
|
CommandResultDoneValue
|
||||||
)
|
)
|
||||||
|
|
||||||
from .types import PortalChannelInfo, UserInfoUnion
|
from .types import PortalChannelInfo, UserInfoUnion, ChannelProps
|
||||||
|
|
||||||
from .errors import InvalidAccessToken
|
from .errors import InvalidAccessToken
|
||||||
from .error_helper import raise_unsuccessful_response
|
from .error_helper import raise_unsuccessful_response
|
||||||
|
@ -207,34 +207,34 @@ class Client:
|
||||||
)
|
)
|
||||||
return profile_req_struct.profile
|
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(
|
return await self._api_user_request_result(
|
||||||
PortalChannelInfo,
|
PortalChannelInfo,
|
||||||
"get_portal_channel_info",
|
"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(
|
return await self._api_user_request_result(
|
||||||
ResultListType(UserInfoUnion),
|
ResultListType(UserInfoUnion),
|
||||||
"get_participants",
|
"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(
|
return await self._api_user_request_result(
|
||||||
ResultListType(Chatlog),
|
ResultListType(Chatlog),
|
||||||
"get_chats",
|
"get_chats",
|
||||||
channel_id=channel_id.serialize(),
|
channel_props=channel_props.serialize(),
|
||||||
sync_from=sync_from.serialize() if sync_from else None,
|
sync_from=sync_from.serialize() if sync_from else None,
|
||||||
limit=limit
|
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(
|
return await self._api_user_request_result(
|
||||||
Chatlog,
|
Chatlog,
|
||||||
"send_message",
|
"send_message",
|
||||||
channel_id=channel_id.serialize(),
|
channel_props=channel_props.serialize(),
|
||||||
text=text
|
text=text
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,9 @@ from attr import dataclass
|
||||||
|
|
||||||
from mautrix.types import SerializableAttrs, JSON, deserializer
|
from mautrix.types import SerializableAttrs, JSON, deserializer
|
||||||
|
|
||||||
|
from ..types.bson import Long
|
||||||
from ..types.channel.channel_info import NormalChannelInfo
|
from ..types.channel.channel_info import NormalChannelInfo
|
||||||
|
from ..types.channel.channel_type import ChannelType
|
||||||
from ..types.openlink.open_channel_info import OpenChannelInfo
|
from ..types.openlink.open_channel_info import OpenChannelInfo
|
||||||
from ..types.user.channel_user_info import NormalChannelUserInfo, OpenChannelUserInfo
|
from ..types.user.channel_user_info import NormalChannelUserInfo, OpenChannelUserInfo
|
||||||
|
|
||||||
|
@ -56,3 +58,9 @@ class PortalChannelInfo(SerializableAttrs):
|
||||||
participants: list[UserInfoUnion]
|
participants: list[UserInfoUnion]
|
||||||
# TODO Image
|
# TODO Image
|
||||||
channel_info: Optional[ChannelInfoUnion] = None # Should be set manually by caller
|
channel_info: Optional[ChannelInfoUnion] = None # Should be set manually by caller
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ChannelProps(SerializableAttrs):
|
||||||
|
id: Long
|
||||||
|
type: ChannelType
|
||||||
|
|
|
@ -52,7 +52,7 @@ from .kt.types.channel.channel_info import ChannelInfo
|
||||||
from .kt.types.channel.channel_type import KnownChannelType, ChannelType
|
from .kt.types.channel.channel_type import KnownChannelType, ChannelType
|
||||||
from .kt.types.chat.chat import Chatlog
|
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
|
from .kt.client.errors import CommandException
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
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}")
|
raise ValueError(f"Non-direct chat portal should have no sender, but has sender {self._kt_sender}")
|
||||||
return self._kt_sender
|
return self._kt_sender
|
||||||
|
|
||||||
|
@property
|
||||||
|
def channel_props(self) -> ChannelProps:
|
||||||
|
return ChannelProps(
|
||||||
|
id=self.ktid,
|
||||||
|
type=self.kt_type
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def main_intent(self) -> IntentAPI:
|
def main_intent(self) -> IntentAPI:
|
||||||
if not self._main_intent:
|
if not self._main_intent:
|
||||||
|
@ -245,7 +252,7 @@ class Portal(DBPortal, BasePortal):
|
||||||
) -> PortalChannelInfo:
|
) -> PortalChannelInfo:
|
||||||
if not info:
|
if not info:
|
||||||
self.log.debug("Called update_info with no info, fetching channel 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
|
changed = False
|
||||||
if not self.is_direct:
|
if not self.is_direct:
|
||||||
changed = any(
|
changed = any(
|
||||||
|
@ -400,7 +407,7 @@ class Portal(DBPortal, BasePortal):
|
||||||
async def _update_participants(self, source: u.User, participants: list[UserInfoUnion] | None = None) -> bool:
|
async def _update_participants(self, source: u.User, participants: list[UserInfoUnion] | None = None) -> bool:
|
||||||
if participants is None:
|
if participants is None:
|
||||||
self.log.debug("Called _update_participants with no participants, fetching them now...")
|
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
|
changed = False
|
||||||
if not self._main_intent:
|
if not self._main_intent:
|
||||||
assert self.is_direct, "_main_intent for non-direct chat portal should have been set already"
|
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)
|
converted = await matrix_to_kakaotalk(message, self.mxid, self.log)
|
||||||
try:
|
try:
|
||||||
chatlog = await sender.client.send_message(
|
chatlog = await sender.client.send_message(
|
||||||
self.ktid,
|
self.channel_props,
|
||||||
text=converted.text,
|
text=converted.text,
|
||||||
# TODO
|
# TODO
|
||||||
#mentions=converted.mentions,
|
#mentions=converted.mentions,
|
||||||
|
@ -959,7 +966,7 @@ class Portal(DBPortal, BasePortal):
|
||||||
self.log.debug(f"Backfilling history through {source.mxid}")
|
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}")
|
self.log.debug(f"Fetching {f'up to {limit}' if limit else 'all'} messages through {source.ktid}")
|
||||||
messages = await source.client.get_chats(
|
messages = await source.client.get_chats(
|
||||||
channel_info.channelId,
|
self.channel_props,
|
||||||
after_log_id,
|
after_log_id,
|
||||||
limit
|
limit
|
||||||
)
|
)
|
||||||
|
@ -989,7 +996,6 @@ class Portal(DBPortal, BasePortal):
|
||||||
# TODO Save kt_sender in DB instead? Depends on if DM channels are shared...
|
# TODO Save kt_sender in DB instead? Depends on if DM channels are shared...
|
||||||
user = await u.User.get_by_ktid(self.kt_receiver)
|
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}"
|
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)
|
await self._update_participants(user)
|
||||||
else:
|
else:
|
||||||
self.log.debug("Not setting _main_intent of new direct chat until after checking participant list")
|
self.log.debug("Not setting _main_intent of new direct chat until after checking participant list")
|
||||||
|
|
|
@ -499,7 +499,7 @@ class User(DBUser, BaseUser):
|
||||||
kt_receiver=self.ktid,
|
kt_receiver=self.ktid,
|
||||||
kt_type=channel_info.type
|
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
|
portal_info.channel_info = channel_info
|
||||||
if not portal.mxid:
|
if not portal.mxid:
|
||||||
await portal.create_matrix_room(self, portal_info)
|
await portal.create_matrix_room(self, portal_info)
|
||||||
|
|
|
@ -24,6 +24,8 @@ import {
|
||||||
util,
|
util,
|
||||||
} from "node-kakao"
|
} from "node-kakao"
|
||||||
/** @typedef {import("node-kakao").OAuthCredential} OAuthCredential */
|
/** @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"
|
import chat from "node-kakao/chat"
|
||||||
const { KnownChatType } = chat
|
const { KnownChatType } = chat
|
||||||
|
@ -68,6 +70,30 @@ class UserClient {
|
||||||
return 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() {
|
close() {
|
||||||
this.#talkClient.close()
|
this.#talkClient.close()
|
||||||
}
|
}
|
||||||
|
@ -337,11 +363,11 @@ export default class PeerClient {
|
||||||
/**
|
/**
|
||||||
* @param {Object} req
|
* @param {Object} req
|
||||||
* @param {string} req.mxid
|
* @param {string} req.mxid
|
||||||
* @param {Long} req.channel_id
|
* @param {Object} req.channel_props
|
||||||
*/
|
*/
|
||||||
getPortalChannelInfo = async (req) => {
|
getPortalChannelInfo = async (req) => {
|
||||||
const userClient = this.#getUser(req.mxid)
|
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()
|
const res = await talkChannel.updateAll()
|
||||||
if (!res.success) return res
|
if (!res.success) return res
|
||||||
|
@ -356,24 +382,24 @@ export default class PeerClient {
|
||||||
/**
|
/**
|
||||||
* @param {Object} req
|
* @param {Object} req
|
||||||
* @param {string} req.mxid
|
* @param {string} req.mxid
|
||||||
* @param {Long} req.channel_id
|
* @param {Object} req.channel_props
|
||||||
*/
|
*/
|
||||||
getParticipants = async (req) => {
|
getParticipants = async (req) => {
|
||||||
const userClient = this.#getUser(req.mxid)
|
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()
|
return await talkChannel.getAllLatestUserInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Object} req
|
* @param {Object} req
|
||||||
* @param {string} req.mxid
|
* @param {string} req.mxid
|
||||||
* @param {Long} req.channel_id
|
* @param {Object} req.channel_props
|
||||||
* @param {Long?} req.sync_from
|
* @param {Long?} req.sync_from
|
||||||
* @param {Number?} req.limit
|
* @param {Number?} req.limit
|
||||||
*/
|
*/
|
||||||
getChats = async (req) => {
|
getChats = async (req) => {
|
||||||
const userClient = this.#getUser(req.mxid)
|
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)
|
const res = await talkChannel.getChatListFrom(req.sync_from)
|
||||||
if (res.success && 0 < req.limit && req.limit < res.result.length) {
|
if (res.success && 0 < req.limit && req.limit < res.result.length) {
|
||||||
|
@ -385,12 +411,12 @@ export default class PeerClient {
|
||||||
/**
|
/**
|
||||||
* @param {Object} req
|
* @param {Object} req
|
||||||
* @param {string} req.mxid
|
* @param {string} req.mxid
|
||||||
* @param {Long} req.channel_id
|
* @param {Object} req.channel_props
|
||||||
* @param {string} req.text
|
* @param {string} req.text
|
||||||
*/
|
*/
|
||||||
sendMessage = async (req) => {
|
sendMessage = async (req) => {
|
||||||
const userClient = this.#getUser(req.mxid)
|
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({
|
return await talkChannel.sendChat({
|
||||||
type: KnownChatType.TEXT,
|
type: KnownChatType.TEXT,
|
||||||
|
@ -517,3 +543,18 @@ export default class PeerClient {
|
||||||
return value
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue