Inbound channel/user join/leave
This commit is contained in:
parent
4a68796fdf
commit
c9189d17cf
|
@ -37,12 +37,13 @@ from mautrix.util.logging import TraceLogger
|
||||||
from ...config import Config
|
from ...config import Config
|
||||||
from ...rpc import EventHandler, RPCClient
|
from ...rpc import EventHandler, RPCClient
|
||||||
|
|
||||||
from ..types.api.struct.profile import ProfileReqStruct, ProfileStruct
|
|
||||||
from ..types.api.struct import FriendListStruct
|
from ..types.api.struct import FriendListStruct
|
||||||
|
from ..types.api.struct.profile import ProfileReqStruct, ProfileStruct
|
||||||
from ..types.bson import Long
|
from ..types.bson import Long
|
||||||
from ..types.client.client_session import LoginResult
|
from ..types.channel.channel_info import ChannelInfo
|
||||||
from ..types.chat import Chatlog, KnownChatType
|
from ..types.chat import Chatlog, KnownChatType
|
||||||
from ..types.chat.attachment import MentionStruct, ReplyAttachment
|
from ..types.chat.attachment import MentionStruct, ReplyAttachment
|
||||||
|
from ..types.client.client_session import LoginResult
|
||||||
from ..types.oauth import OAuthCredential, OAuthInfo
|
from ..types.oauth import OAuthCredential, OAuthInfo
|
||||||
from ..types.openlink.open_link_user_info import OpenLinkChannelUserInfo
|
from ..types.openlink.open_link_user_info import OpenLinkChannelUserInfo
|
||||||
from ..types.packet.chat.kickout import KnownKickoutType, KickoutRes
|
from ..types.packet.chat.kickout import KnownKickoutType, KickoutRes
|
||||||
|
@ -427,6 +428,40 @@ class Client:
|
||||||
OpenLinkChannelUserInfo.deserialize(data["info"]),
|
OpenLinkChannelUserInfo.deserialize(data["info"]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def _on_channel_join(self, data: dict[str, JSON]) -> None:
|
||||||
|
await self.user.on_channel_join(
|
||||||
|
ChannelInfo.deserialize(data["channelInfo"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _on_channel_left(self, data: dict[str, JSON]) -> None:
|
||||||
|
await self.user.on_channel_left(
|
||||||
|
Long.deserialize(data["channelId"]),
|
||||||
|
str(data["channelType"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _on_channel_kicked(self, data: dict[str, JSON]) -> None:
|
||||||
|
await self.user.on_channel_kicked(
|
||||||
|
Long.deserialize(data["userId"]),
|
||||||
|
Long.deserialize(data["senderId"]),
|
||||||
|
Long.deserialize(data["channelId"]),
|
||||||
|
str(data["channelType"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _on_user_join(self, data: dict[str, JSON]) -> None:
|
||||||
|
await self.user.on_user_join(
|
||||||
|
Long.deserialize(data["userId"]),
|
||||||
|
Long.deserialize(data["channelId"]),
|
||||||
|
str(data["channelType"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _on_user_left(self, data: dict[str, JSON]) -> None:
|
||||||
|
await self.user.on_user_left(
|
||||||
|
Long.deserialize(data["userId"]),
|
||||||
|
Long.deserialize(data["channelId"]),
|
||||||
|
str(data["channelType"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _on_listen_disconnect(self, data: dict[str, JSON]) -> None:
|
async def _on_listen_disconnect(self, data: dict[str, JSON]) -> None:
|
||||||
try:
|
try:
|
||||||
res = KickoutRes.deserialize(data)
|
res = KickoutRes.deserialize(data)
|
||||||
|
@ -452,6 +487,11 @@ class Client:
|
||||||
self._add_event_handler("chat_deleted", self._on_chat_deleted)
|
self._add_event_handler("chat_deleted", self._on_chat_deleted)
|
||||||
self._add_event_handler("chat_read", self._on_chat_read)
|
self._add_event_handler("chat_read", self._on_chat_read)
|
||||||
self._add_event_handler("profile_changed", self._on_profile_changed)
|
self._add_event_handler("profile_changed", self._on_profile_changed)
|
||||||
|
self._add_event_handler("channel_join", self._on_channel_join)
|
||||||
|
self._add_event_handler("channel_left", self._on_channel_left)
|
||||||
|
self._add_event_handler("channel_kicked", self._on_channel_kicked)
|
||||||
|
self._add_event_handler("user_join", self._on_user_join)
|
||||||
|
self._add_event_handler("user_left", self._on_user_left)
|
||||||
self._add_event_handler("disconnected", self._on_listen_disconnect)
|
self._add_event_handler("disconnected", self._on_listen_disconnect)
|
||||||
self._add_event_handler("switch_server", self._on_switch_server)
|
self._add_event_handler("switch_server", self._on_switch_server)
|
||||||
self._add_event_handler("error", self._on_error)
|
self._add_event_handler("error", self._on_error)
|
||||||
|
|
|
@ -1264,7 +1264,25 @@ class Portal(DBPortal, BasePortal):
|
||||||
await self.main_intent.redact(message.mx_room, message.mxid, timestamp=timestamp)
|
await self.main_intent.redact(message.mx_room, message.mxid, timestamp=timestamp)
|
||||||
await message.delete()
|
await message.delete()
|
||||||
|
|
||||||
# TODO Many more remote handlers
|
async def handle_kakaotalk_user_join(
|
||||||
|
self, source: u.User, user: p.Puppet
|
||||||
|
) -> None:
|
||||||
|
await self.main_intent.ensure_joined(self.mxid)
|
||||||
|
if not user.name:
|
||||||
|
self.schedule_resync(source, user)
|
||||||
|
|
||||||
|
async def handle_kakaotalk_user_left(
|
||||||
|
self, source: u.User, sender: p.Puppet, removed: p.Puppet
|
||||||
|
) -> None:
|
||||||
|
if sender == removed:
|
||||||
|
await removed.intent_for(self).leave_room(self.mxid)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
await sender.intent_for(self).kick_user(self.mxid, removed.mxid)
|
||||||
|
except MForbidden:
|
||||||
|
await self.main_intent.kick_user(
|
||||||
|
self.mxid, removed.mxid, reason=f"Kicked by {sender.name}"
|
||||||
|
)
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
|
@ -1301,7 +1319,6 @@ class Portal(DBPortal, BasePortal):
|
||||||
source,
|
source,
|
||||||
limit,
|
limit,
|
||||||
most_recent.ktid if most_recent else None,
|
most_recent.ktid if most_recent else None,
|
||||||
channel_info=channel_info,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _backfill(
|
async def _backfill(
|
||||||
|
@ -1309,7 +1326,6 @@ class Portal(DBPortal, BasePortal):
|
||||||
source: u.User,
|
source: u.User,
|
||||||
limit: int | None,
|
limit: int | None,
|
||||||
after_log_id: Long | None,
|
after_log_id: Long | None,
|
||||||
channel_info: ChannelInfo,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
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}")
|
||||||
|
|
|
@ -54,6 +54,11 @@ METRIC_CHAT = Summary("bridge_on_chat", "calls to on_chat")
|
||||||
METRIC_CHAT_DELETED = Summary("bridge_on_chat_deleted", "calls to on_chat_deleted")
|
METRIC_CHAT_DELETED = Summary("bridge_on_chat_deleted", "calls to on_chat_deleted")
|
||||||
METRIC_CHAT_READ = Summary("bridge_on_chat_read", "calls to on_chat_read")
|
METRIC_CHAT_READ = Summary("bridge_on_chat_read", "calls to on_chat_read")
|
||||||
METRIC_PROFILE_CHANGE = Summary("bridge_on_profile_changed", "calls to on_profile_changed")
|
METRIC_PROFILE_CHANGE = Summary("bridge_on_profile_changed", "calls to on_profile_changed")
|
||||||
|
METRIC_CHANNEL_JOIN = Summary("bridge_on_channel_join", "calls to on_channel_join")
|
||||||
|
METRIC_CHANNEL_LEFT = Summary("bridge_on_channel_left", "calls to on_channel_left")
|
||||||
|
METRIC_CHANNEL_KICKED = Summary("bridge_on_channel_kicked", "calls to on_channel_kicked")
|
||||||
|
METRIC_USER_JOIN = Summary("bridge_on_user_join", "calls to on_user_join")
|
||||||
|
METRIC_USER_LEFT = Summary("bridge_on_user_left", "calls to on_user_left")
|
||||||
METRIC_LOGGED_IN = Gauge("bridge_logged_in", "Users logged into the bridge")
|
METRIC_LOGGED_IN = Gauge("bridge_logged_in", "Users logged into the bridge")
|
||||||
METRIC_CONNECTED = Gauge("bridge_connected", "Bridge users connected to KakaoTalk")
|
METRIC_CONNECTED = Gauge("bridge_connected", "Bridge users connected to KakaoTalk")
|
||||||
|
|
||||||
|
@ -442,7 +447,7 @@ class User(DBUser, BaseUser):
|
||||||
key=get_channel_update_time
|
key=get_channel_update_time
|
||||||
)[:sync_count]:
|
)[:sync_count]:
|
||||||
try:
|
try:
|
||||||
await self._sync_channel(login_data)
|
await self._sync_channel_on_login(login_data)
|
||||||
except AuthenticationRequired:
|
except AuthenticationRequired:
|
||||||
raise
|
raise
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -450,7 +455,7 @@ class User(DBUser, BaseUser):
|
||||||
|
|
||||||
await self.update_direct_chats()
|
await self.update_direct_chats()
|
||||||
|
|
||||||
async def _sync_channel(self, login_data: LoginDataItem) -> None:
|
def _sync_channel_on_login(self, login_data: LoginDataItem) -> Awaitable[None]:
|
||||||
channel_data = login_data.channel
|
channel_data = login_data.channel
|
||||||
self.log.debug(f"Syncing channel {channel_data.channelId} (last updated at {login_data.lastUpdate})")
|
self.log.debug(f"Syncing channel {channel_data.channelId} (last updated at {login_data.lastUpdate})")
|
||||||
channel_info = channel_data.info
|
channel_info = channel_data.info
|
||||||
|
@ -485,6 +490,9 @@ class User(DBUser, BaseUser):
|
||||||
for display_user_info in channel_info.displayUserList:
|
for display_user_info in channel_info.displayUserList:
|
||||||
self.log.debug(f"Member: {display_user_info.nickname} - {display_user_info.profileURL} - {display_user_info.userId}")
|
self.log.debug(f"Member: {display_user_info.nickname} - {display_user_info.profileURL} - {display_user_info.userId}")
|
||||||
|
|
||||||
|
return self._sync_channel(channel_info)
|
||||||
|
|
||||||
|
async def _sync_channel(self, channel_info: ChannelInfo):
|
||||||
portal = await po.Portal.get_by_ktid(
|
portal = await po.Portal.get_by_ktid(
|
||||||
channel_info.channelId,
|
channel_info.channelId,
|
||||||
kt_receiver=self.ktid,
|
kt_receiver=self.ktid,
|
||||||
|
@ -729,6 +737,71 @@ class User(DBUser, BaseUser):
|
||||||
if puppet:
|
if puppet:
|
||||||
await puppet.update_info_from_participant(self, info)
|
await puppet.update_info_from_participant(self, info)
|
||||||
|
|
||||||
# TODO Many more handlers
|
@async_time(METRIC_CHANNEL_JOIN)
|
||||||
|
def on_channel_join(self, channel_info: ChannelInfo) -> Awaitable[None]:
|
||||||
|
return self._sync_channel(channel_info)
|
||||||
|
|
||||||
|
@async_time(METRIC_CHANNEL_LEFT)
|
||||||
|
async def on_channel_left(self, channel_id: Long, channel_type: ChannelType) -> None:
|
||||||
|
portal = await po.Portal.get_by_ktid(
|
||||||
|
channel_id,
|
||||||
|
kt_receiver=self.ktid,
|
||||||
|
kt_type=channel_type,
|
||||||
|
)
|
||||||
|
if portal.mxid:
|
||||||
|
await portal.main_intent.kick_user(portal.mxid, self.mxid, "Left this channel from KakaoTalk")
|
||||||
|
|
||||||
|
@async_time(METRIC_CHANNEL_KICKED)
|
||||||
|
async def on_channel_kicked(
|
||||||
|
self,
|
||||||
|
user_id: Long,
|
||||||
|
sender_id: Long,
|
||||||
|
channel_id: Long,
|
||||||
|
channel_type: ChannelType
|
||||||
|
) -> None:
|
||||||
|
portal = await po.Portal.get_by_ktid(
|
||||||
|
channel_id,
|
||||||
|
kt_receiver=self.ktid,
|
||||||
|
kt_type=channel_type,
|
||||||
|
)
|
||||||
|
if portal.mxid:
|
||||||
|
sender = await pu.Puppet.get_by_ktid(sender_id)
|
||||||
|
user = await pu.Puppet.get_by_ktid(user_id)
|
||||||
|
await portal.backfill_lock.wait("channel kicked")
|
||||||
|
await portal.handle_kakaotalk_user_left(self, sender, user)
|
||||||
|
|
||||||
|
@async_time(METRIC_USER_JOIN)
|
||||||
|
async def on_user_join(
|
||||||
|
self,
|
||||||
|
user_id: Long,
|
||||||
|
channel_id: Long,
|
||||||
|
channel_type: ChannelType
|
||||||
|
) -> None:
|
||||||
|
portal = await po.Portal.get_by_ktid(
|
||||||
|
channel_id,
|
||||||
|
kt_receiver=self.ktid,
|
||||||
|
kt_type=channel_type,
|
||||||
|
)
|
||||||
|
if portal.mxid:
|
||||||
|
user = await pu.Puppet.get_by_ktid(user_id)
|
||||||
|
await portal.backfill_lock.wait("user join")
|
||||||
|
await portal.handle_kakaotalk_user_join(self, user)
|
||||||
|
|
||||||
|
@async_time(METRIC_USER_LEFT)
|
||||||
|
async def on_user_left(
|
||||||
|
self,
|
||||||
|
user_id: Long,
|
||||||
|
channel_id: Long,
|
||||||
|
channel_type: ChannelType
|
||||||
|
) -> None:
|
||||||
|
portal = await po.Portal.get_by_ktid(
|
||||||
|
channel_id,
|
||||||
|
kt_receiver=self.ktid,
|
||||||
|
kt_type=channel_type,
|
||||||
|
)
|
||||||
|
if portal.mxid:
|
||||||
|
user = await pu.Puppet.get_by_ktid(user_id)
|
||||||
|
await portal.backfill_lock.wait("user left")
|
||||||
|
await portal.handle_kakaotalk_user_left(self, user, user)
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
|
@ -104,7 +104,7 @@ class UserClient {
|
||||||
})
|
})
|
||||||
|
|
||||||
this.#talkClient.on("message_hidden", (hideLog, channel, feed) => {
|
this.#talkClient.on("message_hidden", (hideLog, channel, feed) => {
|
||||||
this.log(`Message ${hideLog.logId} hid from channel ${channel.channelId} by user ${hideLog.sender.userId}`)
|
this.log(`Message ${feed.logId} hid from channel ${channel.channelId} by user ${hideLog.sender.userId}`)
|
||||||
return this.write("chat_deleted", {
|
return this.write("chat_deleted", {
|
||||||
chatId: feed.logId,
|
chatId: feed.logId,
|
||||||
senderId: hideLog.sender.userId,
|
senderId: hideLog.sender.userId,
|
||||||
|
@ -125,7 +125,7 @@ class UserClient {
|
||||||
})
|
})
|
||||||
|
|
||||||
this.#talkClient.on("profile_changed", (channel, lastInfo, user) => {
|
this.#talkClient.on("profile_changed", (channel, lastInfo, user) => {
|
||||||
this.log(`Profile of ${user.userId} changed (channel: ${channel})`)
|
this.log(`Profile of ${user.userId} changed (channel: ${channel ? channel.channelId : "None"})`)
|
||||||
return this.write("profile_changed", {
|
return this.write("profile_changed", {
|
||||||
info: user,
|
info: user,
|
||||||
/* TODO Is this ever a per-channel profile change?
|
/* TODO Is this ever a per-channel profile change?
|
||||||
|
@ -135,6 +135,49 @@ class UserClient {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.#talkClient.on("channel_join", channel => {
|
||||||
|
this.log(`Joined channel ${channel.channelId}`)
|
||||||
|
return this.write("channel_join", {
|
||||||
|
channelInfo: channel.info,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.#talkClient.on("channel_left", channel => {
|
||||||
|
this.log(`Left channel ${channel.channelId}`)
|
||||||
|
return this.write("channel_left", {
|
||||||
|
channelId: channel.channelId,
|
||||||
|
channelType: channel.info.type,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.#talkClient.on("channel_kicked", (kickedLog, channel, feed) => {
|
||||||
|
this.log(`User ${feed.member.userId} kicked from channel ${channel.channelId} by user ${kickedLog.sender.userId}`)
|
||||||
|
return this.write("channel_kicked", {
|
||||||
|
userId: feed.member.userId,
|
||||||
|
senderId: kickedLog.sender.userId,
|
||||||
|
channelId: channel.channelId,
|
||||||
|
channelType: channel.info.type,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.#talkClient.on("user_join", (joinLog, channel, user, feed) => {
|
||||||
|
this.log(`User ${user.userId} joined channel ${channel.channelId}`)
|
||||||
|
return this.write("user_join", {
|
||||||
|
userId: user.userId,
|
||||||
|
channelId: channel.channelId,
|
||||||
|
channelType: channel.info.type,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.#talkClient.on("user_left", (leftLog, channel, user, feed) => {
|
||||||
|
this.log(`User ${user.userId} left channel ${channel.channelId}`)
|
||||||
|
return this.write("user_left", {
|
||||||
|
userId: user.userId,
|
||||||
|
channelId: channel.channelId,
|
||||||
|
channelType: channel.info.type,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
this.#talkClient.on("disconnected", (reason) => {
|
this.#talkClient.on("disconnected", (reason) => {
|
||||||
this.log(`Disconnected (reason=${reason})`)
|
this.log(`Disconnected (reason=${reason})`)
|
||||||
this.disconnect()
|
this.disconnect()
|
||||||
|
|
Loading…
Reference in New Issue