2022-05-02 10:34:48 +00:00
|
|
|
|
import asyncio
|
2021-06-03 15:36:22 +00:00
|
|
|
|
import copy
|
2021-02-15 15:32:47 +00:00
|
|
|
|
import logging
|
|
|
|
|
import tempfile
|
|
|
|
|
import threading
|
|
|
|
|
import time
|
|
|
|
|
import uuid
|
2022-02-05 12:58:20 +00:00
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
|
from typing import Any, BinaryIO, Dict, List, Optional, Tuple, Union
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
import aiocqhttp
|
|
|
|
|
from aiocqhttp import CQHttp, Event
|
2021-02-15 15:32:47 +00:00
|
|
|
|
from efb_qq_slave import BaseClient, QQMessengerChannel
|
2022-02-05 12:58:20 +00:00
|
|
|
|
from ehforwarderbot import Chat, Message, MsgType, Status, coordinator
|
|
|
|
|
from ehforwarderbot.chat import (
|
|
|
|
|
ChatMember,
|
2022-03-09 14:06:40 +00:00
|
|
|
|
GroupChat,
|
2022-02-05 12:58:20 +00:00
|
|
|
|
PrivateChat,
|
|
|
|
|
SelfChatMember,
|
|
|
|
|
SystemChatMember,
|
|
|
|
|
)
|
|
|
|
|
from ehforwarderbot.exceptions import (
|
|
|
|
|
EFBChatNotFound,
|
|
|
|
|
EFBMessageError,
|
|
|
|
|
EFBOperationNotSupported,
|
|
|
|
|
)
|
|
|
|
|
from ehforwarderbot.message import MessageCommand, MessageCommands
|
2021-02-15 15:32:47 +00:00
|
|
|
|
from ehforwarderbot.status import MessageRemoval
|
2022-03-09 11:52:21 +00:00
|
|
|
|
from ehforwarderbot.types import ChatID, MessageID
|
2021-02-15 15:32:47 +00:00
|
|
|
|
from ehforwarderbot.utils import extra
|
2022-05-02 10:34:48 +00:00
|
|
|
|
from hypercorn.asyncio import serve
|
|
|
|
|
from hypercorn.config import Config as HyperConfig
|
2022-02-05 12:58:20 +00:00
|
|
|
|
from PIL import Image
|
2022-05-02 10:34:48 +00:00
|
|
|
|
from quart.logging import create_serving_logger
|
2021-02-15 15:32:47 +00:00
|
|
|
|
from requests import RequestException
|
|
|
|
|
|
|
|
|
|
from .ChatMgr import ChatManager
|
2022-02-05 12:58:20 +00:00
|
|
|
|
from .Exceptions import (
|
|
|
|
|
CoolQAPIFailureException,
|
|
|
|
|
CoolQDisconnectedException,
|
|
|
|
|
CoolQOfflineException,
|
|
|
|
|
)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
from .MsgDecorator import QQMsgProcessor
|
2022-02-05 12:58:20 +00:00
|
|
|
|
from .Utils import (
|
|
|
|
|
async_send_messages_to_master,
|
|
|
|
|
coolq_text_encode,
|
|
|
|
|
download_file,
|
|
|
|
|
download_group_avatar,
|
|
|
|
|
download_user_avatar,
|
|
|
|
|
process_quote_text,
|
|
|
|
|
qq_emoji_list,
|
2022-03-12 11:49:03 +00:00
|
|
|
|
strf_time,
|
2022-02-05 12:58:20 +00:00
|
|
|
|
)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
|
|
|
|
|
2021-05-30 17:40:01 +00:00
|
|
|
|
class GoCQHttp(BaseClient):
|
2021-06-04 13:20:24 +00:00
|
|
|
|
client_name: str = "GoCQHttp Client"
|
|
|
|
|
client_id: str = "GoCQHttp"
|
2021-02-15 15:32:47 +00:00
|
|
|
|
client_config: Dict[str, Any]
|
|
|
|
|
|
|
|
|
|
coolq_bot: CQHttp = None
|
|
|
|
|
logger: logging.Logger = logging.getLogger(__name__)
|
|
|
|
|
channel: QQMessengerChannel
|
|
|
|
|
|
2022-03-09 14:06:40 +00:00
|
|
|
|
friend_list: List[Dict] = []
|
2021-06-03 14:18:49 +00:00
|
|
|
|
friend_dict: Dict[int, dict] = {}
|
2021-06-03 15:36:22 +00:00
|
|
|
|
stranger_dict: Dict[int, dict] = {}
|
2022-03-09 14:06:40 +00:00
|
|
|
|
group_list: List[Dict] = []
|
2021-06-03 14:18:49 +00:00
|
|
|
|
group_dict: Dict[int, dict] = {}
|
|
|
|
|
group_member_dict: Dict[int, Dict[str, Any]] = {}
|
|
|
|
|
group_member_info_dict: Dict[Tuple[int, int], dict] = {}
|
2022-03-09 14:06:40 +00:00
|
|
|
|
discuss_list: List[Dict] = []
|
|
|
|
|
extra_group_list: List[Dict] = []
|
2021-02-15 15:32:47 +00:00
|
|
|
|
repeat_counter = 0
|
|
|
|
|
update_repeat_counter = 0
|
|
|
|
|
|
|
|
|
|
def __init__(self, client_id: str, config: Dict[str, Any], channel):
|
|
|
|
|
super().__init__(client_id, config)
|
|
|
|
|
self.client_config = config[self.client_id]
|
2022-02-05 12:58:20 +00:00
|
|
|
|
self.coolq_bot = CQHttp(
|
|
|
|
|
api_root=self.client_config["api_root"],
|
|
|
|
|
access_token=self.client_config["access_token"],
|
|
|
|
|
)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.channel = channel
|
|
|
|
|
self.chat_manager = ChatManager(channel)
|
|
|
|
|
|
|
|
|
|
self.is_connected = False
|
|
|
|
|
self.is_logged_in = False
|
|
|
|
|
self.msg_decorator = QQMsgProcessor(instance=self)
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
self.loop = asyncio.get_event_loop()
|
|
|
|
|
self.shutdown_event = asyncio.Event()
|
|
|
|
|
|
|
|
|
|
asyncio.set_event_loop(self.loop)
|
|
|
|
|
|
|
|
|
|
async def forward_msgs_wrapper(msg_elements: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
2022-03-09 14:06:40 +00:00
|
|
|
|
fmt_msgs: List[Dict] = []
|
2022-03-06 12:22:40 +00:00
|
|
|
|
for msg in msg_elements:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
from_user = await self.get_user_info(msg["sender"]["user_id"])
|
2022-03-06 12:22:40 +00:00
|
|
|
|
header_text = {"data": {"text": f'{from_user["remark"]}({from_user["nickname"]}):\n'}, "type": "text"}
|
|
|
|
|
footer_text = {"data": {"text": "\n- - - - - - - - - - - - - - -\n"}, "type": "text"}
|
|
|
|
|
msg["content"].insert(0, header_text)
|
|
|
|
|
msg["content"].append(footer_text)
|
|
|
|
|
for i, inner_msg in enumerate(msg["content"]):
|
|
|
|
|
if "content" in inner_msg:
|
|
|
|
|
if i == 1:
|
|
|
|
|
fmt_msgs.pop()
|
|
|
|
|
msg["content"].pop()
|
2022-05-02 10:34:48 +00:00
|
|
|
|
fmt_msgs += await forward_msgs_wrapper([inner_msg])
|
2022-03-06 12:22:40 +00:00
|
|
|
|
else:
|
|
|
|
|
fmt_msgs.append(inner_msg)
|
|
|
|
|
return fmt_msgs
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def message_element_wrapper(
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context: Dict[str, Any], msg_element: Dict[str, Any], chat: Chat
|
|
|
|
|
) -> Tuple[str, List[Message], List[Tuple[Tuple[int, int], Union[Chat, ChatMember]]]]:
|
|
|
|
|
msg_type = msg_element["type"]
|
|
|
|
|
msg_data = msg_element["data"]
|
|
|
|
|
main_text: str = ""
|
2021-06-04 14:04:17 +00:00
|
|
|
|
messages: List[Message] = []
|
|
|
|
|
at_list: List[Tuple[Tuple[int, int], Union[Chat, ChatMember]]] = []
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if msg_type == "text":
|
|
|
|
|
main_text = msg_data["text"]
|
|
|
|
|
elif msg_type == "face":
|
|
|
|
|
qq_face = int(msg_data["id"])
|
2021-06-04 14:04:17 +00:00
|
|
|
|
if qq_face in qq_emoji_list:
|
|
|
|
|
main_text = qq_emoji_list[qq_face]
|
|
|
|
|
else:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
main_text = "\u2753" # ❓
|
|
|
|
|
elif msg_type == "sface":
|
|
|
|
|
main_text = "\u2753" # ❓
|
|
|
|
|
elif msg_type == "at":
|
2021-06-04 14:04:17 +00:00
|
|
|
|
# todo Recheck if bug exists
|
2022-02-05 12:58:20 +00:00
|
|
|
|
g_id = context["group_id"]
|
2022-05-02 10:34:48 +00:00
|
|
|
|
my_uid = await self.get_qq_uid()
|
2022-02-05 12:58:20 +00:00
|
|
|
|
self.logger.debug("My QQ uid: %s\n" "QQ mentioned: %s\n", my_uid, msg_data["qq"])
|
|
|
|
|
if str(msg_data["qq"]) == "all":
|
|
|
|
|
group_card = "all"
|
2021-06-04 14:04:17 +00:00
|
|
|
|
else:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
member_info = await self.get_user_info(msg_data["qq"], group_id=g_id)["in_group_info"]
|
2022-02-05 12:58:20 +00:00
|
|
|
|
group_card = member_info["card"] if member_info["card"] != "" else member_info["nickname"]
|
|
|
|
|
self.logger.debug("Group card: {}".format(group_card))
|
2021-06-04 14:04:17 +00:00
|
|
|
|
substitution_begin = len(main_text)
|
|
|
|
|
substitution_end = len(main_text) + len(group_card) + 1
|
2022-02-05 12:58:20 +00:00
|
|
|
|
main_text = "@{} ".format(group_card)
|
|
|
|
|
if str(my_uid) == str(msg_data["qq"]) or str(msg_data["qq"]) == "all":
|
2021-06-04 14:04:17 +00:00
|
|
|
|
at_dict = ((substitution_begin, substitution_end), chat.self)
|
|
|
|
|
at_list.append(at_dict)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
elif msg_type == "reply":
|
2022-05-02 10:34:48 +00:00
|
|
|
|
ref_user = await self.get_user_info(msg_data["qq"])
|
2022-02-05 12:58:20 +00:00
|
|
|
|
main_text = (
|
|
|
|
|
f'「{ref_user["remark"]}({ref_user["nickname"]}):{msg_data["text"]}」\n'
|
|
|
|
|
"- - - - - - - - - - - - - - -\n"
|
|
|
|
|
)
|
2022-03-06 12:22:40 +00:00
|
|
|
|
elif msg_type == "forward":
|
2022-05-02 10:34:48 +00:00
|
|
|
|
forward_msgs = await self.coolq_api_query("get_forward_msg", message_id=msg_data["id"])["messages"]
|
2022-03-06 12:22:40 +00:00
|
|
|
|
logging.debug(f"Forwarded message: {forward_msgs}")
|
2022-05-02 10:34:48 +00:00
|
|
|
|
fmt_forward_msgs = await forward_msgs_wrapper(forward_msgs)
|
2022-03-06 12:22:40 +00:00
|
|
|
|
logging.debug(f"Formated forwarded message: {forward_msgs}")
|
|
|
|
|
header_msg = {"data": {"text": "合并转发消息开始\n- - - - - - - - - - - - - - -\n"}, "type": "text"}
|
|
|
|
|
footer_msg = {"data": {"text": "合并转发消息结束"}, "type": "text"}
|
|
|
|
|
fmt_forward_msgs.insert(0, header_msg)
|
|
|
|
|
fmt_forward_msgs.append(footer_msg)
|
2022-05-02 10:34:48 +00:00
|
|
|
|
main_text, messages, _ = await message_elements_wrapper(context, fmt_forward_msgs, chat)
|
2022-03-09 14:06:40 +00:00
|
|
|
|
return main_text, messages, []
|
2021-06-04 14:04:17 +00:00
|
|
|
|
else:
|
|
|
|
|
messages.extend(self.call_msg_decorator(msg_type, msg_data, chat))
|
|
|
|
|
return main_text, messages, at_list
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def message_elements_wrapper(
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context: Dict[str, Any], msg_elements: List[Dict[str, Any]], chat: Chat
|
|
|
|
|
) -> Tuple[str, List[Message], Dict[Tuple[int, int], Union[Chat, ChatMember]]]:
|
2021-06-09 12:54:47 +00:00
|
|
|
|
messages: List[Message] = []
|
2022-02-05 12:58:20 +00:00
|
|
|
|
main_text: str = ""
|
2021-06-09 12:54:47 +00:00
|
|
|
|
at_dict: Dict[Tuple[int, int], Union[Chat, ChatMember]] = {}
|
|
|
|
|
for msg_element in msg_elements:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
sub_main_text, sub_messages, sub_at_list = await message_element_wrapper(context, msg_element, chat)
|
2021-06-09 12:54:47 +00:00
|
|
|
|
main_text_len = len(main_text)
|
|
|
|
|
for at_tuple in sub_at_list:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
pos = (
|
|
|
|
|
at_tuple[0][0] + main_text_len,
|
|
|
|
|
at_tuple[0][1] + main_text_len,
|
|
|
|
|
)
|
2021-06-09 12:54:47 +00:00
|
|
|
|
at_dict[pos] = at_tuple[1]
|
|
|
|
|
main_text += sub_main_text
|
|
|
|
|
messages.extend(sub_messages)
|
|
|
|
|
return main_text, messages, at_dict
|
|
|
|
|
|
2021-02-15 15:32:47 +00:00
|
|
|
|
@self.coolq_bot.on_message
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def handle_msg(context: Event):
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.logger.debug(repr(context))
|
2022-02-05 12:58:20 +00:00
|
|
|
|
msg_elements = context["message"]
|
|
|
|
|
qq_uid = context["user_id"]
|
2021-02-15 15:32:47 +00:00
|
|
|
|
chat: Chat
|
|
|
|
|
author: ChatMember
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
user = await self.get_user_info(qq_uid)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if context["message_type"] == "private":
|
|
|
|
|
context["alias"] = user["remark"]
|
2022-05-02 10:34:48 +00:00
|
|
|
|
chat: PrivateChat = await self.chat_manager.build_efb_chat_as_private(context)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
else:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
chat = await self.chat_manager.build_efb_chat_as_group(context)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if "anonymous" not in context or context["anonymous"] is None:
|
|
|
|
|
if context["message_type"] == "group":
|
|
|
|
|
if context["sub_type"] == "notice":
|
2022-03-09 14:06:40 +00:00
|
|
|
|
context["event_description"] = "System Notification"
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context["uid_prefix"] = "group_notification"
|
2021-02-15 15:32:47 +00:00
|
|
|
|
author = chat.add_system_member(
|
2022-02-05 12:58:20 +00:00
|
|
|
|
name=context["event_description"],
|
|
|
|
|
uid=ChatID("__{context[uid_prefix]}__".format(context=context)),
|
2021-02-15 15:32:47 +00:00
|
|
|
|
)
|
|
|
|
|
else:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
user = await self.get_user_info(qq_uid, group_id=context["group_id"])
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context["nickname"] = user["remark"]
|
|
|
|
|
context["alias"] = user["in_group_info"]["card"]
|
2022-05-02 10:34:48 +00:00
|
|
|
|
author = await self.chat_manager.build_or_get_efb_member(chat, context)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
elif context["message_type"] == "private":
|
2021-02-15 15:32:47 +00:00
|
|
|
|
author = chat.other
|
|
|
|
|
else:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
author = await self.chat_manager.build_or_get_efb_member(chat, context)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
else: # anonymous user in group
|
|
|
|
|
author = self.chat_manager.build_efb_chat_as_anonymous_user(chat, context)
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
main_text, messages, at_dict = await message_elements_wrapper(context, msg_elements, chat)
|
2021-06-04 14:04:17 +00:00
|
|
|
|
|
2021-02-15 15:32:47 +00:00
|
|
|
|
if main_text != "":
|
2021-06-04 14:04:17 +00:00
|
|
|
|
messages.append(self.msg_decorator.qq_text_simple_wrapper(main_text, at_dict))
|
2022-02-05 12:58:20 +00:00
|
|
|
|
coolq_msg_id = context["message_id"]
|
2021-02-15 15:32:47 +00:00
|
|
|
|
for i in range(len(messages)):
|
|
|
|
|
if not isinstance(messages[i], Message):
|
|
|
|
|
continue
|
|
|
|
|
efb_msg: Message = messages[i]
|
2022-03-09 14:06:40 +00:00
|
|
|
|
efb_msg.uid = (
|
|
|
|
|
f"{chat.uid.split('_')[-1]}_{coolq_msg_id}_{i}"
|
|
|
|
|
if i > 0
|
|
|
|
|
else f"{chat.uid.split('_')[-1]}_{coolq_msg_id}"
|
|
|
|
|
)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
efb_msg.chat = chat
|
|
|
|
|
efb_msg.author = author
|
|
|
|
|
# if qq_uid != '80000000':
|
|
|
|
|
|
|
|
|
|
# Append discuss group into group list
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if context["message_type"] == "discuss" and efb_msg.chat not in self.discuss_list:
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.discuss_list.append(efb_msg.chat)
|
|
|
|
|
|
|
|
|
|
efb_msg.deliver_to = coordinator.master
|
|
|
|
|
|
|
|
|
|
def send_message_wrapper(*args, **kwargs):
|
|
|
|
|
threading.Thread(target=async_send_messages_to_master, args=args, kwargs=kwargs).start()
|
|
|
|
|
|
|
|
|
|
send_message_wrapper(efb_msg)
|
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
@self.coolq_bot.on_notice("group_increase")
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def handle_group_increase_msg(context: Event):
|
2022-03-09 14:06:40 +00:00
|
|
|
|
context["event_description"] = "\u2139 Group Member Increase Event"
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if (context["sub_type"]) == "invite":
|
2022-03-09 14:06:40 +00:00
|
|
|
|
text = "{nickname}({context[user_id]}) joined the group({group_name}) via invitation"
|
2021-02-15 15:32:47 +00:00
|
|
|
|
else:
|
2022-03-09 14:06:40 +00:00
|
|
|
|
text = "{nickname}({context[user_id]}) joined the group({group_name})"
|
2022-02-05 12:58:20 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
original_group = await self.get_group_info(context["group_id"], False)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
group_name = context["group_id"]
|
|
|
|
|
if original_group is not None and "group_name" in original_group:
|
|
|
|
|
group_name = original_group["group_name"]
|
|
|
|
|
text = text.format(
|
2022-05-02 10:34:48 +00:00
|
|
|
|
nickname=await self.get_stranger_info(context["user_id"])["nickname"],
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context=context,
|
|
|
|
|
group_name=group_name,
|
|
|
|
|
)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context["message"] = text
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.send_efb_group_notice(context)
|
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
@self.coolq_bot.on_notice("group_decrease")
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def handle_group_decrease_msg(context: Event):
|
2022-03-09 14:06:40 +00:00
|
|
|
|
context["event_description"] = "\u2139 Group Member Decrease Event"
|
2022-05-02 10:34:48 +00:00
|
|
|
|
original_group = await self.get_group_info(context["group_id"], False)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
group_name = context["group_id"]
|
|
|
|
|
if original_group is not None and "group_name" in original_group:
|
|
|
|
|
group_name = original_group["group_name"]
|
|
|
|
|
text = ""
|
|
|
|
|
if context["sub_type"] == "kick_me":
|
2022-03-09 14:06:40 +00:00
|
|
|
|
text = ("You've been kicked from the group({})").format(group_name)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
else:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if context["sub_type"] == "leave":
|
2022-03-09 14:06:40 +00:00
|
|
|
|
text = "{nickname}({context[user_id]}) quited the group({group_name})"
|
2021-02-15 15:32:47 +00:00
|
|
|
|
else:
|
2022-03-09 14:06:40 +00:00
|
|
|
|
text = "{nickname}({context[user_id]}) was kicked from the group({group_name})"
|
2022-02-05 12:58:20 +00:00
|
|
|
|
text = text.format(
|
2022-05-02 10:34:48 +00:00
|
|
|
|
nickname=await self.get_stranger_info(context["user_id"])["nickname"],
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context=context,
|
|
|
|
|
group_name=group_name,
|
|
|
|
|
)
|
|
|
|
|
context["message"] = text
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.send_efb_group_notice(context)
|
|
|
|
|
|
2022-03-12 11:49:03 +00:00
|
|
|
|
@self.coolq_bot.on_notice("group_admin")
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def handle_group_admin_msg(context: Event):
|
2022-03-14 05:13:26 +00:00
|
|
|
|
context["event_description"] = "\u2139 Group Admin Change Event"
|
2022-03-12 11:49:03 +00:00
|
|
|
|
if (context["sub_type"]) == "set":
|
2022-03-14 05:13:26 +00:00
|
|
|
|
text = "{nickname}({context[user_id]}) has been appointed as the group({group_name}) administrator"
|
2022-03-12 11:49:03 +00:00
|
|
|
|
else:
|
2022-03-14 05:13:26 +00:00
|
|
|
|
text = "{nickname}({context[user_id]}) has been de-appointed as the group({group_name}) administrator"
|
2022-03-12 11:49:03 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
original_group = await self.get_group_info(context["group_id"], False)
|
2022-03-12 11:49:03 +00:00
|
|
|
|
group_name = context["group_id"]
|
|
|
|
|
if original_group is not None and "group_name" in original_group:
|
|
|
|
|
group_name = original_group["group_name"]
|
|
|
|
|
text = text.format(
|
2022-05-02 10:34:48 +00:00
|
|
|
|
nickname=await self.get_stranger_info(context["user_id"])["nickname"],
|
2022-03-12 11:49:03 +00:00
|
|
|
|
context=context,
|
|
|
|
|
group_name=group_name,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
context["message"] = text
|
|
|
|
|
self.send_efb_group_notice(context)
|
|
|
|
|
|
|
|
|
|
@self.coolq_bot.on_notice("group_ban")
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def handle_group_ban_msg(context: Event):
|
2022-03-14 05:13:26 +00:00
|
|
|
|
context["event_description"] = "\u2139 Group Member Restrict Event"
|
2022-03-12 11:49:03 +00:00
|
|
|
|
if (context["sub_type"]) == "ban":
|
2022-03-14 05:13:26 +00:00
|
|
|
|
text = (
|
2022-03-12 11:52:26 +00:00
|
|
|
|
"{nickname}({context[user_id]}) "
|
|
|
|
|
"is restricted for speaking for {time} at the group({group_name}) by "
|
|
|
|
|
"{nickname_}({context[operator_id]})"
|
|
|
|
|
)
|
2022-03-12 11:49:03 +00:00
|
|
|
|
time_text = strf_time(context["duration"])
|
|
|
|
|
else:
|
2022-03-14 05:13:26 +00:00
|
|
|
|
text = (
|
2022-03-12 11:52:26 +00:00
|
|
|
|
"{nickname}({context[user_id]}) "
|
|
|
|
|
"is lifted from restrictions at the group({group_name}) by "
|
|
|
|
|
"{nickname_}({context[operator_id]}){time}"
|
|
|
|
|
)
|
2022-03-12 11:49:03 +00:00
|
|
|
|
time_text = ""
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
original_group = await self.get_group_info(context["group_id"], False)
|
2022-03-12 11:49:03 +00:00
|
|
|
|
group_name = context["group_id"]
|
|
|
|
|
if original_group is not None and "group_name" in original_group:
|
|
|
|
|
group_name = original_group["group_name"]
|
|
|
|
|
text = text.format(
|
2022-05-02 10:34:48 +00:00
|
|
|
|
nickname=await self.get_stranger_info(context["user_id"])["nickname"],
|
2022-03-12 11:49:03 +00:00
|
|
|
|
context=context,
|
|
|
|
|
time=time_text,
|
|
|
|
|
group_name=group_name,
|
2022-05-02 10:34:48 +00:00
|
|
|
|
nickname_=await self.get_stranger_info(context["operator_id"])["nickname"],
|
2022-03-12 11:49:03 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
context["message"] = text
|
|
|
|
|
self.send_efb_group_notice(context)
|
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
@self.coolq_bot.on_notice("offline_file")
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def handle_offline_file_upload_msg(context: Event):
|
2022-03-09 14:06:40 +00:00
|
|
|
|
context["event_description"] = "\u2139 Offline File Upload Event"
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context["uid_prefix"] = "offline_file"
|
2022-03-09 14:06:40 +00:00
|
|
|
|
file_info_msg = ("Filename: {file[name]}\n" "File size: {file[size]}").format(file=context["file"])
|
2022-05-02 10:34:48 +00:00
|
|
|
|
user = await self.get_user_info(context["user_id"])
|
2022-03-09 14:06:40 +00:00
|
|
|
|
text = "{remark}({nickname}) uploaded a file to you\n"
|
2022-02-05 12:58:20 +00:00
|
|
|
|
text = text.format(remark=user["remark"], nickname=user["nickname"]) + file_info_msg
|
|
|
|
|
context["message"] = text
|
2021-06-02 16:20:31 +00:00
|
|
|
|
self.send_msg_to_master(context)
|
|
|
|
|
param_dict = {
|
2022-02-05 12:58:20 +00:00
|
|
|
|
"context": context,
|
|
|
|
|
"download_url": context["file"]["url"],
|
2021-06-02 16:20:31 +00:00
|
|
|
|
}
|
|
|
|
|
threading.Thread(target=self.async_download_file, args=[], kwargs=param_dict).start()
|
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
@self.coolq_bot.on_notice("group_upload")
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def handle_group_file_upload_msg(context: Event):
|
2022-03-09 14:06:40 +00:00
|
|
|
|
context["event_description"] = "\u2139 Group File Upload Event"
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context["uid_prefix"] = "group_upload"
|
2022-05-02 10:34:48 +00:00
|
|
|
|
original_group = await self.get_group_info(context["group_id"], False)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
group_name = context["group_id"]
|
|
|
|
|
if original_group is not None and "group_name" in original_group:
|
|
|
|
|
group_name = original_group["group_name"]
|
|
|
|
|
|
2022-03-09 14:06:40 +00:00
|
|
|
|
file_info_msg = ("File ID: {file[id]}\n" "Filename: {file[name]}\n" "File size: {file[size]}").format(
|
2022-02-05 12:58:20 +00:00
|
|
|
|
file=context["file"]
|
|
|
|
|
)
|
2022-05-02 10:34:48 +00:00
|
|
|
|
member_info = await self.get_user_info(context["user_id"], group_id=context["group_id"])["in_group_info"]
|
2022-02-05 12:58:20 +00:00
|
|
|
|
group_card = member_info["card"] if member_info["card"] != "" else member_info["nickname"]
|
2022-03-09 14:06:40 +00:00
|
|
|
|
text = "{member_card}({context[user_id]}) uploaded a file to group({group_name})\n"
|
2022-02-05 12:58:20 +00:00
|
|
|
|
text = text.format(member_card=group_card, context=context, group_name=group_name) + file_info_msg
|
|
|
|
|
context["message"] = text
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.send_efb_group_notice(context)
|
|
|
|
|
|
|
|
|
|
param_dict = {
|
2022-02-05 12:58:20 +00:00
|
|
|
|
"context": context,
|
|
|
|
|
"group_id": context["group_id"],
|
|
|
|
|
"file_id": context["file"]["id"],
|
|
|
|
|
"busid": context["file"]["busid"],
|
2021-02-15 15:32:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-02 16:20:31 +00:00
|
|
|
|
threading.Thread(target=self.async_download_group_file, args=[], kwargs=param_dict).start()
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
@self.coolq_bot.on_notice("friend_add")
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def handle_friend_add_msg(context: Event):
|
2022-03-09 14:06:40 +00:00
|
|
|
|
context["event_description"] = "\u2139 New Friend Event"
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context["uid_prefix"] = "friend_add"
|
2022-03-09 14:06:40 +00:00
|
|
|
|
text = "{nickname}({context[user_id]}) has become your friend!"
|
2022-02-05 12:58:20 +00:00
|
|
|
|
text = text.format(
|
2022-05-02 10:34:48 +00:00
|
|
|
|
nickname=await self.get_stranger_info(context["user_id"])["nickname"],
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context=context,
|
|
|
|
|
)
|
|
|
|
|
context["message"] = text
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.send_msg_to_master(context)
|
|
|
|
|
|
2022-03-09 11:52:21 +00:00
|
|
|
|
@self.coolq_bot.on_notice("group_recall")
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def handle_group_recall_msg(context: Event):
|
2022-03-09 11:52:21 +00:00
|
|
|
|
coolq_msg_id = context["message_id"]
|
|
|
|
|
chat = GroupChat(channel=self.channel, uid=f"group_{context['group_id']}")
|
|
|
|
|
|
2022-03-09 14:06:40 +00:00
|
|
|
|
efb_msg = Message(chat=chat, uid=MessageID(f"{chat.uid.split('_')[-1]}_{coolq_msg_id}"))
|
|
|
|
|
coordinator.send_status(
|
|
|
|
|
MessageRemoval(source_channel=self.channel, destination_channel=coordinator.master, message=efb_msg)
|
2022-03-09 11:52:21 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@self.coolq_bot.on_notice("friend_recall")
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def handle_friend_recall_msg(context: Event):
|
2022-03-09 11:52:21 +00:00
|
|
|
|
coolq_msg_id = context["message_id"]
|
|
|
|
|
|
|
|
|
|
try:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
chat: PrivateChat = await self.chat_manager.build_efb_chat_as_private(context)
|
2022-03-09 14:06:40 +00:00
|
|
|
|
except Exception:
|
2022-03-09 11:52:21 +00:00
|
|
|
|
return
|
2022-03-09 14:06:40 +00:00
|
|
|
|
efb_msg = Message(chat=chat, uid=MessageID(f"{chat.uid.split('_')[-1]}_{coolq_msg_id}"))
|
|
|
|
|
coordinator.send_status(
|
|
|
|
|
MessageRemoval(source_channel=self.channel, destination_channel=coordinator.master, message=efb_msg)
|
2022-03-09 11:52:21 +00:00
|
|
|
|
)
|
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
@self.coolq_bot.on_request("friend") # Add friend request
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def handle_add_friend_request(context: Event):
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.logger.debug(repr(context))
|
2022-03-09 14:06:40 +00:00
|
|
|
|
context["event_description"] = "\u2139 New Friend Request"
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context["uid_prefix"] = "friend_request"
|
2022-03-09 14:06:40 +00:00
|
|
|
|
text = (
|
2022-02-05 12:58:20 +00:00
|
|
|
|
"{nickname}({context[user_id]}) wants to be your friend!\n"
|
|
|
|
|
"Here is the verification comment:\n"
|
|
|
|
|
"{context[comment]}"
|
|
|
|
|
)
|
|
|
|
|
text = text.format(
|
2022-05-02 10:34:48 +00:00
|
|
|
|
nickname=await self.get_stranger_info(context["user_id"])["nickname"],
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context=context,
|
|
|
|
|
)
|
|
|
|
|
context["message"] = text
|
|
|
|
|
commands = [
|
|
|
|
|
MessageCommand(
|
2022-03-09 14:06:40 +00:00
|
|
|
|
name=("Accept"),
|
2022-02-05 12:58:20 +00:00
|
|
|
|
callable_name="process_friend_request",
|
|
|
|
|
kwargs={"result": "accept", "flag": context["flag"]},
|
|
|
|
|
),
|
|
|
|
|
MessageCommand(
|
2022-03-09 14:06:40 +00:00
|
|
|
|
name=("Decline"),
|
2022-02-05 12:58:20 +00:00
|
|
|
|
callable_name="process_friend_request",
|
|
|
|
|
kwargs={"result": "decline", "flag": context["flag"]},
|
|
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
context["commands"] = commands
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.send_msg_to_master(context)
|
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
@self.coolq_bot.on_request("group")
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def handle_group_request(context: Event):
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.logger.debug(repr(context))
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context["uid_prefix"] = "group_request"
|
2022-05-02 10:34:48 +00:00
|
|
|
|
context["group_name"] = ("[Request]") + await self.get_group_info(context["group_id"])["group_name"]
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context["group_id_orig"] = context["group_id"]
|
|
|
|
|
context["group_id"] = str(context["group_id"]) + "_notification"
|
|
|
|
|
context["message_type"] = "group"
|
|
|
|
|
context["event_description"] = "\u2139 New Group Join Request"
|
2022-05-02 10:34:48 +00:00
|
|
|
|
original_group = await self.get_group_info(context["group_id_orig"], False)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
group_name = context["group_id"]
|
|
|
|
|
if original_group is not None and "group_name" in original_group:
|
|
|
|
|
group_name = original_group["group_name"]
|
2021-02-15 15:32:47 +00:00
|
|
|
|
msg = Message()
|
2022-02-05 12:58:20 +00:00
|
|
|
|
msg.uid = "group" + "_" + str(context["group_id"])
|
2022-03-08 12:10:35 +00:00
|
|
|
|
msg.author = (self.chat_manager.build_efb_chat_as_system_user(context)).other
|
2022-05-02 10:34:48 +00:00
|
|
|
|
msg.chat = await self.chat_manager.build_efb_chat_as_group(context)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
msg.deliver_to = coordinator.master
|
|
|
|
|
msg.type = MsgType.Text
|
|
|
|
|
name = ""
|
2022-05-02 10:34:48 +00:00
|
|
|
|
if not await self.get_friend_remark(context["user_id"]):
|
2021-02-15 15:32:47 +00:00
|
|
|
|
name = "{}({})[{}] ".format(
|
2022-05-02 10:34:48 +00:00
|
|
|
|
await self.get_stranger_info(context["user_id"])["nickname"],
|
|
|
|
|
await self.get_friend_remark(context["user_id"]),
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context["user_id"],
|
|
|
|
|
)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
else:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
name = "{}[{}] ".format(
|
2022-05-02 10:34:48 +00:00
|
|
|
|
await self.get_stranger_info(context["user_id"])["nickname"],
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context["user_id"],
|
|
|
|
|
)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
msg.text = "{} wants to join the group {}({}). \nHere is the comment: {}".format(
|
2022-02-05 12:58:20 +00:00
|
|
|
|
name, group_name, context["group_id_orig"], context["comment"]
|
|
|
|
|
)
|
|
|
|
|
msg.commands = MessageCommands(
|
|
|
|
|
[
|
|
|
|
|
MessageCommand(
|
2022-03-09 14:06:40 +00:00
|
|
|
|
name=("Accept"),
|
2022-02-05 12:58:20 +00:00
|
|
|
|
callable_name="process_group_request",
|
|
|
|
|
kwargs={
|
|
|
|
|
"result": "accept",
|
|
|
|
|
"flag": context["flag"],
|
|
|
|
|
"sub_type": context["sub_type"],
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
MessageCommand(
|
2022-03-09 14:06:40 +00:00
|
|
|
|
name=("Decline"),
|
2022-02-05 12:58:20 +00:00
|
|
|
|
callable_name="process_group_request",
|
|
|
|
|
kwargs={
|
|
|
|
|
"result": "decline",
|
|
|
|
|
"flag": context["flag"],
|
|
|
|
|
"sub_type": context["sub_type"],
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
]
|
2021-02-15 15:32:47 +00:00
|
|
|
|
)
|
|
|
|
|
coordinator.send_message(msg)
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
asyncio.run(self.check_status_periodically(run_once=True))
|
|
|
|
|
|
|
|
|
|
def run_instance(self, host: str, port: int, debug: bool = False):
|
|
|
|
|
def _run():
|
|
|
|
|
config = HyperConfig()
|
|
|
|
|
config.access_log_format = "%(h)s %(r)s %(s)s %(b)s %(D)s"
|
|
|
|
|
config.accesslog = create_serving_logger()
|
|
|
|
|
config.bind = [f"{host}:{port}"]
|
|
|
|
|
if debug is not None:
|
|
|
|
|
self.debug = debug
|
|
|
|
|
config.use_reloader = debug
|
|
|
|
|
config.errorlog = config.accesslog
|
|
|
|
|
|
|
|
|
|
self.loop.create_task(serve(self.coolq_bot.server_app, config, shutdown_trigger=self.shutdown_event.wait))
|
|
|
|
|
self.loop.create_task(self.check_status_periodically())
|
|
|
|
|
self.loop.create_task(self.update_contacts_periodically())
|
|
|
|
|
self.loop.run_forever()
|
|
|
|
|
|
|
|
|
|
self.t = threading.Thread(target=_run)
|
|
|
|
|
self.t.daemon = True
|
|
|
|
|
self.t.start()
|
|
|
|
|
|
|
|
|
|
def relogin(self):
|
|
|
|
|
raise NotImplementedError
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
|
|
|
|
def logout(self):
|
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
@extra(
|
2022-03-09 14:06:40 +00:00
|
|
|
|
name=("Check CoolQ Status"),
|
|
|
|
|
desc=("Force efb-qq-slave to refresh status from CoolQ Client.\n" "Usage: {function_name}"),
|
2022-02-05 12:58:20 +00:00
|
|
|
|
)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
def login(self, param: str = ""):
|
2022-05-02 10:34:48 +00:00
|
|
|
|
asyncio.run(self.check_status_periodically(run_once=True))
|
2022-02-05 12:58:20 +00:00
|
|
|
|
return "Done"
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def get_stranger_info(self, user_id: int, no_cache: bool = False) -> Dict[str, Any]:
|
2021-06-03 15:36:22 +00:00
|
|
|
|
user_id = int(user_id)
|
2022-05-02 10:34:48 +00:00
|
|
|
|
return await self.get_user_info(user_id, no_cache=no_cache)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def get_login_info(self) -> Dict[Any, Any]:
|
|
|
|
|
res = await self.coolq_bot.get_status()
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if "good" in res or "online" in res:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
data = await self.coolq_bot.get_login_info()
|
2022-02-05 12:58:20 +00:00
|
|
|
|
return {
|
|
|
|
|
"status": 0,
|
|
|
|
|
"data": {"uid": data["user_id"], "nickname": data["nickname"]},
|
|
|
|
|
}
|
2021-02-15 15:32:47 +00:00
|
|
|
|
else:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
return {"status": 1}
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def get_groups(self) -> List:
|
2021-02-15 15:32:47 +00:00
|
|
|
|
# todo Add support for discuss group iteration
|
2022-05-02 10:34:48 +00:00
|
|
|
|
await self.update_group_list() # Force update group list
|
2021-02-15 15:32:47 +00:00
|
|
|
|
res = self.group_list
|
|
|
|
|
# res = self.coolq_bot.get_group_list()
|
|
|
|
|
groups = []
|
|
|
|
|
for i in range(len(res)):
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context = {"message_type": "group", "group_id": res[i]["group_id"]}
|
2022-05-02 10:34:48 +00:00
|
|
|
|
efb_chat = await self.chat_manager.build_efb_chat_as_group(context)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
groups.append(efb_chat)
|
|
|
|
|
for i in range(len(self.extra_group_list)):
|
|
|
|
|
does_exist = False
|
2022-02-05 12:58:20 +00:00
|
|
|
|
for _j in range(len(res)):
|
|
|
|
|
if str(self.extra_group_list[i]["group_id"]) == str(res[i]["group_id"]):
|
2021-02-15 15:32:47 +00:00
|
|
|
|
does_exist = True
|
|
|
|
|
break
|
|
|
|
|
if does_exist:
|
|
|
|
|
continue
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context = {
|
|
|
|
|
"message_type": "group",
|
|
|
|
|
"group_id": self.extra_group_list[i]["group_id"],
|
|
|
|
|
}
|
2022-05-02 10:34:48 +00:00
|
|
|
|
efb_chat = await self.chat_manager.build_efb_chat_as_group(context)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
groups.append(efb_chat)
|
|
|
|
|
return groups + self.discuss_list
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def get_friends(self) -> List:
|
2021-02-15 15:32:47 +00:00
|
|
|
|
try:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
await self.update_friend_list() # Force update friend list
|
2021-02-15 15:32:47 +00:00
|
|
|
|
except CoolQAPIFailureException:
|
2022-03-09 14:06:40 +00:00
|
|
|
|
self.deliver_alert_to_master(("Failed to retrieve the friend list.\n" "Only groups are shown."))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
return []
|
|
|
|
|
users = []
|
2021-06-03 14:18:49 +00:00
|
|
|
|
for current_user in self.friend_list:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context = {
|
|
|
|
|
"user_id": str(current_user["user_id"]),
|
|
|
|
|
"nickname": current_user["nickname"],
|
|
|
|
|
"alias": current_user["remark"],
|
|
|
|
|
}
|
2022-05-02 10:34:48 +00:00
|
|
|
|
efb_chat = await self.chat_manager.build_efb_chat_as_private(context)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
users.append(efb_chat)
|
|
|
|
|
return users
|
|
|
|
|
|
|
|
|
|
def receive_message(self):
|
|
|
|
|
# Replaced by handle_msg()
|
|
|
|
|
pass
|
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
def send_message(self, msg: "Message") -> "Message":
|
2021-02-15 15:32:47 +00:00
|
|
|
|
# todo Add support for edited message
|
|
|
|
|
"""
|
|
|
|
|
self.logger.info("[%s] Sending message to WeChat:\n"
|
|
|
|
|
"uid: %s\n"
|
|
|
|
|
"Type: %s\n"
|
|
|
|
|
"Text: %s\n"
|
|
|
|
|
"Target Chat: %s\n"
|
|
|
|
|
"Target uid: %s\n",
|
|
|
|
|
msg.uid,
|
|
|
|
|
msg.chat.chat_uid, msg.type, msg.text, repr(msg.target.chat), msg.target.uid)
|
|
|
|
|
"""
|
|
|
|
|
m = QQMsgProcessor(instance=self)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
chat_type = msg.chat.uid.split("_")
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
self.logger.debug("[%s] Is edited: %s", msg.uid, msg.edit)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
if msg.edit:
|
2021-06-02 13:18:24 +00:00
|
|
|
|
try:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
uid_type = msg.uid.split("_")
|
2022-05-02 10:34:48 +00:00
|
|
|
|
asyncio.run(self.recall_message(uid_type[1]))
|
2021-06-02 13:18:24 +00:00
|
|
|
|
except CoolQAPIFailureException:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
raise EFBOperationNotSupported(
|
2022-03-09 14:06:40 +00:00
|
|
|
|
("Failed to recall the message!\n" "This message may have already expired.")
|
2022-02-05 12:58:20 +00:00
|
|
|
|
)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
|
|
|
|
if msg.type in [MsgType.Text, MsgType.Link]:
|
|
|
|
|
if msg.text == "kick`":
|
|
|
|
|
group_id = chat_type[1]
|
|
|
|
|
user_id = msg.target.author.uid
|
2022-05-02 10:34:48 +00:00
|
|
|
|
asyncio.run(self.coolq_api_query("set_group_kick", group_id=group_id, user_id=user_id))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
else:
|
|
|
|
|
if isinstance(msg.target, Message):
|
|
|
|
|
max_length = 50
|
|
|
|
|
tgt_text = coolq_text_encode(process_quote_text(msg.target.text, max_length))
|
|
|
|
|
tgt_alias = ""
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if chat_type[0] != "private" and not isinstance(msg.target.author, SelfChatMember):
|
2021-02-15 15:32:47 +00:00
|
|
|
|
tgt_alias += m.coolq_code_at_wrapper(msg.target.author.uid)
|
|
|
|
|
else:
|
|
|
|
|
tgt_alias = ""
|
2022-02-05 12:58:20 +00:00
|
|
|
|
msg.text = "%s%s\n\n%s" % (
|
|
|
|
|
tgt_alias,
|
|
|
|
|
tgt_text,
|
|
|
|
|
coolq_text_encode(msg.text),
|
|
|
|
|
)
|
2022-05-02 10:34:48 +00:00
|
|
|
|
msg.uid = asyncio.run(self.coolq_send_message(chat_type[0], chat_type[1], msg.text))
|
2022-02-05 12:58:20 +00:00
|
|
|
|
self.logger.debug("[%s] Sent as a text message. %s", msg.uid, msg.text)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
elif msg.type in (MsgType.Image, MsgType.Sticker, MsgType.Animation):
|
|
|
|
|
self.logger.info("[%s] Image/Sticker/Animation %s", msg.uid, msg.type)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
text = ""
|
2021-06-02 13:18:24 +00:00
|
|
|
|
if msg.type != MsgType.Sticker:
|
|
|
|
|
text += m.coolq_code_image_wrapper(msg.file, msg.path)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
else:
|
2021-06-02 13:18:24 +00:00
|
|
|
|
with tempfile.NamedTemporaryFile(suffix=".gif") as f:
|
|
|
|
|
img = Image.open(msg.file)
|
|
|
|
|
try:
|
|
|
|
|
alpha = img.split()[3]
|
|
|
|
|
mask = Image.eval(alpha, lambda a: 255 if a <= 128 else 0)
|
|
|
|
|
except IndexError:
|
|
|
|
|
mask = Image.eval(img.split()[0], lambda a: 0)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
img = img.convert("RGB").convert("P", palette=Image.ADAPTIVE, colors=255)
|
2021-06-02 13:18:24 +00:00
|
|
|
|
img.paste(255, mask)
|
|
|
|
|
img.save(f, transparency=255)
|
|
|
|
|
msg.file.close()
|
|
|
|
|
f.seek(0)
|
|
|
|
|
text += m.coolq_code_image_wrapper(f, f.name)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
if msg.text:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
msg.uid = asyncio.run(
|
|
|
|
|
self.coolq_send_message(chat_type[0], chat_type[1], text + coolq_text_encode(msg.text))
|
|
|
|
|
)
|
2021-07-19 05:34:22 +00:00
|
|
|
|
else:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
msg.uid = asyncio.run(self.coolq_send_message(chat_type[0], chat_type[1], text))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
# todo More MsgType Support
|
|
|
|
|
elif msg.type is MsgType.Voice:
|
|
|
|
|
text = m.coolq_voice_image_wrapper(msg.file, msg.path)
|
2022-05-02 10:34:48 +00:00
|
|
|
|
msg.uid = asyncio.run(self.coolq_send_message(chat_type[0], chat_type[1], text))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
if msg.text:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
asyncio.run(self.coolq_send_message(chat_type[0], chat_type[1], msg.text))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
return msg
|
|
|
|
|
|
2021-06-04 03:40:17 +00:00
|
|
|
|
def call_msg_decorator(self, msg_type: str, *args) -> List[Message]:
|
|
|
|
|
try:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
func = getattr(self.msg_decorator, "qq_{}_wrapper".format(msg_type))
|
2021-06-04 03:40:17 +00:00
|
|
|
|
except AttributeError:
|
2021-07-01 09:48:18 +00:00
|
|
|
|
msg = f"Unsupported message type: {msg_type}"
|
|
|
|
|
self.logger.error(msg)
|
|
|
|
|
return self.msg_decorator.qq_unsupported_wrapper(msg)
|
2021-06-04 03:40:17 +00:00
|
|
|
|
else:
|
|
|
|
|
return func(*args)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def get_qq_uid(self):
|
|
|
|
|
res = await self.get_login_info()
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if res["status"] == 0:
|
|
|
|
|
return res["data"]["uid"]
|
2021-02-15 15:32:47 +00:00
|
|
|
|
else:
|
|
|
|
|
return None
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def get_group_member_list(self, group_id, no_cache=False) -> List[Dict[str, Any]]:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if (
|
|
|
|
|
no_cache
|
|
|
|
|
or (group_id not in self.group_member_dict)
|
|
|
|
|
or (datetime.now() - self.group_member_dict[group_id]["time"] > timedelta(hours=1))
|
|
|
|
|
): # Force Update
|
2021-02-15 15:32:47 +00:00
|
|
|
|
try:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
member_list = await self.coolq_api_query("get_group_member_list", group_id=group_id, no_cache=no_cache)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
except CoolQAPIFailureException as e:
|
2022-03-09 14:06:40 +00:00
|
|
|
|
self.deliver_alert_to_master(("Failed the get group member detail.") + "{}".format(e))
|
2021-06-03 15:36:22 +00:00
|
|
|
|
return []
|
2021-06-03 14:18:49 +00:00
|
|
|
|
self.group_member_dict[group_id] = {
|
2022-02-05 12:58:20 +00:00
|
|
|
|
"members": member_list,
|
|
|
|
|
"time": datetime.now(),
|
2021-02-15 15:32:47 +00:00
|
|
|
|
}
|
2022-02-05 12:58:20 +00:00
|
|
|
|
return self.group_member_dict[group_id]["members"]
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def get_user_info(self, user_id: int, group_id: Optional[str] = None, no_cache=False):
|
2021-06-03 15:36:22 +00:00
|
|
|
|
user_id = int(user_id)
|
|
|
|
|
if no_cache or (not self.friend_list) or (user_id not in self.friend_dict):
|
2022-05-02 10:34:48 +00:00
|
|
|
|
await self.update_friend_list()
|
2022-03-09 14:06:40 +00:00
|
|
|
|
friend = self.friend_dict.get(user_id)
|
2021-06-02 16:20:31 +00:00
|
|
|
|
if friend:
|
2022-03-09 14:06:40 +00:00
|
|
|
|
user = copy.deepcopy(friend)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
user["is_friend"] = True
|
2021-06-02 16:20:31 +00:00
|
|
|
|
else:
|
2022-03-09 14:06:40 +00:00
|
|
|
|
if no_cache:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
stranger = await self.coolq_api_query("get_stranger_info", user_id=user_id)
|
2022-03-09 14:06:40 +00:00
|
|
|
|
self.stranger_dict[user_id] = stranger
|
|
|
|
|
stranger = self.stranger_dict.get(user_id)
|
|
|
|
|
if stranger is None:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
stranger = await self.coolq_api_query("get_stranger_info", user_id=user_id)
|
2022-03-09 14:06:40 +00:00
|
|
|
|
self.stranger_dict[user_id] = stranger
|
|
|
|
|
user = copy.deepcopy(stranger)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
user["is_friend"] = False
|
2021-06-03 15:36:22 +00:00
|
|
|
|
if group_id is not None:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
user["is_in_group"] = False
|
2022-05-02 10:34:48 +00:00
|
|
|
|
for member in await self.get_group_member_list(group_id):
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if member["user_id"] == user_id:
|
|
|
|
|
user["is_in_group"] = True
|
|
|
|
|
user["in_group_info"] = member
|
2021-06-03 15:36:22 +00:00
|
|
|
|
break
|
2022-02-05 12:58:20 +00:00
|
|
|
|
remark = user.get("remark")
|
2021-06-03 15:36:22 +00:00
|
|
|
|
if not remark:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
user["remark"] = user["nickname"]
|
2021-06-02 16:20:31 +00:00
|
|
|
|
return user
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def get_group_info(self, group_id, no_cache=False):
|
2021-02-15 15:32:47 +00:00
|
|
|
|
if no_cache or not self.group_list:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
await self.update_group_list()
|
2021-06-03 14:18:49 +00:00
|
|
|
|
group = self.group_dict.get(group_id)
|
|
|
|
|
if group:
|
|
|
|
|
return group
|
|
|
|
|
if no_cache:
|
|
|
|
|
for extra_group in self.extra_group_list:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if extra_group["group_id"] == group_id:
|
2021-06-03 14:18:49 +00:00
|
|
|
|
return extra_group
|
2021-02-15 15:32:47 +00:00
|
|
|
|
try:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
external_group = await self.get_external_group_info(group_id)
|
2021-06-03 14:18:49 +00:00
|
|
|
|
except CoolQAPIFailureException:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
self.logger.error(f"Get external group({group_id}) info failed.")
|
2021-02-15 15:32:47 +00:00
|
|
|
|
return None
|
|
|
|
|
else:
|
2021-06-03 14:18:49 +00:00
|
|
|
|
self.extra_group_list.append(external_group)
|
|
|
|
|
return external_group
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def coolq_send_message(self, msg_type, uid, message):
|
2022-02-05 12:58:20 +00:00
|
|
|
|
keyword = msg_type if msg_type != "private" else "user"
|
2022-05-02 10:34:48 +00:00
|
|
|
|
res = await self.coolq_api_query("send_msg", message_type=msg_type, **{keyword + "_id": uid}, message=message)
|
2022-03-09 11:52:21 +00:00
|
|
|
|
return str(uid) + "_" + str(res["message_id"])
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def _coolq_api_wrapper(self, func_name, **kwargs):
|
2021-02-15 15:32:47 +00:00
|
|
|
|
try:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
res = await self.coolq_bot.call_action(func_name, **kwargs)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
except RequestException as e:
|
2022-03-09 14:06:40 +00:00
|
|
|
|
raise CoolQDisconnectedException(("Unable to connect to CoolQ Client!" "Error Message:\n{}").format(str(e)))
|
2022-05-02 10:34:48 +00:00
|
|
|
|
except aiocqhttp.Error as ex:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
api_ex = CoolQAPIFailureException(
|
2022-03-09 14:06:40 +00:00
|
|
|
|
("CoolQ HTTP API encountered an error!\n" "Status Code:{} " "Return Code:{}").format(
|
2022-02-05 12:58:20 +00:00
|
|
|
|
ex.status_code, ex.retcode
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
api_ex.status_code = ex.status_code
|
|
|
|
|
api_ex.retcode = ex.retcode
|
2021-02-15 15:32:47 +00:00
|
|
|
|
raise api_ex
|
|
|
|
|
else:
|
|
|
|
|
return res
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def check_running_status(self):
|
|
|
|
|
res = await self._coolq_api_wrapper("get_status")
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if res["good"] or res["online"]:
|
2021-02-15 15:32:47 +00:00
|
|
|
|
return True
|
|
|
|
|
else:
|
2022-03-09 14:06:40 +00:00
|
|
|
|
raise CoolQOfflineException(("CoolQ Client isn't working correctly!"))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def coolq_api_query(self, func_name, **kwargs) -> Any:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
"""# Do not call get_status too frequently
|
2021-02-15 15:32:47 +00:00
|
|
|
|
if self.check_running_status():
|
|
|
|
|
return self._coolq_api_wrapper(func_name, **kwargs)
|
|
|
|
|
"""
|
|
|
|
|
if self.is_logged_in and self.is_connected:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
return await self._coolq_api_wrapper(func_name, **kwargs)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
elif self.repeat_counter < 3:
|
2022-03-09 14:06:40 +00:00
|
|
|
|
self.deliver_alert_to_master(("Your status is offline.\n" "You may try login with /0_login"))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.repeat_counter += 1
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def check_status_periodically(self, run_once: bool = False):
|
2021-02-15 15:32:47 +00:00
|
|
|
|
interval = 300
|
2022-05-02 10:34:48 +00:00
|
|
|
|
while True:
|
|
|
|
|
self.logger.debug("Start checking status...")
|
|
|
|
|
flag = True
|
|
|
|
|
try:
|
|
|
|
|
flag = await self.check_running_status()
|
|
|
|
|
except CoolQDisconnectedException as e:
|
|
|
|
|
if self.repeat_counter < 3:
|
|
|
|
|
self.deliver_alert_to_master(
|
|
|
|
|
(
|
|
|
|
|
"We're unable to communicate with CoolQ Client.\n"
|
|
|
|
|
"Please check the connection and credentials provided.\n"
|
|
|
|
|
"{}"
|
|
|
|
|
).format(str(e))
|
2022-02-05 12:58:20 +00:00
|
|
|
|
)
|
2022-05-02 10:34:48 +00:00
|
|
|
|
self.repeat_counter += 1
|
|
|
|
|
self.is_connected = False
|
|
|
|
|
self.is_logged_in = False
|
|
|
|
|
interval = 3600
|
|
|
|
|
except (CoolQOfflineException, CoolQAPIFailureException):
|
2021-02-15 15:32:47 +00:00
|
|
|
|
if self.repeat_counter < 3:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
self.deliver_alert_to_master(
|
2022-03-09 14:06:40 +00:00
|
|
|
|
(
|
2022-05-02 10:34:48 +00:00
|
|
|
|
"CoolQ is running in abnormal status.\n"
|
|
|
|
|
"You may need to relogin your account "
|
|
|
|
|
"or have a check in CoolQ Client.\n"
|
2022-02-05 12:58:20 +00:00
|
|
|
|
)
|
|
|
|
|
)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.repeat_counter += 1
|
|
|
|
|
self.is_connected = True
|
|
|
|
|
self.is_logged_in = False
|
|
|
|
|
interval = 3600
|
|
|
|
|
else:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
if not flag:
|
|
|
|
|
if self.repeat_counter < 3:
|
|
|
|
|
self.deliver_alert_to_master(
|
|
|
|
|
(
|
|
|
|
|
"We don't know why, but status check failed.\n"
|
|
|
|
|
"Please enable debug mode and consult the log "
|
|
|
|
|
"for more details."
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
self.repeat_counter += 1
|
|
|
|
|
self.is_connected = True
|
|
|
|
|
self.is_logged_in = False
|
|
|
|
|
interval = 3600
|
|
|
|
|
else:
|
|
|
|
|
self.logger.debug("Status: OK")
|
|
|
|
|
self.is_connected = True
|
|
|
|
|
self.is_logged_in = True
|
|
|
|
|
self.repeat_counter = 0
|
|
|
|
|
if run_once:
|
|
|
|
|
return
|
|
|
|
|
await asyncio.sleep(interval)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
|
|
|
|
def deliver_alert_to_master(self, message: str):
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context = {
|
|
|
|
|
"message": message,
|
|
|
|
|
"uid_prefix": "alert",
|
2022-03-09 14:06:40 +00:00
|
|
|
|
"event_description": ("CoolQ Alert"),
|
2022-02-05 12:58:20 +00:00
|
|
|
|
}
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.send_msg_to_master(context)
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def update_friend_list(self):
|
|
|
|
|
self.friend_list = await self.coolq_api_query("get_friend_list")
|
2021-02-15 15:32:47 +00:00
|
|
|
|
if self.friend_list:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
self.logger.debug("Update friend list completed. Entries: %s", len(self.friend_list))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
for friend in self.friend_list:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if friend["remark"] == "":
|
|
|
|
|
friend["remark"] = friend["nickname"]
|
|
|
|
|
self.friend_dict[friend["user_id"]] = friend
|
2021-02-15 15:32:47 +00:00
|
|
|
|
else:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
self.logger.warning("Failed to update friend list")
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def update_group_list(self):
|
|
|
|
|
self.group_list = await self.coolq_api_query("get_group_list")
|
2021-02-15 15:32:47 +00:00
|
|
|
|
if self.group_list:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
self.logger.debug("Update group list completed. Entries: %s", len(self.group_list))
|
2021-06-03 14:18:49 +00:00
|
|
|
|
for group in self.group_list:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
self.group_dict[group["group_id"]] = group
|
2021-02-15 15:32:47 +00:00
|
|
|
|
else:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
self.logger.warning("Failed to update group list")
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def update_contacts_periodically(self, run_once: bool = False):
|
2021-02-15 15:32:47 +00:00
|
|
|
|
interval = 1800
|
2022-05-02 10:34:48 +00:00
|
|
|
|
while True:
|
|
|
|
|
self.logger.debug("Start updating friend & group list")
|
|
|
|
|
if self.is_connected and self.is_logged_in:
|
|
|
|
|
try:
|
|
|
|
|
await self.update_friend_list()
|
|
|
|
|
await self.update_group_list()
|
|
|
|
|
except CoolQAPIFailureException as ex:
|
|
|
|
|
if (ex.status_code) == 200 and (ex.retcode) == 104 and self.update_repeat_counter < 3:
|
|
|
|
|
self.send_cookie_expired_alarm()
|
|
|
|
|
if self.update_repeat_counter < 3:
|
|
|
|
|
self.deliver_alert_to_master(("Errors occurred when updating contacts: ") + (ex.message))
|
|
|
|
|
self.update_repeat_counter += 1
|
|
|
|
|
else:
|
|
|
|
|
self.update_repeat_counter = 0
|
|
|
|
|
self.logger.debug("Update completed")
|
|
|
|
|
if run_once:
|
|
|
|
|
return
|
|
|
|
|
await asyncio.sleep(interval)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def get_friend_remark(self, uid):
|
2021-06-03 14:18:49 +00:00
|
|
|
|
if (not self.friend_list) or (uid not in self.friend_dict):
|
2022-05-02 10:34:48 +00:00
|
|
|
|
await self.update_friend_list()
|
2021-06-03 14:18:49 +00:00
|
|
|
|
if uid not in self.friend_dict:
|
2021-02-15 15:32:47 +00:00
|
|
|
|
return None # I don't think you have such a friend
|
2022-02-05 12:58:20 +00:00
|
|
|
|
return self.friend_dict[uid]["remark"]
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
|
|
|
|
def send_efb_group_notice(self, context):
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context["message_type"] = "group"
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.logger.debug(repr(context))
|
2022-05-02 10:34:48 +00:00
|
|
|
|
chat = asyncio.run(self.chat_manager.build_efb_chat_as_group(context))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
try:
|
|
|
|
|
author = chat.get_member(SystemChatMember.SYSTEM_ID)
|
|
|
|
|
except KeyError:
|
|
|
|
|
author = chat.add_system_member()
|
2022-03-12 11:49:03 +00:00
|
|
|
|
event_description = context.get("event_description", "")
|
2021-02-15 15:32:47 +00:00
|
|
|
|
msg = Message(
|
|
|
|
|
uid="__group_notice__.%s" % int(time.time()),
|
|
|
|
|
type=MsgType.Text,
|
|
|
|
|
chat=chat,
|
|
|
|
|
author=author,
|
2022-03-12 11:49:03 +00:00
|
|
|
|
text=(event_description + "\n\n" + context["message"]) if event_description else context["message"],
|
2022-02-05 12:58:20 +00:00
|
|
|
|
deliver_to=coordinator.master,
|
2021-02-15 15:32:47 +00:00
|
|
|
|
)
|
|
|
|
|
coordinator.send_message(msg)
|
|
|
|
|
|
|
|
|
|
def send_msg_to_master(self, context):
|
|
|
|
|
self.logger.debug(repr(context))
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if not getattr(coordinator, "master", None): # Master Channel not initialized
|
|
|
|
|
raise Exception(context["message"])
|
2021-02-15 15:32:47 +00:00
|
|
|
|
chat = self.chat_manager.build_efb_chat_as_system_user(context)
|
|
|
|
|
try:
|
|
|
|
|
author = chat.get_member(SystemChatMember.SYSTEM_ID)
|
|
|
|
|
except KeyError:
|
|
|
|
|
author = chat.add_system_member()
|
|
|
|
|
msg = Message(
|
2022-02-05 12:58:20 +00:00
|
|
|
|
uid="__{context[uid_prefix]}__.{uni_id}".format(context=context, uni_id=str(int(time.time()))),
|
2021-02-15 15:32:47 +00:00
|
|
|
|
type=MsgType.Text,
|
|
|
|
|
chat=chat,
|
|
|
|
|
author=author,
|
2022-02-05 12:58:20 +00:00
|
|
|
|
deliver_to=coordinator.master,
|
2021-02-15 15:32:47 +00:00
|
|
|
|
)
|
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
if "message" in context:
|
|
|
|
|
msg.text = context["message"]
|
|
|
|
|
if "commands" in context:
|
|
|
|
|
msg.commands = MessageCommands(context["commands"])
|
2021-02-15 15:32:47 +00:00
|
|
|
|
coordinator.send_message(msg)
|
|
|
|
|
|
|
|
|
|
# As the old saying goes
|
|
|
|
|
# A programmer spent 20% of time on coding
|
|
|
|
|
# while the rest 80% on considering a variable/function/class name
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def get_external_group_info(self, group_id): # Special thanks to @lwl12 for thinking of this name
|
|
|
|
|
res = await self.coolq_api_query("get_group_info", group_id=group_id)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
return res
|
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
def send_status(self, status: "Status"):
|
2021-02-15 15:32:47 +00:00
|
|
|
|
if isinstance(status, MessageRemoval):
|
|
|
|
|
if not isinstance(status.message.author, SelfChatMember):
|
2022-03-09 14:06:40 +00:00
|
|
|
|
raise EFBMessageError(("You can only recall your own messages."))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
try:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
uid_type = status.message.uid.split("_")
|
2022-05-02 10:34:48 +00:00
|
|
|
|
asyncio.run(self.recall_message(uid_type[1]))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
except CoolQAPIFailureException:
|
2022-03-09 14:06:40 +00:00
|
|
|
|
raise EFBMessageError(("Failed to recall the message. This message may have already expired."))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
else:
|
|
|
|
|
raise EFBOperationNotSupported()
|
|
|
|
|
# todo
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def recall_message(self, message_id):
|
|
|
|
|
await self.coolq_api_query("delete_msg", message_id=message_id)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
|
|
|
|
def send_cookie_expired_alarm(self):
|
2022-02-05 12:58:20 +00:00
|
|
|
|
self.deliver_alert_to_master(
|
2022-03-09 14:06:40 +00:00
|
|
|
|
(
|
2022-02-05 12:58:20 +00:00
|
|
|
|
"Your cookie of CoolQ Client seems to be expired. "
|
|
|
|
|
"Although it will not affect the normal functioning of sending/receiving "
|
|
|
|
|
"messages, however, you may encounter issues like failing to retrieve "
|
|
|
|
|
"friend list. Please consult "
|
|
|
|
|
"https://github.com/milkice233/efb-qq-slave/wiki/Workaround-for-expired"
|
|
|
|
|
"-cookies-of-CoolQ for solutions."
|
|
|
|
|
)
|
|
|
|
|
)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def process_friend_request(self, result, flag):
|
2022-02-05 12:58:20 +00:00
|
|
|
|
res = "true" if result == "accept" else "false"
|
2021-02-15 15:32:47 +00:00
|
|
|
|
try:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
await self.coolq_api_query("set_friend_add_request", approve=res, flag=flag)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
except CoolQAPIFailureException as e:
|
2022-03-09 14:06:40 +00:00
|
|
|
|
return ("Failed to process request! Error Message:\n") + getattr(e, "message", repr(e))
|
2022-02-05 12:58:20 +00:00
|
|
|
|
return "Done"
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def process_group_request(self, result, flag, sub_type):
|
2022-02-05 12:58:20 +00:00
|
|
|
|
res = "true" if result == "accept" else "false"
|
2021-02-15 15:32:47 +00:00
|
|
|
|
try:
|
2022-05-02 10:34:48 +00:00
|
|
|
|
await self.coolq_api_query("set_group_add_request", approve=res, flag=flag, sub_type=sub_type)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
except CoolQAPIFailureException as e:
|
2022-03-09 14:06:40 +00:00
|
|
|
|
return ("Failed to process request! Error Message:\n") + getattr(e, "message", repr(e))
|
2022-02-05 12:58:20 +00:00
|
|
|
|
return "Done"
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2021-06-02 16:20:31 +00:00
|
|
|
|
def async_download_file(self, context, download_url):
|
2021-05-30 17:16:50 +00:00
|
|
|
|
res = download_file(download_url)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
if isinstance(res, str):
|
2022-03-09 14:06:40 +00:00
|
|
|
|
context["message"] = ("[Download] ") + res
|
2021-02-15 15:32:47 +00:00
|
|
|
|
self.send_efb_group_notice(context)
|
|
|
|
|
elif res is None:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
data = {"file": res, "filename": context["file"]["name"]}
|
|
|
|
|
context["message_type"] = "group"
|
2021-02-15 15:32:47 +00:00
|
|
|
|
efb_msg = self.msg_decorator.qq_file_after_wrapper(data)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
efb_msg.uid = str(context["user_id"]) + "_" + str(uuid.uuid4()) + "_" + str(1)
|
|
|
|
|
efb_msg.text = "Sent a file\n{}".format(context["file"]["name"])
|
|
|
|
|
if context["uid_prefix"] == "offline_file":
|
2022-05-02 10:34:48 +00:00
|
|
|
|
efb_msg.chat = asyncio.run(self.chat_manager.build_efb_chat_as_private(context))
|
2022-02-05 12:58:20 +00:00
|
|
|
|
elif context["uid_prefix"] == "group_upload":
|
2022-05-02 10:34:48 +00:00
|
|
|
|
efb_msg.chat = asyncio.run(self.chat_manager.build_efb_chat_as_group(context))
|
|
|
|
|
efb_msg.author = asyncio.run(self.chat_manager.build_or_get_efb_member(efb_msg.chat, context))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
efb_msg.deliver_to = coordinator.master
|
|
|
|
|
async_send_messages_to_master(efb_msg)
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def async_download_group_file(self, context, group_id, file_id, busid):
|
|
|
|
|
file = await self.coolq_api_query("get_group_file_url", group_id=group_id, file_id=file_id, busid=busid)
|
2022-02-05 12:58:20 +00:00
|
|
|
|
download_url = file["url"]
|
2021-06-02 16:20:31 +00:00
|
|
|
|
self.async_download_file(context, download_url)
|
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
def get_chat_picture(self, chat: "Chat") -> BinaryIO:
|
|
|
|
|
chat_type = chat.uid.split("_")
|
|
|
|
|
if chat_type[0] == "private":
|
2021-02-15 15:32:47 +00:00
|
|
|
|
return download_user_avatar(chat_type[1])
|
2022-02-05 12:58:20 +00:00
|
|
|
|
elif chat_type[0] == "group":
|
2021-02-15 15:32:47 +00:00
|
|
|
|
return download_group_avatar(chat_type[1])
|
|
|
|
|
else:
|
|
|
|
|
return download_group_avatar("")
|
|
|
|
|
|
|
|
|
|
def get_chats(self):
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def _get_chats():
|
|
|
|
|
return await asyncio.gather(self.get_friends(), self.get_groups())
|
|
|
|
|
|
|
|
|
|
friend_chats, group_chats = asyncio.run(_get_chats())
|
|
|
|
|
return friend_chats + group_chats
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
2022-02-05 12:58:20 +00:00
|
|
|
|
def get_chat(self, chat_uid: ChatID) -> "Chat":
|
2021-02-15 15:32:47 +00:00
|
|
|
|
# todo what is member_uid used for?
|
2022-02-05 12:58:20 +00:00
|
|
|
|
chat_type = chat_uid.split("_")
|
|
|
|
|
if chat_type[0] == "private":
|
2021-02-15 15:32:47 +00:00
|
|
|
|
qq_uid = int(chat_type[1])
|
2022-05-02 10:34:48 +00:00
|
|
|
|
remark = asyncio.run(self.get_friend_remark(qq_uid))
|
2022-03-09 14:06:40 +00:00
|
|
|
|
context: Dict[str, Any] = {"user_id": qq_uid}
|
2021-02-15 15:32:47 +00:00
|
|
|
|
if remark is not None:
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context["alias"] = remark
|
2022-05-02 10:34:48 +00:00
|
|
|
|
return asyncio.run(self.chat_manager.build_efb_chat_as_private(context))
|
2022-02-05 12:58:20 +00:00
|
|
|
|
elif chat_type[0] == "group":
|
2021-02-15 15:32:47 +00:00
|
|
|
|
group_id = int(chat_type[1])
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context = {"message_type": "group", "group_id": group_id}
|
2022-05-02 10:34:48 +00:00
|
|
|
|
return asyncio.run(self.chat_manager.build_efb_chat_as_group(context, update_member=True))
|
2022-02-05 12:58:20 +00:00
|
|
|
|
elif chat_type[0] == "discuss":
|
2021-02-15 15:32:47 +00:00
|
|
|
|
discuss_id = int(chat_type[1])
|
2022-02-05 12:58:20 +00:00
|
|
|
|
context = {"message_type": "discuss", "discuss_id": discuss_id}
|
2022-05-02 10:34:48 +00:00
|
|
|
|
return asyncio.run(self.chat_manager.build_efb_chat_as_group(context))
|
2021-02-15 15:32:47 +00:00
|
|
|
|
raise EFBChatNotFound()
|
|
|
|
|
|
2022-05-02 10:34:48 +00:00
|
|
|
|
async def check_self_update(self, run_once: bool = False):
|
2021-02-15 15:32:47 +00:00
|
|
|
|
interval = 60 * 60 * 24
|
2022-05-02 10:34:48 +00:00
|
|
|
|
while True:
|
|
|
|
|
latest_version = self.channel.check_updates()
|
|
|
|
|
if latest_version is not None:
|
|
|
|
|
self.deliver_alert_to_master(
|
|
|
|
|
"New version({version}) of EFB-QQ-Slave has released! "
|
|
|
|
|
"Please manually update EQS by stopping ehForwarderbot first and then execute "
|
|
|
|
|
"<code>pip3 install --upgrade efb-qq-slave</code>".format(version=latest_version)
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
pass
|
|
|
|
|
if run_once:
|
|
|
|
|
return
|
|
|
|
|
await asyncio.sleep(interval)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
|
|
|
|
def poll(self):
|
2022-05-02 10:34:48 +00:00
|
|
|
|
asyncio.run(self.check_self_update(run_once=True))
|
2022-02-05 12:58:20 +00:00
|
|
|
|
self.run_instance(
|
|
|
|
|
host=self.client_config["host"],
|
|
|
|
|
port=self.client_config["port"],
|
|
|
|
|
debug=False,
|
|
|
|
|
)
|
2021-02-15 15:32:47 +00:00
|
|
|
|
|
|
|
|
|
def stop_polling(self):
|
2022-05-02 10:34:48 +00:00
|
|
|
|
self.logger.debug("Gracefully stopping QQ Slave")
|
|
|
|
|
self.shutdown_event.set()
|
|
|
|
|
self.loop.stop()
|
|
|
|
|
self.t.join()
|