efb-qq-plugin-go-cqhttp/efb_qq_plugin_go_cqhttp/GoCQHttp.py

1104 lines
48 KiB
Python
Raw Normal View History

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
2021-02-15 15:32:47 +00:00
from gettext import translation
2022-02-05 12:58:20 +00:00
from typing import Any, BinaryIO, Dict, List, Optional, Tuple, Union
2021-02-15 15:32:47 +00:00
2021-05-30 17:40:01 +00:00
import cherrypy
2021-02-15 15:32:47 +00:00
import cqhttp
2021-05-30 17:40:01 +00:00
from cherrypy._cpserver import Server
2021-02-15 15:32:47 +00:00
from cherrypy.process.wspbus import states
from cqhttp import CQHttp
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,
PrivateChat,
SelfChatMember,
SystemChatMember,
)
from ehforwarderbot.exceptions import (
EFBChatNotFound,
EFBMessageError,
EFBOperationNotSupported,
)
from ehforwarderbot.chat import GroupChat
2022-02-05 12:58:20 +00:00
from ehforwarderbot.message import MessageCommand, MessageCommands
2021-02-15 15:32:47 +00:00
from ehforwarderbot.status import MessageRemoval
from ehforwarderbot.types import ChatID, MessageID
2021-02-15 15:32:47 +00:00
from ehforwarderbot.utils import extra
2022-02-05 12:58:20 +00:00
from PIL import Image
2021-02-15 15:32:47 +00:00
from pkg_resources import resource_filename
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,
)
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-02-05 12:58:20 +00:00
translator = translation(
"efb_qq_slave",
resource_filename("efb_qq_slave", "Clients/CoolQ/locale"),
fallback=True,
)
2021-02-15 15:32:47 +00:00
_ = translator.gettext
ngettext = translator.ngettext
friend_list = []
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] = {}
2021-02-15 15:32:47 +00:00
group_list = []
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] = {}
2021-02-15 15:32:47 +00:00
discuss_list = []
extra_group_list = []
repeat_counter = 0
update_repeat_counter = 0
event = threading.Event()
update_contacts_timer: threading.Timer
self_update_timer: threading.Timer
check_status_timer: threading.Timer
cherryServer: Server
can_send_image: bool = False
can_send_voice: bool = False
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-03-06 12:22:40 +00:00
def forward_msgs_wrapper(msg_elements: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
fmt_msgs = []
for msg in msg_elements:
from_user = self.get_user_info(msg["sender"]["user_id"])
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()
fmt_msgs += forward_msgs_wrapper([inner_msg])
else:
fmt_msgs.append(inner_msg)
return fmt_msgs
2022-02-05 12:58:20 +00:00
def message_element_wrapper(
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"]
2021-06-04 14:04:17 +00:00
my_uid = 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-02-05 12:58:20 +00:00
member_info = self.get_user_info(msg_data["qq"], group_id=g_id)["in_group_info"]
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":
ref_user = self.get_user_info(msg_data["qq"])
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":
forward_msgs = self.coolq_api_query("get_forward_msg", message_id=msg_data["id"])["messages"]
logging.debug(f"Forwarded message: {forward_msgs}")
fmt_forward_msgs = forward_msgs_wrapper(forward_msgs)
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)
return message_elements_wrapper(context, fmt_forward_msgs, chat)
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-02-05 12:58:20 +00:00
def message_elements_wrapper(
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:
sub_main_text, sub_messages, sub_at_list = message_element_wrapper(context, msg_element, chat)
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
def handle_msg(context):
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
2021-06-03 15:36:22 +00:00
user = self.get_user_info(qq_uid)
2022-02-05 12:58:20 +00:00
if context["message_type"] == "private":
context["alias"] = user["remark"]
2021-02-15 15:32:47 +00:00
chat: PrivateChat = self.chat_manager.build_efb_chat_as_private(context)
else:
chat = self.chat_manager.build_efb_chat_as_group(context)
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":
context["event_description"] = self._("System Notification")
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-02-05 12:58:20 +00:00
user = self.get_user_info(qq_uid, group_id=context["group_id"])
context["nickname"] = user["remark"]
context["alias"] = user["in_group_info"]["card"]
2021-02-15 15:32:47 +00:00
author = 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:
author = self.chat_manager.build_or_get_efb_member(chat, context)
else: # anonymous user in group
author = self.chat_manager.build_efb_chat_as_anonymous_user(chat, context)
2021-06-09 12:54:47 +00:00
main_text, messages, at_dict = 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]
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")
2021-02-15 15:32:47 +00:00
def handle_group_increase_msg(context):
2022-02-05 12:58:20 +00:00
context["event_description"] = self._("\u2139 Group Member Increase Event")
if (context["sub_type"]) == "invite":
text = self._("{nickname}({context[user_id]}) joined the group({group_name}) via invitation")
2021-02-15 15:32:47 +00:00
else:
2022-02-05 12:58:20 +00:00
text = self._("{nickname}({context[user_id]}) joined the group({group_name})")
original_group = self.get_group_info(context["group_id"], False)
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(
nickname=self.get_stranger_info(context["user_id"])["nickname"],
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")
2021-02-15 15:32:47 +00:00
def handle_group_decrease_msg(context):
2022-02-05 12:58:20 +00:00
context["event_description"] = self._("\u2139 Group Member Decrease Event")
original_group = self.get_group_info(context["group_id"], False)
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":
2021-02-15 15:32:47 +00:00
text = self._("You've been kicked from the group({})").format(group_name)
else:
2022-02-05 12:58:20 +00:00
if context["sub_type"] == "leave":
text = self._("{nickname}({context[user_id]}) quited the group({group_name})")
2021-02-15 15:32:47 +00:00
else:
2022-02-05 12:58:20 +00:00
text = self._("{nickname}({context[user_id]}) was kicked from the group({group_name})")
text = text.format(
nickname=self.get_stranger_info(context["user_id"])["nickname"],
context=context,
group_name=group_name,
)
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("offline_file")
2021-06-02 16:20:31 +00:00
def handle_offline_file_upload_msg(context):
2022-02-05 12:58:20 +00:00
context["event_description"] = self._("\u2139 Offline File Upload Event")
context["uid_prefix"] = "offline_file"
file_info_msg = self._("Filename: {file[name]}\n" "File size: {file[size]}").format(file=context["file"])
user = self.get_user_info(context["user_id"])
text = self._("{remark}({nickname}) uploaded a file to you\n")
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")
2021-02-15 15:32:47 +00:00
def handle_group_file_upload_msg(context):
2022-02-05 12:58:20 +00:00
context["event_description"] = self._("\u2139 Group File Upload Event")
context["uid_prefix"] = "group_upload"
original_group = self.get_group_info(context["group_id"], False)
group_name = context["group_id"]
if original_group is not None and "group_name" in original_group:
group_name = original_group["group_name"]
file_info_msg = self._("File ID: {file[id]}\n" "Filename: {file[name]}\n" "File size: {file[size]}").format(
file=context["file"]
)
member_info = self.get_user_info(context["user_id"], group_id=context["group_id"])["in_group_info"]
group_card = member_info["card"] if member_info["card"] != "" else member_info["nickname"]
text = self._("{member_card}({context[user_id]}) uploaded a file to group({group_name})\n")
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")
2021-02-15 15:32:47 +00:00
def handle_friend_add_msg(context):
2022-02-05 12:58:20 +00:00
context["event_description"] = self._("\u2139 New Friend Event")
context["uid_prefix"] = "friend_add"
text = self._("{nickname}({context[user_id]}) has become your friend!")
text = text.format(
nickname=self.get_stranger_info(context["user_id"])["nickname"],
context=context,
)
context["message"] = text
2021-02-15 15:32:47 +00:00
self.send_msg_to_master(context)
@self.coolq_bot.on_notice("group_recall")
def handle_group_recall_msg(context):
coolq_msg_id = context["message_id"]
chat = GroupChat(channel=self.channel, uid=f"group_{context['group_id']}")
efb_msg = Message(
chat=chat,
2022-03-09 12:56:45 +00:00
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))
@self.coolq_bot.on_notice("friend_recall")
def handle_friend_recall_msg(context):
coolq_msg_id = context["message_id"]
try:
chat: PrivateChat = self.chat_manager.build_efb_chat_as_private(context)
except:
return
efb_msg = Message(
chat=chat,
2022-03-09 12:56:45 +00:00
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-02-05 12:58:20 +00:00
@self.coolq_bot.on_request("friend") # Add friend request
2021-02-15 15:32:47 +00:00
def handle_add_friend_request(context):
self.logger.debug(repr(context))
2022-02-05 12:58:20 +00:00
context["event_description"] = self._("\u2139 New Friend Request")
context["uid_prefix"] = "friend_request"
text = self._(
"{nickname}({context[user_id]}) wants to be your friend!\n"
"Here is the verification comment:\n"
"{context[comment]}"
)
text = text.format(
nickname=self.get_stranger_info(context["user_id"])["nickname"],
context=context,
)
context["message"] = text
commands = [
MessageCommand(
name=self._("Accept"),
callable_name="process_friend_request",
kwargs={"result": "accept", "flag": context["flag"]},
),
MessageCommand(
name=self._("Decline"),
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")
2021-02-15 15:32:47 +00:00
def handle_group_request(context):
self.logger.debug(repr(context))
2022-02-05 12:58:20 +00:00
context["uid_prefix"] = "group_request"
context["group_name"] = self._("[Request]") + self.get_group_info(context["group_id"])["group_name"]
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"
original_group = 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"])
msg.author = (self.chat_manager.build_efb_chat_as_system_user(context)).other
2021-02-15 15:32:47 +00:00
msg.chat = self.chat_manager.build_efb_chat_as_group(context)
msg.deliver_to = coordinator.master
msg.type = MsgType.Text
name = ""
2022-02-05 12:58:20 +00:00
if not self.get_friend_remark(context["user_id"]):
2021-02-15 15:32:47 +00:00
name = "{}({})[{}] ".format(
2022-02-05 12:58:20 +00:00
self.get_stranger_info(context["user_id"])["nickname"],
self.get_friend_remark(context["user_id"]),
context["user_id"],
)
2021-02-15 15:32:47 +00:00
else:
2022-02-05 12:58:20 +00:00
name = "{}[{}] ".format(
self.get_stranger_info(context["user_id"])["nickname"],
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(
name=self._("Accept"),
callable_name="process_group_request",
kwargs={
"result": "accept",
"flag": context["flag"],
"sub_type": context["sub_type"],
},
),
MessageCommand(
name=self._("Decline"),
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)
self.check_status_periodically(threading.Event())
self.update_contacts_timer = threading.Timer(1800, self.update_contacts_periodically, [threading.Event()])
self.update_contacts_timer.start()
# threading.Thread(target=self.check_running_status).start()
def run_instance(self, *args, **kwargs):
# threading.Thread(target=self.coolq_bot.run, args=args, kwargs=kwargs, daemon=True).start()
cherrypy.tree.graft(self.coolq_bot.wsgi, "/")
cherrypy.server.unsubscribe()
self.cherryServer = Server()
2022-02-05 12:58:20 +00:00
self.cherryServer.socket_host = self.client_config["host"]
self.cherryServer.socket_port = self.client_config["port"]
2021-02-15 15:32:47 +00:00
self.cherryServer.subscribe()
cherrypy.engine.start()
cherrypy.engine.wait(states.EXITING)
2022-02-05 12:58:20 +00:00
@extra(
name=_("Restart CoolQ Client"),
desc=_(
"Force CoolQ to restart\n"
"Usage: {function_name} [-l] [-c] [-e]\n"
" -l: Restart and clean log\n"
" -c: Restart and clean cache\n"
" -e: Restart and clean event\n"
),
)
2021-02-15 15:32:47 +00:00
def relogin(self, param: str = ""):
param_dict = dict()
if param:
2022-02-05 12:58:20 +00:00
params = param.split(" ")
2021-02-15 15:32:47 +00:00
for each_param in params:
2022-02-05 12:58:20 +00:00
if each_param == " ":
2021-02-15 15:32:47 +00:00
continue
2022-02-05 12:58:20 +00:00
if each_param == "-l":
param_dict["clean_log"] = "true"
elif each_param == "-c":
param_dict["clean_cache"] = "true"
elif each_param == "-e":
param_dict["clean_event"] = "true"
2021-02-15 15:32:47 +00:00
else:
return self._("Unknown parameter: {}.").format(param)
self.logger.debug(repr(param_dict))
2022-02-05 12:58:20 +00:00
self.coolq_api_query("_set_restart", **param_dict)
return "Done. Please wait for a while."
2021-02-15 15:32:47 +00:00
def logout(self):
raise NotImplementedError
2022-02-05 12:58:20 +00:00
@extra(
name=_("Check CoolQ Status"),
desc=_("Force efb-qq-slave to refresh status from CoolQ Client.\n" "Usage: {function_name}"),
)
2021-02-15 15:32:47 +00:00
def login(self, param: str = ""):
self.check_status_periodically(None)
2022-02-05 12:58:20 +00:00
return "Done"
2021-02-15 15:32:47 +00:00
2021-06-03 15:36:22 +00:00
def get_stranger_info(self, user_id: int, no_cache: bool = False) -> Dict[str, Any]:
user_id = int(user_id)
return self.get_user_info(user_id, no_cache=no_cache)
2021-02-15 15:32:47 +00:00
def get_login_info(self) -> Dict[Any, Any]:
res = self.coolq_bot.get_status()
2022-02-05 12:58:20 +00:00
if "good" in res or "online" in res:
2021-02-15 15:32:47 +00:00
data = 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
def get_groups(self) -> List:
# todo Add support for discuss group iteration
self.update_group_list() # Force update group list
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"]}
2021-02-15 15:32:47 +00:00
efb_chat = self.chat_manager.build_efb_chat_as_group(context)
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"],
}
2021-02-15 15:32:47 +00:00
efb_chat = self.chat_manager.build_efb_chat_as_group(context)
groups.append(efb_chat)
return groups + self.discuss_list
def get_friends(self) -> List:
try:
self.update_friend_list() # Force update friend list
except CoolQAPIFailureException:
2022-02-05 12:58:20 +00:00
self.deliver_alert_to_master(self._("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"],
}
2021-02-15 15:32:47 +00:00
efb_chat = self.chat_manager.build_efb_chat_as_private(context)
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("_")
2021-06-02 13:18:24 +00:00
self.recall_message(uid_type[1])
except CoolQAPIFailureException:
2022-02-05 12:58:20 +00:00
raise EFBOperationNotSupported(
self._("Failed to recall the message!\n" "This message may have already expired.")
)
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-02-05 12:58:20 +00:00
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),
)
2021-02-15 15:32:47 +00:00
msg.uid = 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 not self.can_send_image:
self.check_features() # Force checking features
2022-02-05 12:58:20 +00:00
raise EFBOperationNotSupported(
self._("Unable to send image now. Please check your CoolQ version " "or retry later")
)
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:
2021-07-19 05:34:22 +00:00
msg.uid = self.coolq_send_message(chat_type[0], chat_type[1], text + coolq_text_encode(msg.text))
else:
msg.uid = 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:
if not self.can_send_voice:
self.check_features() # Force checking features
2022-02-05 12:58:20 +00:00
raise EFBOperationNotSupported(
self._(
"Unable to send voice now. Please check your CoolQ version "
" and install CoolQ audio library or retry later"
)
)
2021-02-15 15:32:47 +00:00
text = m.coolq_voice_image_wrapper(msg.file, msg.path)
msg.uid = self.coolq_send_message(chat_type[0], chat_type[1], text)
if msg.text:
self.coolq_send_message(chat_type[0], chat_type[1], msg.text)
return msg
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))
except AttributeError:
msg = f"Unsupported message type: {msg_type}"
self.logger.error(msg)
return self.msg_decorator.qq_unsupported_wrapper(msg)
else:
return func(*args)
2021-02-15 15:32:47 +00:00
def get_qq_uid(self):
res = 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
2021-06-03 15:36:22 +00:00
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-02-05 12:58:20 +00:00
member_list = 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:
self.deliver_alert_to_master(self._("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
2021-06-03 15:36:22 +00:00
def get_user_info(self, user_id: int, group_id: Optional[str] = None, no_cache=False):
user_id = int(user_id)
if no_cache or (not self.friend_list) or (user_id not in self.friend_dict):
2021-06-02 16:20:31 +00:00
self.update_friend_list()
2021-06-03 15:42:53 +00:00
friend = copy.deepcopy(self.friend_dict.get(user_id))
2021-06-02 16:20:31 +00:00
if friend:
2021-06-03 15:42:53 +00:00
user = friend
2022-02-05 12:58:20 +00:00
user["is_friend"] = True
2021-06-02 16:20:31 +00:00
else:
2021-06-03 15:42:53 +00:00
user = copy.deepcopy(self.stranger_dict.get(user_id))
2021-06-03 15:36:22 +00:00
if no_cache or (user is None):
2022-02-05 12:58:20 +00:00
user = self.coolq_api_query("get_stranger_info", user_id=user_id)
2021-06-03 15:42:53 +00:00
self.stranger_dict[user_id] = copy.deepcopy(user)
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
2021-06-03 15:36:22 +00:00
for member in 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
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:
2021-06-03 14:18:49 +00:00
self.update_group_list()
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:
external_group = 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
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"
res = self.coolq_api_query("send_msg", message_type=msg_type, **{keyword + "_id": uid}, message=message)
return str(uid) + "_" + str(res["message_id"])
2021-02-15 15:32:47 +00:00
def _coolq_api_wrapper(self, func_name, **kwargs):
try:
func = getattr(self.coolq_bot, func_name)
res = func(**kwargs)
except RequestException as e:
2022-02-05 12:58:20 +00:00
raise CoolQDisconnectedException(
self._("Unable to connect to CoolQ Client!" "Error Message:\n{}").format(str(e))
)
2021-02-15 15:32:47 +00:00
except cqhttp.Error as ex:
2022-02-05 12:58:20 +00:00
api_ex = CoolQAPIFailureException(
self._("CoolQ HTTP API encountered an error!\n" "Status Code:{} " "Return Code:{}").format(
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
def check_running_status(self):
2022-02-05 12:58:20 +00:00
res = self._coolq_api_wrapper("get_status")
if res["good"] or res["online"]:
2021-02-15 15:32:47 +00:00
return True
else:
raise CoolQOfflineException(self._("CoolQ Client isn't working correctly!"))
def coolq_api_query(self, func_name, **kwargs):
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:
return self._coolq_api_wrapper(func_name, **kwargs)
elif self.repeat_counter < 3:
2022-02-05 12:58:20 +00:00
self.deliver_alert_to_master(self._("Your status is offline.\n" "You may try login with /0_login"))
2021-02-15 15:32:47 +00:00
self.repeat_counter += 1
def check_status_periodically(self, t_event):
2022-02-05 12:58:20 +00:00
self.logger.debug("Start checking status...")
2021-02-15 15:32:47 +00:00
flag = True
interval = 300
try:
flag = self.check_running_status()
except CoolQDisconnectedException as e:
if self.repeat_counter < 3:
2022-02-05 12:58:20 +00:00
self.deliver_alert_to_master(
self._(
"We're unable to communicate with CoolQ Client.\n"
"Please check the connection and credentials provided.\n"
"{}"
).format(str(e))
)
2021-02-15 15:32:47 +00:00
self.repeat_counter += 1
self.is_connected = False
self.is_logged_in = False
interval = 3600
except (CoolQOfflineException, CoolQAPIFailureException):
if self.repeat_counter < 3:
2022-02-05 12:58:20 +00:00
self.deliver_alert_to_master(
self._(
"CoolQ is running in abnormal status.\n"
"You may need to relogin your account "
"or have a check in CoolQ Client.\n"
)
)
2021-02-15 15:32:47 +00:00
self.repeat_counter += 1
self.is_connected = True
self.is_logged_in = False
interval = 3600
else:
if not flag:
if self.repeat_counter < 3:
2022-02-05 12:58:20 +00:00
self.deliver_alert_to_master(
self._(
"We don't know why, but status check failed.\n"
"Please enable debug mode and consult the log "
"for more details."
)
)
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-02-05 12:58:20 +00:00
self.logger.debug("Status: OK")
2021-02-15 15:32:47 +00:00
self.is_connected = True
self.is_logged_in = True
self.repeat_counter = 0
self.check_features()
if t_event is not None and not t_event.is_set():
self.check_status_timer = threading.Timer(interval, self.check_status_periodically, [t_event])
self.check_status_timer.start()
def deliver_alert_to_master(self, message: str):
2022-02-05 12:58:20 +00:00
context = {
"message": message,
"uid_prefix": "alert",
"event_description": self._("CoolQ Alert"),
}
2021-02-15 15:32:47 +00:00
self.send_msg_to_master(context)
def update_friend_list(self):
2022-02-05 12:58:20 +00:00
self.friend_list = 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
def update_group_list(self):
2022-02-05 12:58:20 +00:00
self.group_list = 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
def update_contacts_periodically(self, t_event):
2022-02-05 12:58:20 +00:00
self.logger.debug("Start updating friend & group list")
2021-02-15 15:32:47 +00:00
interval = 1800
if self.is_connected and self.is_logged_in:
try:
self.update_friend_list()
self.update_group_list()
except CoolQAPIFailureException as ex:
2022-02-05 12:58:20 +00:00
if (ex.status_code) == 200 and (ex.retcode) == 104 and self.update_repeat_counter < 3:
2021-02-15 15:32:47 +00:00
self.send_cookie_expired_alarm()
if self.update_repeat_counter < 3:
2022-02-05 12:58:20 +00:00
self.deliver_alert_to_master(self._("Errors occurred when updating contacts: ") + (ex.message))
2021-02-15 15:32:47 +00:00
self.update_repeat_counter += 1
else:
self.update_repeat_counter = 0
2022-02-05 12:58:20 +00:00
self.logger.debug("Update completed")
2021-02-15 15:32:47 +00:00
if t_event is not None and not t_event.is_set():
self.update_contacts_timer = threading.Timer(interval, self.update_contacts_periodically, [t_event])
self.update_contacts_timer.start()
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):
self.update_friend_list()
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))
chat = self.chat_manager.build_efb_chat_as_group(context)
try:
author = chat.get_member(SystemChatMember.SYSTEM_ID)
except KeyError:
author = chat.add_system_member()
msg = Message(
uid="__group_notice__.%s" % int(time.time()),
type=MsgType.Text,
chat=chat,
author=author,
2022-02-05 12:58:20 +00:00
text=context["message"],
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
def get_external_group_info(self, group_id): # Special thanks to @lwl12 for thinking of this name
2022-02-05 12:58:20 +00:00
res = 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-02-05 12:58:20 +00:00
raise EFBMessageError(self._("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("_")
2021-02-15 15:32:47 +00:00
self.recall_message(uid_type[1])
except CoolQAPIFailureException:
2022-02-05 12:58:20 +00:00
raise EFBMessageError(self._("Failed to recall the message. This message may have already expired."))
2021-02-15 15:32:47 +00:00
else:
raise EFBOperationNotSupported()
# todo
def recall_message(self, message_id):
2022-02-05 12:58:20 +00:00
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(
self._(
"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
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-02-05 12:58:20 +00:00
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-02-05 12:58:20 +00:00
return self._("Failed to process request! Error Message:\n") + getattr(e, "message", repr(e))
return "Done"
2021-02-15 15:32:47 +00:00
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-02-05 12:58:20 +00:00
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-02-05 12:58:20 +00:00
return self._("Failed to process request! Error Message:\n") + getattr(e, "message", repr(e))
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-02-05 12:58:20 +00:00
context["message"] = self._("[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":
2021-06-02 16:20:31 +00:00
efb_msg.chat = self.chat_manager.build_efb_chat_as_private(context)
2022-02-05 12:58:20 +00:00
elif context["uid_prefix"] == "group_upload":
2021-06-02 16:20:31 +00:00
efb_msg.chat = self.chat_manager.build_efb_chat_as_group(context)
2021-02-15 15:32:47 +00:00
efb_msg.author = self.chat_manager.build_or_get_efb_member(efb_msg.chat, context)
efb_msg.deliver_to = coordinator.master
async_send_messages_to_master(efb_msg)
2021-06-02 16:20:31 +00:00
def async_download_group_file(self, context, group_id, file_id, busid):
2022-02-05 12:58:20 +00:00
file = self.coolq_api_query("get_group_file_url", group_id=group_id, file_id=file_id, busid=busid)
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):
qq_chats = self.get_friends()
group_chats = self.get_groups()
return qq_chats + group_chats
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])
remark = self.get_friend_remark(qq_uid)
context = {"user_id": qq_uid}
if remark is not None:
2022-02-05 12:58:20 +00:00
context["alias"] = remark
2021-02-15 15:32:47 +00:00
return 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}
2021-02-15 15:32:47 +00:00
return 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}
2021-02-15 15:32:47 +00:00
return self.chat_manager.build_efb_chat_as_group(context)
raise EFBChatNotFound()
def check_self_update(self, t_event):
interval = 60 * 60 * 24
latest_version = self.channel.check_updates()
if latest_version is not None:
2022-02-05 12:58:20 +00:00
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)
)
2021-02-15 15:32:47 +00:00
else:
if t_event is not None and not t_event.is_set():
self.self_update_timer = threading.Timer(interval, self.check_self_update, [t_event])
self.self_update_timer.start()
def poll(self):
self.check_self_update(threading.Event())
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
self.logger.debug("EQS gracefully shut down")
def stop_polling(self):
self.update_contacts_timer.cancel()
self.check_status_timer.cancel()
self.self_update_timer.cancel()
cherrypy.engine.exit()
def check_features(self):
2022-02-05 12:58:20 +00:00
self.can_send_image = self.coolq_api_query("can_send_image")["yes"]
self.can_send_voice = self.coolq_api_query("can_send_record")["yes"]