Compare commits
No commits in common. "370865c2c1a6b9d5dc687b3cdff4af84a80fbfd0" and "861e3ff30d3a36b9b52e4ad783a4dc394dc50d8b" have entirely different histories.
370865c2c1
...
861e3ff30d
16
ROADMAP.md
16
ROADMAP.md
@ -16,7 +16,7 @@
|
|||||||
* [x] Mentions
|
* [x] Mentions
|
||||||
* [x] Message redactions<sup>[1]</sup>
|
* [x] Message redactions<sup>[1]</sup>
|
||||||
* [ ] Message reactions
|
* [ ] Message reactions
|
||||||
* [x] Read receipts
|
* [ ] Read receipts
|
||||||
* [ ] Power level
|
* [ ] Power level
|
||||||
* [ ] Membership actions
|
* [ ] Membership actions
|
||||||
* [ ] Invite
|
* [ ] Invite
|
||||||
@ -42,13 +42,11 @@
|
|||||||
* [ ] Message reactions
|
* [ ] Message reactions
|
||||||
* [x] Message history
|
* [x] Message history
|
||||||
* [ ] Read receipts
|
* [ ] Read receipts
|
||||||
* [ ] On backfill
|
|
||||||
* [x] On live event
|
|
||||||
* [ ] Admin status
|
* [ ] Admin status
|
||||||
* [x] Membership actions
|
* [ ] Membership actions
|
||||||
* [x] Add member
|
* [ ] Add member
|
||||||
* [x] Remove member
|
* [ ] Remove member
|
||||||
* [x] Leave
|
* [ ] Leave
|
||||||
* [ ] Chat metadata changes
|
* [ ] Chat metadata changes
|
||||||
* [x] Title
|
* [x] Title
|
||||||
* [ ] Avatar
|
* [ ] Avatar
|
||||||
@ -61,9 +59,9 @@
|
|||||||
* Misc
|
* Misc
|
||||||
* [x] Multi-user support
|
* [x] Multi-user support
|
||||||
* [x] Shared group chat portals
|
* [x] Shared group chat portals
|
||||||
* [x] Automatic portal creation
|
* [ ] Automatic portal creation
|
||||||
* [x] At startup
|
* [x] At startup
|
||||||
* [x] When added to chat
|
* [ ] When added to chat
|
||||||
* [x] When receiving message
|
* [x] When receiving message
|
||||||
* [ ] Private chat creation by inviting Matrix puppet of KakaoTalk user to new room
|
* [ ] Private chat creation by inviting Matrix puppet of KakaoTalk user to new room
|
||||||
* [x] For existing recently-updated KakaoTalk channels
|
* [x] For existing recently-updated KakaoTalk channels
|
||||||
|
@ -22,7 +22,7 @@ with any other potential backend.
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, cast, Awaitable, Type, Optional, Union
|
from typing import TYPE_CHECKING, cast, Type, Optional, Union
|
||||||
import asyncio
|
import asyncio
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
import logging
|
import logging
|
||||||
@ -37,15 +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 import FriendListStruct
|
|
||||||
from ..types.api.struct.profile import ProfileReqStruct, ProfileStruct
|
from ..types.api.struct.profile import ProfileReqStruct, ProfileStruct
|
||||||
|
from ..types.api.struct import FriendListStruct
|
||||||
from ..types.bson import Long
|
from ..types.bson import Long
|
||||||
from ..types.channel.channel_info import ChannelInfo
|
from ..types.client.client_session import LoginResult
|
||||||
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.packet.chat.kickout import KnownKickoutType, KickoutRes
|
from ..types.packet.chat.kickout import KnownKickoutType, KickoutRes
|
||||||
from ..types.request import (
|
from ..types.request import (
|
||||||
deserialize_result,
|
deserialize_result,
|
||||||
@ -356,17 +354,6 @@ class Client:
|
|||||||
chat_id=chat_id.serialize(),
|
chat_id=chat_id.serialize(),
|
||||||
)
|
)
|
||||||
|
|
||||||
async def mark_read(
|
|
||||||
self,
|
|
||||||
channel_props: ChannelProps,
|
|
||||||
read_until_chat_id: Long,
|
|
||||||
) -> None:
|
|
||||||
return await self._api_user_request_void(
|
|
||||||
"mark_read",
|
|
||||||
channel_props=channel_props.serialize(),
|
|
||||||
read_until_chat_id=read_until_chat_id.serialize(),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO Combine these into one
|
# TODO Combine these into one
|
||||||
|
|
||||||
@ -415,52 +402,10 @@ class Client:
|
|||||||
str(data["channelType"]),
|
str(data["channelType"]),
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _on_chat_read(self, data: dict[str, JSON]) -> None:
|
""" TODO
|
||||||
await self.user.on_chat_read(
|
async def _on_receipt(self, data: Dict[str, JSON]) -> None:
|
||||||
Long.deserialize(data["chatId"]),
|
await self.user.on_receipt(Receipt.deserialize(data["receipt"]))
|
||||||
Long.deserialize(data["senderId"]),
|
"""
|
||||||
Long.deserialize(data["channelId"]),
|
|
||||||
str(data["channelType"]),
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _on_profile_changed(self, data: dict[str, JSON]) -> None:
|
|
||||||
await self.user.on_profile_changed(
|
|
||||||
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:
|
||||||
@ -478,23 +423,13 @@ class Client:
|
|||||||
self._stop_listen()
|
self._stop_listen()
|
||||||
await self.user.on_disconnect(res)
|
await self.user.on_disconnect(res)
|
||||||
|
|
||||||
def _on_error(self, data: dict[str, JSON]) -> Awaitable[None]:
|
|
||||||
return self.user.on_error(data)
|
|
||||||
|
|
||||||
|
|
||||||
def _start_listen(self) -> None:
|
def _start_listen(self) -> None:
|
||||||
self._add_event_handler("chat", self._on_chat)
|
self._add_event_handler("chat", self._on_chat)
|
||||||
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)
|
# TODO many more listeners
|
||||||
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)
|
|
||||||
|
|
||||||
def _stop_listen(self) -> None:
|
def _stop_listen(self) -> None:
|
||||||
for method in self._handler_methods:
|
for method in self._handler_methods:
|
||||||
|
@ -45,7 +45,7 @@ class ChannelInfo(Channel):
|
|||||||
type: ChannelType
|
type: ChannelType
|
||||||
activeUserCount: int
|
activeUserCount: int
|
||||||
newChatCount: int
|
newChatCount: int
|
||||||
newChatCountInvalid: Optional[bool] = None # NOTE Made optional
|
newChatCountInvalid: bool
|
||||||
lastChatLogId: Long
|
lastChatLogId: Long
|
||||||
lastSeenLogId: Long
|
lastSeenLogId: Long
|
||||||
lastChatLog: Optional[Chatlog] = None
|
lastChatLog: Optional[Chatlog] = None
|
||||||
|
@ -24,7 +24,6 @@ from mautrix.types import (
|
|||||||
EventType,
|
EventType,
|
||||||
ReactionEvent,
|
ReactionEvent,
|
||||||
ReactionEventContent,
|
ReactionEventContent,
|
||||||
ReceiptEvent,
|
|
||||||
RedactionEvent,
|
RedactionEvent,
|
||||||
RelationType,
|
RelationType,
|
||||||
RoomID,
|
RoomID,
|
||||||
@ -33,7 +32,6 @@ from mautrix.types import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from . import portal as po, user as u
|
from . import portal as po, user as u
|
||||||
from .db import Message as DBMessage
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .__main__ import KakaoTalkBridge
|
from .__main__ import KakaoTalkBridge
|
||||||
@ -49,12 +47,7 @@ class MatrixHandler(BaseMatrixHandler):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def allow_bridging_message(user: u.User, portal: po.Portal) -> bool:
|
async def allow_bridging_message(user: u.User, portal: po.Portal) -> bool:
|
||||||
if user.is_connected:
|
return user.is_connected or (user.relay_whitelisted and portal.has_relay)
|
||||||
return True
|
|
||||||
if user.relay_whitelisted and portal.has_relay:
|
|
||||||
relay_user = await portal.get_relay_user()
|
|
||||||
return relay_user and relay_user.is_connected
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def send_welcome_message(self, room_id: RoomID, inviter: u.User) -> None:
|
async def send_welcome_message(self, room_id: RoomID, inviter: u.User) -> None:
|
||||||
await super().send_welcome_message(room_id, inviter)
|
await super().send_welcome_message(room_id, inviter)
|
||||||
@ -155,16 +148,19 @@ class MatrixHandler(BaseMatrixHandler):
|
|||||||
event_id: EventID,
|
event_id: EventID,
|
||||||
data: SingleReceiptEventContent,
|
data: SingleReceiptEventContent,
|
||||||
) -> None:
|
) -> None:
|
||||||
if not user.is_connected:
|
self.log.info("TODO: handle_read_receipt")
|
||||||
|
"""
|
||||||
|
if not user.mqtt:
|
||||||
return
|
return
|
||||||
|
timestamp = data.get("ts", int(time.time() * 1000))
|
||||||
message = await DBMessage.get_by_mxid(event_id, portal.mxid)
|
message = await DBMessage.get_by_mxid(event_id, portal.mxid)
|
||||||
await user.client.mark_read(portal.channel_props, message.ktid)
|
await user.mqtt.mark_read(
|
||||||
|
portal.ktid,
|
||||||
async def handle_ephemeral_event(
|
True, # TODO
|
||||||
self, evt: ReceiptEvent | Event
|
#portal.fb_type != ThreadType.USER,
|
||||||
) -> None:
|
read_to=message.timestamp if message else timestamp,
|
||||||
if evt.type == EventType.RECEIPT:
|
)
|
||||||
await self.handle_receipt(evt)
|
"""
|
||||||
|
|
||||||
async def handle_event(self, evt: Event) -> None:
|
async def handle_event(self, evt: Event) -> None:
|
||||||
if evt.type == EventType.ROOM_REDACTION:
|
if evt.type == EventType.ROOM_REDACTION:
|
||||||
|
@ -190,7 +190,6 @@ class Portal(DBPortal, BasePortal):
|
|||||||
|
|
||||||
# TODO More
|
# TODO More
|
||||||
cls._chat_type_handler_map = {
|
cls._chat_type_handler_map = {
|
||||||
KnownChatType.FEED: cls._handle_kakaotalk_feed,
|
|
||||||
KnownChatType.TEXT: cls._handle_kakaotalk_text,
|
KnownChatType.TEXT: cls._handle_kakaotalk_text,
|
||||||
KnownChatType.REPLY: cls._handle_kakaotalk_reply,
|
KnownChatType.REPLY: cls._handle_kakaotalk_reply,
|
||||||
KnownChatType.PHOTO: cls._handle_kakaotalk_photo,
|
KnownChatType.PHOTO: cls._handle_kakaotalk_photo,
|
||||||
@ -528,7 +527,8 @@ class Portal(DBPortal, BasePortal):
|
|||||||
if did_join and self.is_direct:
|
if did_join and self.is_direct:
|
||||||
await source.update_direct_chats({self.main_intent.mxid: [self.mxid]})
|
await source.update_direct_chats({self.main_intent.mxid: [self.mxid]})
|
||||||
|
|
||||||
# TODO Sync read receipts?
|
# TODO
|
||||||
|
#await self._sync_read_receipts(info.read_receipts.nodes)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
async def _sync_read_receipts(self, receipts: list[None]) -> None:
|
async def _sync_read_receipts(self, receipts: list[None]) -> None:
|
||||||
@ -702,7 +702,8 @@ class Portal(DBPortal, BasePortal):
|
|||||||
except Exception:
|
except Exception:
|
||||||
self.log.exception("Failed to backfill new portal")
|
self.log.exception("Failed to backfill new portal")
|
||||||
|
|
||||||
# TODO Sync read receipts?
|
# TODO
|
||||||
|
#await self._sync_read_receipts(info.read_receipts.nodes)
|
||||||
|
|
||||||
return self.mxid
|
return self.mxid
|
||||||
|
|
||||||
@ -774,8 +775,8 @@ class Portal(DBPortal, BasePortal):
|
|||||||
sender, is_relay = await self.get_relay_sender(orig_sender, f"message {event_id}")
|
sender, is_relay = await self.get_relay_sender(orig_sender, f"message {event_id}")
|
||||||
if not sender:
|
if not sender:
|
||||||
raise Exception("not logged in")
|
raise Exception("not logged in")
|
||||||
elif not sender.is_connected:
|
elif not sender.has_state:
|
||||||
raise Exception("not connected to KakaoTalk chats")
|
raise Exception("not connected to KakaoTalk")
|
||||||
elif is_relay:
|
elif is_relay:
|
||||||
await self.apply_relay_message_format(orig_sender, message)
|
await self.apply_relay_message_format(orig_sender, message)
|
||||||
if message.msgtype == MessageType.TEXT or message.msgtype == MessageType.NOTICE:
|
if message.msgtype == MessageType.TEXT or message.msgtype == MessageType.NOTICE:
|
||||||
@ -1089,7 +1090,6 @@ class Portal(DBPortal, BasePortal):
|
|||||||
if chat_text:
|
if chat_text:
|
||||||
events = await self._handle_kakaotalk_text(
|
events = await self._handle_kakaotalk_text(
|
||||||
intent=intent,
|
intent=intent,
|
||||||
attachment=None,
|
|
||||||
timestamp=timestamp,
|
timestamp=timestamp,
|
||||||
chat_text=chat_text,
|
chat_text=chat_text,
|
||||||
)
|
)
|
||||||
@ -1104,15 +1104,6 @@ class Portal(DBPortal, BasePortal):
|
|||||||
events.append(await self._send_message(intent, content, timestamp=timestamp))
|
events.append(await self._send_message(intent, content, timestamp=timestamp))
|
||||||
return events
|
return events
|
||||||
|
|
||||||
async def _handle_kakaotalk_feed(
|
|
||||||
self,
|
|
||||||
timestamp: int,
|
|
||||||
chat_text: str | None,
|
|
||||||
**_
|
|
||||||
) -> list[EventID]:
|
|
||||||
self.log.info("Got feed message at %s: %s", timestamp, chat_text or "none")
|
|
||||||
return []
|
|
||||||
|
|
||||||
async def _handle_kakaotalk_text(
|
async def _handle_kakaotalk_text(
|
||||||
self,
|
self,
|
||||||
intent: IntentAPI,
|
intent: IntentAPI,
|
||||||
@ -1275,25 +1266,7 @@ 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()
|
||||||
|
|
||||||
async def handle_kakaotalk_user_join(
|
# TODO Many more remote handlers
|
||||||
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
|
||||||
|
|
||||||
@ -1330,6 +1303,7 @@ 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(
|
||||||
@ -1337,6 +1311,7 @@ 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}")
|
||||||
|
@ -22,7 +22,6 @@ import time
|
|||||||
from mautrix.bridge import BaseUser, async_getter_lock
|
from mautrix.bridge import BaseUser, async_getter_lock
|
||||||
from mautrix.types import (
|
from mautrix.types import (
|
||||||
EventID,
|
EventID,
|
||||||
JSON,
|
|
||||||
MessageType,
|
MessageType,
|
||||||
RoomID,
|
RoomID,
|
||||||
TextMessageEventContent,
|
TextMessageEventContent,
|
||||||
@ -46,19 +45,11 @@ from .kt.types.chat.chat import Chatlog
|
|||||||
from .kt.types.client.client_session import LoginDataItem, LoginResult
|
from .kt.types.client.client_session import LoginDataItem, LoginResult
|
||||||
from .kt.types.oauth import OAuthCredential
|
from .kt.types.oauth import OAuthCredential
|
||||||
from .kt.types.openlink.open_channel_info import OpenChannelData, OpenChannelInfo
|
from .kt.types.openlink.open_channel_info import OpenChannelData, OpenChannelInfo
|
||||||
from .kt.types.openlink.open_link_user_info import OpenLinkChannelUserInfo
|
|
||||||
from .kt.types.packet.chat.kickout import KnownKickoutType, KickoutRes
|
from .kt.types.packet.chat.kickout import KnownKickoutType, KickoutRes
|
||||||
|
|
||||||
METRIC_CONNECT_AND_SYNC = Summary("bridge_connect_and_sync", "calls to connect_and_sync")
|
METRIC_CONNECT_AND_SYNC = Summary("bridge_connect_and_sync", "calls to connect_and_sync")
|
||||||
METRIC_CHAT = Summary("bridge_on_chat", "calls to on_chat")
|
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_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")
|
||||||
|
|
||||||
@ -447,7 +438,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_on_login(login_data)
|
await self._sync_channel(login_data)
|
||||||
except AuthenticationRequired:
|
except AuthenticationRequired:
|
||||||
raise
|
raise
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -455,7 +446,7 @@ class User(DBUser, BaseUser):
|
|||||||
|
|
||||||
await self.update_direct_chats()
|
await self.update_direct_chats()
|
||||||
|
|
||||||
def _sync_channel_on_login(self, login_data: LoginDataItem) -> Awaitable[None]:
|
async def _sync_channel(self, login_data: LoginDataItem) -> 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
|
||||||
@ -490,9 +481,6 @@ 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,
|
||||||
@ -645,14 +633,6 @@ class User(DBUser, BaseUser):
|
|||||||
await self.logout()
|
await self.logout()
|
||||||
await self.send_bridge_notice(f"Disconnected from KakaoTalk: {reason_str} {reason_suffix}")
|
await self.send_bridge_notice(f"Disconnected from KakaoTalk: {reason_str} {reason_suffix}")
|
||||||
|
|
||||||
def on_error(self, error: JSON) -> Awaitable[None]:
|
|
||||||
return self.send_bridge_notice(
|
|
||||||
f"Got error event from KakaoTalk:\n\n> {error}",
|
|
||||||
# TODO Which error code to use?
|
|
||||||
#error_code="kt-connection-error",
|
|
||||||
error_message=str(error),
|
|
||||||
)
|
|
||||||
|
|
||||||
async def on_client_disconnect(self) -> None:
|
async def on_client_disconnect(self) -> None:
|
||||||
self.is_connected = False
|
self.is_connected = False
|
||||||
self._track_metric(METRIC_CONNECTED, False)
|
self._track_metric(METRIC_CONNECTED, False)
|
||||||
@ -684,7 +664,7 @@ class User(DBUser, BaseUser):
|
|||||||
portal = await po.Portal.get_by_ktid(
|
portal = await po.Portal.get_by_ktid(
|
||||||
channel_id,
|
channel_id,
|
||||||
kt_receiver=self.ktid,
|
kt_receiver=self.ktid,
|
||||||
kt_type=channel_type,
|
kt_type=channel_type
|
||||||
)
|
)
|
||||||
puppet = await pu.Puppet.get_by_ktid(chat.sender.userId)
|
puppet = await pu.Puppet.get_by_ktid(chat.sender.userId)
|
||||||
await portal.backfill_lock.wait(chat.logId)
|
await portal.backfill_lock.wait(chat.logId)
|
||||||
@ -705,103 +685,13 @@ class User(DBUser, BaseUser):
|
|||||||
channel_id,
|
channel_id,
|
||||||
kt_receiver=self.ktid,
|
kt_receiver=self.ktid,
|
||||||
kt_type=channel_type,
|
kt_type=channel_type,
|
||||||
create=False,
|
create=False
|
||||||
)
|
)
|
||||||
if portal and portal.mxid:
|
if portal and portal.mxid:
|
||||||
await portal.backfill_lock.wait(f"redaction of {chat_id}")
|
await portal.backfill_lock.wait(f"redaction of {chat_id}")
|
||||||
puppet = await pu.Puppet.get_by_ktid(sender_id)
|
puppet = await pu.Puppet.get_by_ktid(sender_id)
|
||||||
await portal.handle_kakaotalk_chat_delete(puppet, chat_id, timestamp)
|
await portal.handle_kakaotalk_chat_delete(puppet, chat_id, timestamp)
|
||||||
|
|
||||||
@async_time(METRIC_CHAT_READ)
|
# TODO Many more handlers
|
||||||
async def on_chat_read(
|
|
||||||
self,
|
|
||||||
chat_id: Long,
|
|
||||||
sender_id: Long,
|
|
||||||
channel_id: Long,
|
|
||||||
channel_type: ChannelType,
|
|
||||||
) -> None:
|
|
||||||
puppet = await pu.Puppet.get_by_ktid(sender_id)
|
|
||||||
portal = await po.Portal.get_by_ktid(
|
|
||||||
channel_id,
|
|
||||||
kt_receiver=self.ktid,
|
|
||||||
kt_type=channel_type,
|
|
||||||
create=False,
|
|
||||||
)
|
|
||||||
if portal and portal.mxid:
|
|
||||||
await portal.backfill_lock.wait(f"read receipt from {sender_id}")
|
|
||||||
await portal.handle_kakaotalk_read(self, puppet, chat_id)
|
|
||||||
|
|
||||||
@async_time(METRIC_PROFILE_CHANGE)
|
|
||||||
async def on_profile_changed(self, info: OpenLinkChannelUserInfo) -> None:
|
|
||||||
puppet = await pu.Puppet.get_by_ktid(info.userId)
|
|
||||||
if puppet:
|
|
||||||
await puppet.update_info_from_participant(self, info)
|
|
||||||
|
|
||||||
@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
|
||||||
|
@ -48,13 +48,13 @@ ServiceApiClient.prototype.requestFriendList = async function() {
|
|||||||
{
|
{
|
||||||
phone_number_type: 1,
|
phone_number_type: 1,
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: res.status,
|
status: res.status,
|
||||||
success: res.status === 0,
|
success: res.status === 0,
|
||||||
result: res,
|
result: res,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ class UserClient {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.#talkClient.on("chat_deleted", (feedChatlog, channel, feed) => {
|
this.#talkClient.on("chat_deleted", (feedChatlog, channel, feed) => {
|
||||||
this.log(`${feed.logId} deleted in channel ${channel.channelId} by user ${feedChatlog.sender.userId}`)
|
this.log(`${feed.logId} deleted in channel ${channel.channelId} by user ${feedChatlog.sender.userId}`);
|
||||||
return this.write("chat_deleted", {
|
return this.write("chat_deleted", {
|
||||||
chatId: feed.logId,
|
chatId: feed.logId,
|
||||||
senderId: feedChatlog.sender.userId,
|
senderId: feedChatlog.sender.userId,
|
||||||
@ -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 ${feed.logId} hid from channel ${channel.channelId} by user ${hideLog.sender.userId}`)
|
this.log(`Message ${hideLog.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,
|
||||||
@ -114,69 +114,12 @@ class UserClient {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/* TODO Many more listeners
|
||||||
this.#talkClient.on("chat_read", (chat, channel, reader) => {
|
this.#talkClient.on("chat_read", (chat, channel, reader) => {
|
||||||
this.log(`${chat.logId} read in channel ${channel.channelId} by ${reader.userId}`)
|
this.log(`chat_read in channel ${channel.channelId}`)
|
||||||
return this.write("chat_read", {
|
//chat.logId
|
||||||
chatId: chat.logId,
|
|
||||||
senderId: reader.userId,
|
|
||||||
channelId: channel.channelId,
|
|
||||||
channelType: channel.info.type,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
this.#talkClient.on("profile_changed", (channel, lastInfo, user) => {
|
|
||||||
this.log(`Profile of ${user.userId} changed (channel: ${channel ? channel.channelId : "None"})`)
|
|
||||||
return this.write("profile_changed", {
|
|
||||||
info: user,
|
|
||||||
/* TODO Is this ever a per-channel profile change?
|
|
||||||
channelId: channel.channelId,
|
|
||||||
channelType: channel.info.type,
|
|
||||||
*/
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
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})`)
|
||||||
@ -192,13 +135,6 @@ class UserClient {
|
|||||||
is_sequential: true,
|
is_sequential: true,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
this.#talkClient.on("error", (err) => {
|
|
||||||
this.log(`Client error: ${err}`)
|
|
||||||
return this.write("error", {
|
|
||||||
error: err,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -648,20 +584,6 @@ export default class PeerClient {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Object} req
|
|
||||||
* @param {string} req.mxid
|
|
||||||
* @param {ChannelProps} req.channel_props
|
|
||||||
* @param {Long} req.read_until_chat_id
|
|
||||||
*/
|
|
||||||
markRead = async (req) => {
|
|
||||||
const talkChannel = await this.#getUserChannel(req.mxid, req.channel_props)
|
|
||||||
|
|
||||||
return await talkChannel.markRead({
|
|
||||||
logId: req.read_until_chat_id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#makeCommandResult(result) {
|
#makeCommandResult(result) {
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user