diff --git a/chatbridge/common/serializer.py b/chatbridge/common/serializer.py index 8a86e6c..33f83ef 100644 --- a/chatbridge/common/serializer.py +++ b/chatbridge/common/serializer.py @@ -1,10 +1,15 @@ +from typing import TypeVar, Type + from mcdreforged.api.utils.serializer import Serializable +Self = TypeVar('Self', bound='NoMissingFieldSerializable') + class NoMissingFieldSerializable(Serializable): @classmethod - def deserialize(cls, data: dict, **kwargs): + def deserialize(cls: Type[Self], data: dict, **kwargs) -> Self: kwargs.setdefault('error_at_missing', True) + # noinspection PyTypeChecker return super().deserialize(data, **kwargs) @classmethod diff --git a/chatbridge/core/client.py b/chatbridge/core/client.py index f585606..527df68 100644 --- a/chatbridge/core/client.py +++ b/chatbridge/core/client.py @@ -15,7 +15,7 @@ from chatbridge.core.network import net_util from chatbridge.core.network.basic import ChatBridgeBase, Address from chatbridge.core.network.protocol import ChatBridgePacket, PacketType, AbstractPacket, ChatPayload, \ - KeepAlivePayload, AbstractPayload, CommandPayload + KeepAlivePayload, AbstractPayload, CommandPayload, CustomPayload from chatbridge.core.network.protocol import LoginPacket, LoginResultPacket @@ -234,9 +234,9 @@ def _on_stopped(self): self.__thread_keep_alive.join() self.logger.debug('Joined keep alive thread') - # ---------------- - # Packet Logic - # ---------------- + # --------------------- + # Packet core logic + # --------------------- def _send_packet(self, packet: AbstractPacket): if self._is_connected(): @@ -279,13 +279,22 @@ def send_to(self, type_: str, clients: Union[str, Iterable[str]], payload: Abstr def send_to_all(self, type_: str, payload: AbstractPayload): self.__build_and_send_packet(type_, [], payload, is_broadcast=True) + # ------------------------- + # Packet handlers + # ------------------------- + def _on_packet(self, packet: ChatBridgePacket): + """ + A dispatcher that dispatch the packet based on packet type + """ if packet.type == PacketType.keep_alive: self._on_keep_alive(packet.sender, KeepAlivePayload.deserialize(packet.payload)) - if packet.type == PacketType.chat: + elif packet.type == PacketType.chat: self.on_chat(packet.sender, ChatPayload.deserialize(packet.payload)) - if packet.type == PacketType.command: + elif packet.type == PacketType.command: self.on_command(packet.sender, CommandPayload.deserialize(packet.payload)) + elif packet.type == PacketType.custom: + self.on_custom(packet.sender, CustomPayload.deserialize(packet.payload)) def _on_keep_alive(self, sender: str, payload: KeepAlivePayload): if payload.is_ping(): @@ -301,10 +310,20 @@ def on_chat(self, sender: str, payload: ChatPayload): def on_command(self, sender: str, payload: CommandPayload): pass + def on_custom(self, sender: str, payload: CustomPayload): + pass + + # ------------------------- + # Send packet shortcuts + # ------------------------- + def _send_keep_alive_ping(self): self.send_to(PacketType.keep_alive, self._keep_alive_target(), KeepAlivePayload.ping()) - def send_chat(self, message: str, author: str = ''): + def send_chat(self, target: str, message: str, author: str = ''): + self.send_to(PacketType.chat, target, ChatPayload(author=author, message=message)) + + def broadcast_chat(self, message: str, author: str = ''): self.send_to_all(PacketType.chat, ChatPayload(author=author, message=message)) def send_command(self, target: str, command: str, params: Optional[Union[Serializable, dict]] = None): @@ -313,9 +332,15 @@ def send_command(self, target: str, command: str, params: Optional[Union[Seriali def reply_command(self, target: str, asker_payload: 'CommandPayload', result: Union[Serializable, dict]): self.send_to(PacketType.command, target, CommandPayload.answer(asker_payload, result)) - # -------------- - # Keep Alive - # -------------- + def send_custom(self, target: str, data: dict): + self.send_to(PacketType.chat, target, CustomPayload(data=data)) + + def broadcast_custom(self, data: dict): + self.send_to_all(PacketType.chat, CustomPayload(data=data)) + + # ------------------- + # Keep Alive Impl + # ------------------- def _get_keep_alive_thread_name(self): return 'KeepAlive' diff --git a/chatbridge/core/network/protocol.py b/chatbridge/core/network/protocol.py index 7c0d2e4..cbf5f99 100644 --- a/chatbridge/core/network/protocol.py +++ b/chatbridge/core/network/protocol.py @@ -29,6 +29,7 @@ class PacketType: keep_alive = 'chatbridge.keep_alive' chat = 'chatbridge.chat' command = 'chatbridge.command' + custom = 'chatbridge.custom' class ChatBridgePacket(AbstractPacket): @@ -111,3 +112,7 @@ def answer(cls, asker_payload: 'CommandPayload', result: Union[Serializable, dic params=asker_payload.params, result=result, ) + + +class CustomPayload(AbstractPayload): + data: dict diff --git a/chatbridge/impl/cli/cli_client.py b/chatbridge/impl/cli/cli_client.py index b61687c..618adea 100644 --- a/chatbridge/impl/cli/cli_client.py +++ b/chatbridge/impl/cli/cli_client.py @@ -33,7 +33,7 @@ def console_loop(self): self.logger.info('restart: restart the client') self.logger.info('ping: display ping') else: - self.send_chat(text) + self.broadcast_chat(text) def main(): diff --git a/chatbridge/impl/cqhttp/entry.py b/chatbridge/impl/cqhttp/entry.py index a6cb5e0..903a0a8 100644 --- a/chatbridge/impl/cqhttp/entry.py +++ b/chatbridge/impl/cqhttp/entry.py @@ -70,7 +70,7 @@ def on_message(self, _, message: str): if len(sender) == 0: sender = data['sender']['nickname'] text = html.unescape(data['raw_message'].split(' ', 1)[1]) - chatClient.send_chat(text, sender) + chatClient.broadcast_chat(text, sender) if len(args) == 1 and args[0] == '!!online': self.logger.info('!!online command triggered') diff --git a/chatbridge/impl/discord/bot.py b/chatbridge/impl/discord/bot.py index 4071e99..e99fdf1 100644 --- a/chatbridge/impl/discord/bot.py +++ b/chatbridge/impl/discord/bot.py @@ -104,7 +104,7 @@ async def on_message(self, message: Message): # Chat if message.channel.id == self.config.channel_for_chat: self.logger.info('Chat: {}'.format(msg_debug)) - stored.client.send_chat(message.content, author=message.author.name) + stored.client.broadcast_chat(message.content, author=message.author.name) def add_message(self, data, channel_id, t): self.messages.put(MessageData(data=data, channel=channel_id, type=t)) diff --git a/chatbridge/impl/kaiheila/entry.py b/chatbridge/impl/kaiheila/entry.py index fd72703..cec13e4 100644 --- a/chatbridge/impl/kaiheila/entry.py +++ b/chatbridge/impl/kaiheila/entry.py @@ -117,7 +117,7 @@ async def on_message(self, message: Msg): if channel_id == self.config.channel_for_chat: global chatClient if not message.content.startswith(self.config.command_prefix): - chatClient.send_chat(message.content, author=author) + chatClient.broadcast_chat(message.content, author=author) def add_message(self, data, channel_id, t): self.messages.put(MessageData(data=data, channel=channel_id, type=t)) @@ -222,7 +222,7 @@ def on_command(self, sender: str, payload: CommandPayload): message = '错误代码:{}'.format(result.error_code) khlBot.add_message(message, channel_id, MessageDataType.TEXT) elif payload.command == '!!online': - result = OnlineQueryResult.deserialize(payload.result) + result: OnlineQueryResult = OnlineQueryResult.deserialize(payload.result) khlBot.add_embed('{} online players'.format(config.server_display_name), '\n'.join(result.data), channel_id) diff --git a/chatbridge/impl/mcdr/mcdr_entry.py b/chatbridge/impl/mcdr/mcdr_entry.py index 58b0831..b22eeda 100644 --- a/chatbridge/impl/mcdr/mcdr_entry.py +++ b/chatbridge/impl/mcdr/mcdr_entry.py @@ -58,7 +58,7 @@ def send_chat(message: str, *, author: str = ''): if not client.is_running(): client.start() if client.is_online(): - client.send_chat(message, author) + client.broadcast_chat(message, author) def on_load(server: PluginServerInterface, old_module):