From 9e1e2733424fe7a94c1e428ef6918f2d780b317a Mon Sep 17 00:00:00 2001 From: Henry Yang Date: Sun, 21 Jan 2024 16:14:49 +0800 Subject: [PATCH] 0.0.5 pre MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 从多线程更改成异步以节约资源 抽奖更新以及加入连抽 bot_status.py 小更改 --- database.py | 12 +--- main_config.yml | 7 +- plans_manager.py | 2 + plugin_interface.py | 1 - plugin_manager.py | 26 +++---- plugins/admin_points.py | 3 +- plugins/bot_status.py | 3 +- plugins/bot_status.yml | 3 +- plugins/gpt.py | 2 - plugins/gpt4.py | 2 - plugins/lucky_draw.py | 140 ++++++++++++++++++++++++++++++-------- plugins/lucky_draw.yml | 33 +++++---- plugins/menu.yml | 2 +- plugins/random_picture.py | 2 - requirements.txt | 3 +- singleton.py | 14 ++++ start.py | 63 ++++++++--------- 17 files changed, 202 insertions(+), 116 deletions(-) create mode 100644 singleton.py diff --git a/database.py b/database.py index 4b7e5c5..87fb5ba 100644 --- a/database.py +++ b/database.py @@ -9,20 +9,14 @@ from loguru import logger +from singleton import singleton + # 2b queue没法获取返回值 +@singleton class BotDatabase: - _instance = None - - def __new__(cls, *args, **kw): - if cls._instance is None: - cls._instance = object.__new__(cls, *args, **kw) - return cls._instance - def __init__(self): - super().__init__() - self.database = sqlite3.connect('userpoints.db', check_same_thread=False) # 连接数据库 self.wxid_list = self._get_wxid_list() # 获取已有用户列表 diff --git a/main_config.yml b/main_config.yml index 02c496d..a088942 100644 --- a/main_config.yml +++ b/main_config.yml @@ -1,12 +1,13 @@ -#Version 0.0.4 +#Version 0.0.5 pre +bot_version: "v0.0.5 pre" + #如果不知道自己在干什么请别动这两行 ip: 127.0.0.1 port: 5555 admins: [ "" ] -# 建议:(cpu核心数)*5-4 -max_thread: 16 +max_worker: 25 command_prefix: "/" diff --git a/plans_manager.py b/plans_manager.py index aa63ba3..ff0af29 100644 --- a/plans_manager.py +++ b/plans_manager.py @@ -8,8 +8,10 @@ import os from plans_interface import PlansInterface +from singleton import singleton +@singleton class PlansManager: def __init__(self): self.plans = {} diff --git a/plugin_interface.py b/plugin_interface.py index 2744868..5f99846 100644 --- a/plugin_interface.py +++ b/plugin_interface.py @@ -4,7 +4,6 @@ # # This program is licensed under the GNU General Public License v3.0. -# plugin_interface.py class PluginInterface: def run(self, recv): raise NotImplementedError("Subclasses must implement the 'run' method.") diff --git a/plugin_manager.py b/plugin_manager.py index 567f814..fb9c66c 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -3,8 +3,6 @@ # This program is licensed under the GNU General Public License v3.0. # # This program is licensed under the GNU General Public License v3.0. -# -# This program is licensed under the GNU General Public License v3.0. import importlib import os @@ -13,19 +11,12 @@ from loguru import logger from plugin_interface import PluginInterface +from singleton import singleton +@singleton class PluginManager: - _instance = None - - def __new__(cls, *args, **kw): - if cls._instance is None: - cls._instance = object.__new__(cls, *args, **kw) - return cls._instance - def __init__(self): - super().__init__() - self.plugins = {} self.keywords = {} @@ -62,7 +53,8 @@ def get_keywords(self): return self.keywords def load_plugin(self, plugin_name): - if plugin_name not in self.plugins: + if plugin_name not in self.plugins and plugin_name not in self.excluded_plugins and plugin_name != [ + 'manage_plugins']: module = importlib.import_module(f'plugins.{plugin_name}') plugin_class = getattr(module, plugin_name) if issubclass(plugin_class, PluginInterface): @@ -79,11 +71,10 @@ def load_plugins(self, plugin_dir): for plugin_file in os.listdir(plugin_dir): if plugin_file.endswith(".py") and plugin_file != "__init__.py" and not plugin_file.startswith('_'): plugin_name = os.path.splitext(plugin_file)[0] - if plugin_name not in self.excluded_plugins: - self.load_plugin(plugin_name) + self.load_plugin(plugin_name) def unload_plugin(self, plugin_name): - if plugin_name in self.plugins and plugin_name not in ['manage_plugins']: + if plugin_name in self.plugins and plugin_name != ['manage_plugins']: del self.plugins[plugin_name] self.refresh_keywords() logger.debug('- 已卸载插件:{plugin_name}'.format(plugin_name=plugin_name)) @@ -92,13 +83,16 @@ def unload_plugin(self, plugin_name): return False def reload_plugin(self, plugin_name): - if self.unload_plugin(plugin_name): + if self.unload_plugin(plugin_name) and plugin_name != ['manage_plugins']: if self.load_plugin(plugin_name): logger.debug('! 已重载插件:{plugin_name}'.format(plugin_name=plugin_name)) return True else: logger.debug('! 重载插件失败:{plugin_name}'.format(plugin_name=plugin_name)) return False + else: + logger.debug('! 重载插件失败:{plugin_name}'.format(plugin_name=plugin_name)) + return False # 实例化插件管理器 diff --git a/plugins/admin_points.py b/plugins/admin_points.py index 7d22392..8a161b5 100644 --- a/plugins/admin_points.py +++ b/plugins/admin_points.py @@ -26,10 +26,9 @@ def __init__(self): self.bot = pywxdll.Pywxdll(self.ip, self.port) # 机器人api self.admin_list = main_config['admins'] - - def run(self, recv): self.db = BotDatabase() + def run(self, recv): if recv['id1']: # 用于判断是否为管理员 admin_wxid = recv['id1'] # 是群 else: diff --git a/plugins/bot_status.py b/plugins/bot_status.py index 9ef6f1a..2ea5d1b 100644 --- a/plugins/bot_status.py +++ b/plugins/bot_status.py @@ -21,13 +21,14 @@ def __init__(self): config = yaml.load(f.read(), Loader=yaml.FullLoader) self.status_message = config['status_message'] - self.bot_version = config['bot_version'] current_directory = os.path.dirname(os.path.abspath(__file__)) main_config_path = os.path.join(current_directory, '../main_config.yml') with open(main_config_path, 'r', encoding='utf-8') as f: # 读取设置 main_config = yaml.load(f.read(), Loader=yaml.FullLoader) + self.bot_version = main_config['bot_version'] + self.ip = main_config['ip'] self.port = main_config['port'] self.bot = pywxdll.Pywxdll(self.ip, self.port) # 机器人api diff --git a/plugins/bot_status.yml b/plugins/bot_status.yml index cc91c64..55714cf 100644 --- a/plugins/bot_status.yml +++ b/plugins/bot_status.yml @@ -1,5 +1,4 @@ keywords: ["机器人状态","bottest"] plugin_name: "bot_status" -status_message: "Bot Running😊" -bot_version: "v0.0.4" \ No newline at end of file +status_message: "Bot Running😊" \ No newline at end of file diff --git a/plugins/gpt.py b/plugins/gpt.py index 05b9dbc..f63fcc1 100644 --- a/plugins/gpt.py +++ b/plugins/gpt.py @@ -3,8 +3,6 @@ # This program is licensed under the GNU General Public License v3.0. # # This program is licensed under the GNU General Public License v3.0. -# -# This program is licensed under the GNU General Public License v3.0. import os diff --git a/plugins/gpt4.py b/plugins/gpt4.py index f9e8c35..8e13aaa 100644 --- a/plugins/gpt4.py +++ b/plugins/gpt4.py @@ -3,8 +3,6 @@ # This program is licensed under the GNU General Public License v3.0. # # This program is licensed under the GNU General Public License v3.0. -# -# This program is licensed under the GNU General Public License v3.0. import os diff --git a/plugins/lucky_draw.py b/plugins/lucky_draw.py index b25584a..9936633 100644 --- a/plugins/lucky_draw.py +++ b/plugins/lucky_draw.py @@ -22,6 +22,7 @@ def __init__(self): config = yaml.load(f.read(), Loader=yaml.FullLoader) self.lucky_draw_probability = config['lucky_draw_probability'] + self.max_draw = config['max_draw'] current_directory = os.path.dirname(os.path.abspath(__file__)) main_config_path = os.path.join(current_directory, '../main_config.yml') @@ -35,6 +36,10 @@ def __init__(self): self.db = database.BotDatabase() def run(self, recv): + global draw_count, draw_name + + # -----初始化与消息格式监测----- + if recv['id1']: # 用于判断是否为管理员 target_wxid = recv['id1'] # 是群 else: @@ -45,47 +50,84 @@ def run(self, recv): target_points = self.db.get_points(target_wxid) error = '' - if len(command) != 2: - error = '-----XYBot-----\n❌命令格式错误!请查看菜单获取正确命令格式' - else: + + if len(command) == 2: draw_name = command[1] + draw_count = 1 - if not draw_name in self.lucky_draw_probability.keys(): + if draw_name not in self.lucky_draw_probability.keys(): error = '-----XYBot-----\n❌抽奖种类未知或者无效' elif draw_name in self.lucky_draw_probability.keys() and target_points < \ self.lucky_draw_probability[draw_name][ 'cost']: error = '-----XYBot-----\n❌积分不足!' + elif len(command) == 3: + draw_name = command[1] + draw_count = int(command[2]) + + if draw_name not in self.lucky_draw_probability.keys(): + error = '-----XYBot-----\n❌抽奖种类未知或者无效' + elif draw_name in self.lucky_draw_probability.keys() and target_points < \ + self.lucky_draw_probability[draw_name][ + 'cost'] * draw_count: + error = '-----XYBot-----\n❌积分不足!' + else: + error = '-----XYBot-----\n❌命令格式错误!请查看菜单获取正确命令格式' + if not error: + + # -----抽奖核心部分----- + draw_probability = self.lucky_draw_probability[draw_name]['probability'] - draw_cost = self.lucky_draw_probability[draw_name]['cost'] + draw_cost = self.lucky_draw_probability[draw_name]['cost'] * draw_count + + wins = [] self.db.add_points(target_wxid, -1 * draw_cost) - random_num = random.uniform(0, 1) - cumulative_probability = 0 - for probability, prize_dict in draw_probability.items(): - cumulative_probability += float(probability) - if random_num <= cumulative_probability: - win_name = prize_dict['name'] - win_points = prize_dict['points'] - - logger.info( - '[抽奖] {target_wxid}在{draw_name}抽奖中抽到了{win_name} 抽到了{win_points}点积分'.format( - target_wxid=target_wxid, draw_name=draw_name, win_name=win_name, win_points=win_points)) - self.db.add_points(target_wxid, win_points) - out_message = '-----XYBot-----\n🥳恭喜你在 {draw_name}抽奖 中抽到了 {win_name}!✌️你抽到了 {win_points} 点积分!\n🙏🏻谢谢惠顾!\n\n🥳你在抽 {draw_name}抽奖 ,{draw_name}抽奖 需要{draw_cost}点积分💰,中奖概率如下❗️\n\n'.format( - draw_name=draw_name, draw_cost=draw_cost, win_name=win_name, win_points=win_points) - - for probability, prize_info in draw_probability.items(): - message = '🤑{prize_name}:概率为{probability}%,奖励为{prize_points}点积分\n'.format( - prize_name=prize_info['name'], probability=int(float(probability) * 100), - prize_points=prize_info['points']) - out_message += message - self.send_friend_or_group(recv, out_message) - - break + # 保底抽奖 + min_guaranteed = draw_count // 10 + for _ in range(min_guaranteed): + random_num = random.uniform(0, 0.4) + cumulative_probability = 0 + for probability, prize_dict in draw_probability.items(): + cumulative_probability += float(probability) + if random_num <= cumulative_probability: + win_name = prize_dict['name'] + win_points = prize_dict['points'] + win_symbol = prize_dict['symbol'] + + wins.append((win_name, win_points, win_symbol)) + break + + # 正常抽奖 + for _ in range(draw_count - min_guaranteed): + random_num = random.uniform(0, 1) + cumulative_probability = 0 + for probability, prize_dict in draw_probability.items(): + cumulative_probability += float(probability) + if random_num <= cumulative_probability: + win_name = prize_dict['name'] + win_points = prize_dict['points'] + win_symbol = prize_dict['symbol'] + + wins.append((win_name, win_points, win_symbol)) + break + + # -----消息组建----- + + total_win_points = 0 + for win_name, win_points, win_symbol in wins: + total_win_points += win_points + + self.db.add_points(target_wxid, total_win_points) + logger.info( + f'[抽奖] wxid: {target_wxid} | 抽奖名: {draw_name} | 次数: {draw_count} | 赢取积分: {total_win_points}') + + message = self.make_message(wins, draw_name, draw_count, total_win_points, draw_cost) + + self.send_friend_or_group(recv, message) else: self.send_friend_or_group(recv, error) @@ -98,3 +140,45 @@ def send_friend_or_group(self, recv, out_message='null'): else: logger.info('[发送信息]{out_message}| [发送到] {wxid}'.format(out_message=out_message, wxid=recv['wxid'])) self.bot.send_txt_msg(recv['wxid'], out_message) # 发送 + + @staticmethod + def make_message(wins, draw_name, draw_count, total_win_points, draw_cost): + name_max_len = 0 + for win_name, win_points, win_symbol in wins: + if len(win_name) > name_max_len: + name_max_len = len(win_name) + + begin_message = f"----XYBot抽奖----\n🥳恭喜你在 {draw_count}次 {draw_name}抽奖 中抽到了:\n\n" + lines = [] + for _ in range(name_max_len + 2): + lines.append('') + + begin_line = 0 + + one_line_length = 0 + + for win_name, win_points, win_symbol in wins: + if one_line_length >= 10: + begin_line += name_max_len + 2 + for _ in range(name_max_len + 2): + lines.append('') + one_line_length = 0 + + lines[begin_line] += win_symbol + for i in range(begin_line + 1, begin_line + name_max_len + 1): + if i % (name_max_len + 2) <= len(win_name): + lines[i] += "\u2004" + win_name[i % (name_max_len + 2) - 1] + else: + lines[i] += win_symbol + lines[begin_line + name_max_len + 1] += win_symbol + + one_line_length += 1 + + message = '' + message += begin_message + for line in lines: + message += line + '\n' + + message += f"\n\n🎉总计赢取积分: {total_win_points}🎉\n🎉共计消耗积分:{draw_cost}🎉\n\n概率请自行查询菜单⚙️" + + return message diff --git a/plugins/lucky_draw.yml b/plugins/lucky_draw.yml index d809243..48c64f7 100644 --- a/plugins/lucky_draw.yml +++ b/plugins/lucky_draw.yml @@ -1,23 +1,26 @@ keywords: [ "抽奖","积分抽奖" ] plugin_name: "lucky_draw" +max_draw: 100 + lucky_draw_probability: { - "小": { "cost": 20, "probability": { "0.05": { "name": "头等奖","points": 40 }, - "0.1": { "name": "二等奖","points": 30 }, - "0.2": { "name": "三等奖","points": 20 }, - "0.3": { "name": "四等奖","points": 15 }, - "0.35": { "name": "参与奖","points": 10 } } + "小": { "cost": 20, "probability": { "0.05": { "name": "金","points": 80, "symbol": "🟨" }, + "0.1": { "name": "紫","points": 55, "symbol": "🟪" }, + "0.2": { "name": "蓝","points": 35, "symbol": "🟦" }, + "0.3": { "name": "绿","points": 15, "symbol": "🟩" }, + "0.35": { "name": "白","points": 10, "symbol": "⬜️" } } }, - "中": { "cost": 40, "probability": { "0.05": { "name": "头等奖","points": 70 }, - "0.1": { "name": "二等奖","points": 50 }, - "0.2": { "name": "三等奖","points": 40 }, - "0.3": { "name": "四等奖","points": 30 }, - "0.35": { "name": "参与奖","points": 25 } } + "中": { "cost": 40, "probability": { "0.05": { "name": "金","points": 100, "symbol": "🟨" }, + "0.1": { "name": "紫","points": 80, "symbol": "🟪" }, + "0.2": { "name": "蓝","points": 55, "symbol": "🟦" }, + "0.3": { "name": "绿","points": 35, "symbol": "🟩" }, + "0.35": { "name": "白","points": 25, "symbol": "⬜️" } } }, - "大": { "cost": 80, "probability": { "0.05": { "name": "头等奖","points": 130 }, - "0.1": { "name": "二等奖","points": 100 }, - "0.2": { "name": "三等奖","points": 80 }, - "0.3": { "name": "四等奖","points": 70 }, - "0.35": { "name": "参与奖","points": 60 } } + "大": { "cost": 80, "probability": { "0.01": { "name": "红", "points": 300, "symbol": "🟥" }, + "0.05": { "name": "金","points": 200, "symbol": "🟨" }, + "0.1": { "name": "紫","points": 100, "symbol": "🟪" }, + "0.2": { "name": "蓝","points": 80, "symbol": "🟦" }, + "0.3": { "name": "绿","points": 70, "symbol": "🟩" }, + "0.34": { "name": "白","points": 60, "symbol": "⬜️" } } } } \ No newline at end of file diff --git a/plugins/menu.yml b/plugins/menu.yml index 8dcd3ca..ad7dc10 100644 --- a/plugins/menu.yml +++ b/plugins/menu.yml @@ -14,6 +14,6 @@ menus: { "1.1": "-----XYBot菜单------\n1.1: 获取最新实时天气🌧️\n "3.2": "-----XYBot菜单------\n3.2: 查询自己的积分!\n指令:/查询积分", "3.3": "-----XYBot菜单------\n3.3: 查看积分排行榜!\n指令:/积分榜", "3.4": "-----XYBot菜单------\n3.4: 转送积分给其他人!👍🏻\n指令:/积分转账 @(群成员) (积分数量)\n如:/积分转账 50 @XYBot\n注意!⚠️只能转给群内成员\n并且\n该成员的昵称不可与其他人重复,以免发生冲突", - "3.5": "-----XYBot菜单------\n3.5: 使用积分抽奖,赚取积分💰\n指令:/抽奖 (抽奖名)\n\n有三种抽奖,概率如下\n\n小 ❗️需要20点积分❗️ 指令:/抽奖 小\n🤑头等奖:概率为5%,奖励为60点积分\n🤑二等奖:概率为10%,奖励为30点积分\n🤑三等奖:概率为20%,奖励为20点积分\n🤑四等奖:概率为30%,奖励为15点积分\n🤑参与奖:概率为35%,奖励为10点积分\n\n中 ❗️需要40点积分❗️ 指令:/抽奖 中\n🤑头等奖:概率为5%,奖励为80点积分\n🤑二等奖:概率为10%,奖励为50点积分\n🤑三等奖:概率为20%,奖励为40点积分\n🤑四等奖:概率为30%,奖励为30点积分\n🤑参与奖:概率为35%,奖励为25点积分\n\n大 ❗️需要80点积分❗️ 指令:/抽奖 大\n🤑史上最NB头等奖:概率为1%,奖励为300点积分\n🤑头等奖:概率为5%,奖励为150点积分\n🤑二等奖:概率为10%,奖励为100点积分\n🤑三等奖:概率为20%,奖励为80点积分\n🤑四等奖:概率为28%,奖励为70点积分\n🤑参与奖:概率为35%,奖励为60点积分", + "3.5": "-----XYBot菜单------\n3.5: 使用积分抽奖,赚取积分💰\n单抽指令:/抽奖 (抽奖名)\n连抽:/抽奖 (抽奖名) (次数)\n\n有三种抽奖,概率如下\n\n小 ❗️需要20点积分❗\n指令:/抽奖 小 (次数)\n🟨金🟨 5% 80积分\n🟪紫🟪 10% 55积分\n🟦蓝🟦 20% 35积分\n🟩绿🟩 30% 15积分\n⬜️白⬜️ 35% 10积分\n\n中 ❗️需要40点积分❗️\n指令:/抽奖 中 (次数)\n🟨金🟨 5% 100积分\n🟪紫🟪 10% 80积分\n🟦蓝🟦 20% 55积分\n🟩绿🟩 30% 35积分\n⬜️白⬜️ 35% 25积分\n\n大 ❗️需要80点积分❗️\n指令:/抽奖 大 (次数)\n🟥红🟥 1% 300积分\n🟨金🟨 5% 200积分\n🟪紫🟪 10% 100积分\n🟦蓝🟦 20% 80积分\n🟩绿🟩 30% 70积分\n⬜️白⬜️ 34% 60积分\n\n保底:只有连抽有保底,每10抽必出🟦及以上的奖项\n", "3.6": "-----XYBot菜单------\n3.6: 积分红包!🧧\n\n⚙️发红包指令:/发红包 (积分数) (红包数)\n\n⚙️抢红包指令:/抢红包 (验证码)", "4.1": "-----XYBot菜单------\n4.1: 管理员功能:\n\n无管理员也可以用的指令:\n检查机器人状态\n指令:/机器人状态\n\n必须有管理员才可使用下列指令\nwxid可用获取群成员列表功能获取\n\n管理积分:\n指令:/管理积分 (wxid) (加/减) (积分数)\n如: /管理积分 wxid_12345678 加 10\n /管理积分 wxid_12345678 减 10\n\n管理白名单:\n有白名单者使用ChatGPT不扣积分\n指令: /管理白名单 (wxid) (加入/删除)\n如: /管理白名单 wxid_12345678 加入\n/管理白名单 wxid_12345678 删除\n\n重置签到冷却:\n指令: /重置签到状态\n无参数\n\n获取机器人通讯录功能:\n指令: /获取机器人通讯录\n无参数\n\n获取群成员列表功能:\n指令: /获取群成员列表\n无参数\n\n查看已加载插件列表:\n指令:/管理插件 列表\n\n热加载/卸载/重载插件\n指令:/管理插件 (操作名) (插件名)\n例如:/管理插件 重载 lucky_draw" } diff --git a/plugins/random_picture.py b/plugins/random_picture.py index ced75b5..ee555ef 100644 --- a/plugins/random_picture.py +++ b/plugins/random_picture.py @@ -32,8 +32,6 @@ def __init__(self): self.port = main_config['port'] self.bot = pywxdll.Pywxdll(self.ip, self.port) # 机器人api - self.max_thread = main_config['max_thread'] - def run(self, recv): current_directory = os.path.dirname(os.path.abspath(__file__)) diff --git a/requirements.txt b/requirements.txt index fde40a6..c0b6f1c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,5 @@ openai==0.28.0 requests==2.31.0 captcha==0.5.0 beautifulsoup4==4.12.2 -prettytable==3.9.0 \ No newline at end of file +prettytable==3.9.0 +websockets==12.0 \ No newline at end of file diff --git a/singleton.py b/singleton.py new file mode 100644 index 0000000..a91faab --- /dev/null +++ b/singleton.py @@ -0,0 +1,14 @@ +# Copyright (c) 2024. Henry Yang +# +# This program is licensed under the GNU General Public License v3.0. +# +# This program is licensed under the GNU General Public License v3.0. +def singleton(cls): + _instance = {} + + def inner(): + if cls not in _instance: + _instance[cls] = cls() + return _instance[cls] + + return inner diff --git a/start.py b/start.py index f549048..5bb0643 100644 --- a/start.py +++ b/start.py @@ -3,14 +3,15 @@ # This program is licensed under the GNU General Public License v3.0. # # This program is licensed under the GNU General Public License v3.0. - +import asyncio +import concurrent.futures +import json import os -import threading import time -from concurrent.futures import ThreadPoolExecutor import pywxdll import schedule +import websockets import yaml from loguru import logger @@ -19,28 +20,26 @@ from plugin_manager import plugin_manager -def message_handler(recv): # 处理收到的消息 - handlebot = xybot.XYBot() +async def message_handler(recv, handlebot): # 处理收到的消息 handlebot.message_handler(recv) -def threadpool_callback(worker): # 处理线程结束时,有无错误 +def callback(worker): # 处理线程结束时,有无错误 worker_exception = worker.exception() if worker_exception: logger.error(worker_exception) -def schedule_run_pending(): # 计划等待判定线程 - # schedule.run_all() +async def plan_run_pending(): # 计划等待判定线程 while True: schedule.run_pending() - time.sleep(1) + await asyncio.sleep(1) -if __name__ == "__main__": +async def main(): os.chdir(os.path.dirname(os.path.abspath(__file__))) - ###### log设置 读取设置 ###### + # ---- log设置 读取设置 ---- # logger.add('logs/log_{time}.log', encoding='utf-8', enqueue=True, retention='2 weeks', rotation='00:01') # 日志设置 pic_cache_path = 'resources/pic_cache' # 检测是否有pic_cache文件夹 @@ -55,9 +54,9 @@ def schedule_run_pending(): # 计划等待判定线程 ip = config['ip'] port = config['port'] - max_thread = config['max_thread'] + max_worker = config['max_worker'] - ###### 机器人实例化 登陆监测 机器人启动 ###### + # ---- 机器人实例化 登陆监测 机器人启动 ---- # bot = pywxdll.Pywxdll(ip, port) @@ -74,7 +73,9 @@ def schedule_run_pending(): # 计划等待判定线程 bot.start() # 开启机器人 - ###### 加载插件 加载计划 ###### + handlebot = xybot.XYBot() + + # ---- 加载插件 加载计划 ---- # # 加载所有插件 plugin_dir = "plugins" # 插件目录的路径 @@ -83,23 +84,23 @@ def schedule_run_pending(): # 计划等待判定线程 plans_dir = "plans" plan_manager.load_plans(plans_dir) # 加载所有计划 - ###### 线程池创建 计划等待判定线程创建与启动 ###### + asyncio.create_task(plan_run_pending()).add_done_callback(callback) # 开启计划等待判定线程 - pool = ThreadPoolExecutor(max_workers=max_thread, thread_name_prefix='xybot') # 创建线程池 + # ---- 进入获取聊天信息并处理循环 ---- # + async with websockets.connect('ws://{ip}:{port}'.format(ip=ip, port=port)) as websocket: + logger.success('机器人启动成功!') + with concurrent.futures.ThreadPoolExecutor(max_workers=max_worker): + while True: + try: + recv = json.loads(await websocket.recv()) + r_type = recv['type'] + if r_type == 1 or r_type == 3 or r_type == 49: + logger.info('[收到消息]:{message}'.format(message=recv)) + if isinstance(recv['content'], str): # 判断是否为txt消息 + asyncio.create_task(message_handler(recv, handlebot)).add_done_callback(callback) + except Exception as error: + logger.error('出现错误: {error}'.format(error=error)) - run_pending_thread = threading.Thread(target=schedule_run_pending) - run_pending_thread.start() - ####### 进入获取聊天信息并处理循环 ###### - - logger.success('机器人启动成功!') - while True: - try: - if bot.msg_list: # 如果有聊天信息 - recv = bot.msg_list.pop(0) # 获取信息列表第一项并pop - logger.info('[收到消息]:{message}'.format(message=recv)) - if isinstance(recv['content'], str): # 判断是否为txt消息 - pool.submit(message_handler, recv).add_done_callback(threadpool_callback) # 向线程池提交任务 - except Exception as error: - logger.error('出现错误: {error}'.format(error=error)) - time.sleep(3) +if __name__ == "__main__": + asyncio.run(main())