重构插件传入 service 方式

* 重构插件传入 `service` 方式

重构插件传入 `service` 方式
将 `create_handlers`函数的修饰符改为 `classmethod`
This commit is contained in:
洛水.山岭居室 2022-07-07 09:36:34 +08:00 committed by GitHub
parent f21ebc51a1
commit 693cd774d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 202 additions and 179 deletions

View File

@ -7,7 +7,6 @@ from manager import PluginsManager
from plugins.auth import Auth from plugins.auth import Auth
from plugins.base import NewChatMembersHandler from plugins.base import NewChatMembersHandler
from plugins.errorhandler import error_handler from plugins.errorhandler import error_handler
from plugins.help import Help
from plugins.inline import Inline from plugins.inline import Inline
from plugins.start import start, ping, reply_keyboard_remove, unknown_command from plugins.start import start, ping, reply_keyboard_remove, unknown_command
from service import BaseService from service import BaseService
@ -39,20 +38,18 @@ def register_handlers(application: Application, service: BaseService):
plugins_manager.refresh_list("./plugins/*") plugins_manager.refresh_list("./plugins/*")
# 忽略内置模块 # 忽略内置模块
plugins_manager.add_exclude(["help", "start", "base", "auth", "inline", "errorhandler"]) plugins_manager.add_exclude(["start", "base", "auth", "inline", "errorhandler"])
Log.info("加载插件管理器正在加载插件") Log.info("加载插件管理器正在加载插件")
plugins_manager.import_module() plugins_manager.import_module()
plugins_manager.add_handler(application, (service,)) plugins_manager.add_handler(application, service)
Log.info("正在加载内置插件") Log.info("正在加载内置插件")
plugins_help = Help()
inline = Inline(service) inline = Inline(service)
auth = Auth(service) auth = Auth(service)
add_handler(start, command="start") add_handler(start, command="start")
add_handler(plugins_help.command_start, command="help")
add_handler(ping, command="ping") add_handler(ping, command="ping")
add_handler(auth.query, query=r"^auth_challenge\|") add_handler(auth.query, query=r"^auth_challenge\|")
add_handler(auth.admin, query=r"^auth_admin\|") add_handler(auth.admin, query=r"^auth_admin\|")

View File

@ -2,20 +2,29 @@ import os
from glob import glob from glob import glob
from importlib import import_module from importlib import import_module
from os import path from os import path
from typing import List, Union from typing import List, Union, Tuple, Callable
from telegram.ext import Application from telegram.ext import Application
from logger import Log from logger import Log
from plugins.base import BasePlugins from service import BaseService
PluginsClass: List[BasePlugins] = [] PluginsClass: List[Tuple[any, dict]] = []
def listener_plugins_class(): def listener_plugins_class(need_service: bool = False):
def decorator(func: BasePlugins): """监听插件
:param need_service: 插件类中 create_handlers 函数是否传入 service
:return: None
"""
plugin_info = {
"need_service": need_service
}
def decorator(func: Callable):
PluginsClass.append( PluginsClass.append(
func (func, plugin_info)
) )
return func return func
@ -61,12 +70,17 @@ class PluginsManager:
Log.debug(f"插件 {plugin_name} 加载成功") Log.debug(f"插件 {plugin_name} 加载成功")
@staticmethod @staticmethod
def add_handler(application: Application, args=None): def add_handler(application: Application, service: BaseService):
for pc in PluginsClass: for pc in PluginsClass:
if callable(pc): func = pc[0]
plugin_info = pc[1]
# 构建 kwargs
kwargs = {}
if plugin_info.get("need_service", False):
kwargs["service"] = service
if callable(func):
try: try:
ist: BasePlugins = pc(*args) handlers_list = func.create_handlers(**kwargs)
handlers_list = ist.create_handlers(*args)
for handler in handlers_list: for handler in handlers_list:
application.add_handler(handler) application.add_handler(handler)
except AttributeError as exc: except AttributeError as exc:

View File

@ -12,23 +12,23 @@
``` python ``` python
from telegram import Update from telegram import Update
from telegram.ext import CallbackContext
from manager import listener_plugins_class from manager import listener_plugins_class
from plugins.base import BasePlugins, restricts from plugins.base import BasePlugins, restricts
from plugins.errorhandler import conversation_error_handler from plugins.errorhandler import conversation_error_handler
from utils.base import PaimonContext
@listener_plugins_class() @listener_plugins_class()
class Example(BasePlugins): class Example(BasePlugins):
@staticmethod @classmethod
def create_handlers(service: BaseService): def create_handlers(cls):
example = Example(service) example = cls()
return [CommandHandler('example', example.command_start)] return [CommandHandler('example', example.command_start)]
@conversation_error_handler @conversation_error_handler
@restricts() @restricts()
async def command_start(self, update: Update, context: CallbackContext) -> None: async def command_start(self, update: Update, context: PaimonContext) -> None:
await message.reply_text("Example") await message.reply_text("Example")
``` ```
@ -51,3 +51,4 @@ plugins 模块下的类必须提供 `create_handlers` 静态函数作为构建
**注意:`@restricts()` 修饰器带参,必须带括号,否则会出现调用错误** **注意:`@restricts()` 修饰器带参,必须带括号,否则会出现调用错误**
如果 `service` 需要全局共用,可以参考 `daily_note.py` 代码

View File

@ -13,14 +13,9 @@ from utils.base import PaimonContext
@listener_plugins_class() @listener_plugins_class()
class Abyss(BasePlugins): class Abyss(BasePlugins):
def __init__(self, *args): @classmethod
"""Abyss插件入口""" def create_handlers(cls) -> list:
pass abyss = cls()
@staticmethod
def create_handlers(*args) -> list:
_ = args
abyss = Abyss()
return [ return [
CommandHandler("abyss", abyss.command_start, block=False), CommandHandler("abyss", abyss.command_start, block=False),
MessageHandler(filters.Regex(r"^深渊数据查询(.*)"), abyss.command_start, block=True) MessageHandler(filters.Regex(r"^深渊数据查询(.*)"), abyss.command_start, block=True)

View File

@ -6,13 +6,13 @@ from telegram.ext import CallbackContext, CommandHandler
from logger import Log from logger import Log
from manager import listener_plugins_class from manager import listener_plugins_class
from plugins.base import BasePlugins from utils.base import PaimonContext
from service import BaseService
def bot_admins_only(func: Callable) -> Callable: # noqa def bot_admins_only(func: Callable) -> Callable: # noqa
async def decorator(self, update: Update, context: CallbackContext): async def decorator(self, update: Update, context: PaimonContext):
admin_list = await self.service.admin.get_admin_list() service = context.service
admin_list = await service.admin.get_admin_list()
if update.message.from_user.id in admin_list: if update.message.from_user.id in admin_list:
return await func(self, update, context) return await func(self, update, context)
else: else:
@ -23,14 +23,13 @@ def bot_admins_only(func: Callable) -> Callable: # noqa
@listener_plugins_class() @listener_plugins_class()
class Admin(BasePlugins): class Admin:
""" """有关BOT ADMIN处理
有关BOT ADMIN处理
""" """
@staticmethod @classmethod
def create_handlers(service: BaseService) -> list: def create_handlers(cls) -> list:
admin = Admin(service) admin = cls()
return [ return [
CommandHandler("add_admin", admin.add_admin, block=False), CommandHandler("add_admin", admin.add_admin, block=False),
CommandHandler("del_admin", admin.del_admin, block=False), CommandHandler("del_admin", admin.del_admin, block=False),
@ -38,29 +37,31 @@ class Admin(BasePlugins):
] ]
@bot_admins_only @bot_admins_only
async def add_admin(self, update: Update, _: CallbackContext): async def add_admin(self, update: Update, context: PaimonContext):
message = update.message message = update.message
reply_to_message = message.reply_to_message reply_to_message = message.reply_to_message
admin_list = await self.service.admin.get_admin_list() service = context.service
admin_list = await service.admin.get_admin_list()
if reply_to_message is None: if reply_to_message is None:
await message.reply_text("请回复对应消息") await message.reply_text("请回复对应消息")
else: else:
if reply_to_message.from_user.id in admin_list: if reply_to_message.from_user.id in admin_list:
await message.reply_text("该用户已经存在管理员列表") await message.reply_text("该用户已经存在管理员列表")
else: else:
await self.service.admin.add_admin(reply_to_message.from_user.id) await service.admin.add_admin(reply_to_message.from_user.id)
await message.reply_text("添加成功") await message.reply_text("添加成功")
@bot_admins_only @bot_admins_only
async def del_admin(self, update: Update, _: CallbackContext): async def del_admin(self, update: Update, context: PaimonContext):
message = update.message message = update.message
reply_to_message = message.reply_to_message reply_to_message = message.reply_to_message
admin_list = await self.service.admin.get_admin_list() service = context.service
admin_list = await service.admin.get_admin_list()
if reply_to_message is None: if reply_to_message is None:
await message.reply_text("请回复对应消息") await message.reply_text("请回复对应消息")
else: else:
if reply_to_message.from_user.id in admin_list: if reply_to_message.from_user.id in admin_list:
await self.service.admin.delete_admin(reply_to_message.from_user.id) await service.admin.delete_admin(reply_to_message.from_user.id)
await message.reply_text("删除成功") await message.reply_text("删除成功")
else: else:
await message.reply_text("该用户不存在管理员列表") await message.reply_text("该用户不存在管理员列表")

View File

@ -9,9 +9,8 @@ from telegram.helpers import escape_markdown
from logger import Log from logger import Log
from manager import listener_plugins_class from manager import listener_plugins_class
from model.apihelper.artifact import ArtifactOcrRate, get_comment, get_format_sub_item from model.apihelper.artifact import ArtifactOcrRate, get_comment, get_format_sub_item
from plugins.base import BasePlugins, restricts from plugins.base import restricts, BasePlugins
from plugins.errorhandler import conversation_error_handler from plugins.errorhandler import conversation_error_handler
from service import BaseService
@listener_plugins_class() @listener_plugins_class()
@ -31,13 +30,12 @@ class ArtifactRate(BasePlugins):
f"{i * 5 + j}", callback_data=f"artifact_ocr_rate_data|level|{i * 5 + j}") for j in range(1, 6) f"{i * 5 + j}", callback_data=f"artifact_ocr_rate_data|level|{i * 5 + j}") for j in range(1, 6)
] for i in range(0, 4)] ] for i in range(0, 4)]
def __init__(self, service: BaseService): def __init__(self):
super().__init__(service)
self.artifact_rate = ArtifactOcrRate() self.artifact_rate = ArtifactOcrRate()
@staticmethod @classmethod
def create_handlers(service: BaseService) -> list: def create_handlers(cls) -> list:
artifact_rate = ArtifactRate(service) artifact_rate = cls()
return [ return [
ConversationHandler( ConversationHandler(
entry_points=[CommandHandler('artifact_rate', artifact_rate.command_start), entry_points=[CommandHandler('artifact_rate', artifact_rate.command_start),

View File

@ -11,8 +11,8 @@ from telegram.helpers import escape_markdown
from logger import Log from logger import Log
from model.helpers import get_admin_list from model.helpers import get_admin_list
from utils.random import MT19937_Random
from service import BaseService from service import BaseService
from utils.random import MT19937_Random
FullChatPermissions = ChatPermissions( FullChatPermissions = ChatPermissions(
can_send_messages=True, can_send_messages=True,

View File

@ -4,7 +4,6 @@ from functools import wraps
from typing import Callable, Optional from typing import Callable, Optional
from telegram import Update, ReplyKeyboardRemove from telegram import Update, ReplyKeyboardRemove
from telegram.constants import ChatType
from telegram.error import BadRequest from telegram.error import BadRequest
from telegram.ext import CallbackContext, ConversationHandler, filters from telegram.ext import CallbackContext, ConversationHandler, filters
@ -37,8 +36,6 @@ def add_delete_message_job(context: CallbackContext, chat_id: int, message_id: i
class BasePlugins: class BasePlugins:
def __init__(self, service: BaseService):
self.service = service
@staticmethod @staticmethod
async def cancel(update: Update, _: CallbackContext) -> int: async def cancel(update: Update, _: CallbackContext) -> int:
@ -88,22 +85,28 @@ class NewChatMembersHandler:
def restricts(filters_chat: filters = filters.ALL, return_data=None, try_delete_message: bool = False, def restricts(filters_chat: filters = filters.ALL, return_data=None, try_delete_message: bool = False,
restricts_time: int = 5): restricts_time: int = 5):
""" """用于装饰在指定函数防止洪水调用的装饰器
用于装饰在指定函数防止洪水调用的装饰器
被修饰的函数传入参数必须为 被修饰的函数生声明必须为
async def command_func(update, context)
async def command_func(self, update, context)
如果修饰的函数属于 async def command_func(update, context)
ConversationHandler
参数 async def command_func(self, update, context
return_data
必须传入
ConversationHandler.END
我真是服了某些闲着没事干的群友了 如果修饰的函数属于
ConversationHandler
参数
return_data
必须传入
ConversationHandler.END
我真是服了某些闲着没事干的群友了
:param filters_chat: 要限制的群
:param return_data:
:param try_delete_message:
:param restricts_time:
:return: return_data
""" """
def decorator(func: Callable): def decorator(func: Callable):

View File

@ -1,6 +1,4 @@
from http.cookies import SimpleCookie, CookieError from http.cookies import SimpleCookie, CookieError
from typing import List
from urllib.request import BaseHandler
import genshin import genshin
import ujson import ujson
@ -12,10 +10,10 @@ from telegram.helpers import escape_markdown
from logger import Log from logger import Log
from manager import listener_plugins_class from manager import listener_plugins_class
from model.base import ServiceEnum from model.base import ServiceEnum
from plugins.base import BasePlugins, restricts from plugins.base import restricts, BasePlugins
from plugins.errorhandler import conversation_error_handler from plugins.errorhandler import conversation_error_handler
from service import BaseService
from service.base import UserInfoData from service.base import UserInfoData
from utils.base import PaimonContext
class CookiesCommandData: class CookiesCommandData:
@ -33,9 +31,9 @@ class Cookies(BasePlugins):
CHECK_SERVER, CHECK_COOKIES, COMMAND_RESULT = range(10100, 10103) CHECK_SERVER, CHECK_COOKIES, COMMAND_RESULT = range(10100, 10103)
@staticmethod @classmethod
def create_handlers(service: BaseService): def create_handlers(cls):
cookies = Cookies(service) cookies = cls()
cookies_handler = ConversationHandler( cookies_handler = ConversationHandler(
entry_points=[CommandHandler('adduser', cookies.command_start, filters.ChatType.PRIVATE, block=True), entry_points=[CommandHandler('adduser', cookies.command_start, filters.ChatType.PRIVATE, block=True),
MessageHandler(filters.Regex(r"^绑定账号(.*)") & filters.ChatType.PRIVATE, MessageHandler(filters.Regex(r"^绑定账号(.*)") & filters.ChatType.PRIVATE,
@ -70,10 +68,11 @@ class Cookies(BasePlugins):
@conversation_error_handler @conversation_error_handler
@restricts(return_data=ConversationHandler.END) @restricts(return_data=ConversationHandler.END)
async def check_server(self, update: Update, context: CallbackContext) -> int: async def check_server(self, update: Update, context: PaimonContext) -> int:
user = update.effective_user user = update.effective_user
service = context.service
cookies_command_data: CookiesCommandData = context.chat_data.get("cookies_command_data") cookies_command_data: CookiesCommandData = context.chat_data.get("cookies_command_data")
user_info = await self.service.user_service_db.get_user_info(user.id) user_info = await service.user_service_db.get_user_info(user.id)
cookies_command_data.user_info = user_info cookies_command_data.user_info = user_info
if update.message.text == "退出": if update.message.text == "退出":
await update.message.reply_text("退出任务", reply_markup=ReplyKeyboardRemove()) await update.message.reply_text("退出任务", reply_markup=ReplyKeyboardRemove())
@ -175,8 +174,9 @@ class Cookies(BasePlugins):
return self.COMMAND_RESULT return self.COMMAND_RESULT
@conversation_error_handler @conversation_error_handler
async def command_result(self, update: Update, context: CallbackContext) -> int: async def command_result(self, update: Update, context: PaimonContext) -> int:
user = update.effective_user user = update.effective_user
service = context.service
cookies_command_data: CookiesCommandData = context.chat_data.get("cookies_command_data") cookies_command_data: CookiesCommandData = context.chat_data.get("cookies_command_data")
if update.message.text == "退出": if update.message.text == "退出":
await update.message.reply_text("退出任务", reply_markup=ReplyKeyboardRemove()) await update.message.reply_text("退出任务", reply_markup=ReplyKeyboardRemove())
@ -184,17 +184,17 @@ class Cookies(BasePlugins):
elif update.message.text == "确认": elif update.message.text == "确认":
data = ujson.dumps(cookies_command_data.cookies) data = ujson.dumps(cookies_command_data.cookies)
user_info = cookies_command_data.user_info user_info = cookies_command_data.user_info
service = ServiceEnum.NULL.value game_service = ServiceEnum.NULL.value
if cookies_command_data.service == ServiceEnum.HYPERION: if cookies_command_data.service == ServiceEnum.HYPERION:
user_info.mihoyo_game_uid = cookies_command_data.game_uid user_info.mihoyo_game_uid = cookies_command_data.game_uid
service = ServiceEnum.HYPERION.value game_service = ServiceEnum.HYPERION.value
elif cookies_command_data.service == ServiceEnum.HOYOLAB: elif cookies_command_data.service == ServiceEnum.HOYOLAB:
user_info.hoyoverse_game_uid = cookies_command_data.game_uid user_info.hoyoverse_game_uid = cookies_command_data.game_uid
service = ServiceEnum.HOYOLAB.value game_service = ServiceEnum.HOYOLAB.value
await self.service.user_service_db.set_user_info(user.id, user_info.mihoyo_game_uid, await service.user_service_db.set_user_info(user.id, user_info.mihoyo_game_uid,
user_info.hoyoverse_game_uid, user_info.hoyoverse_game_uid,
service) game_service)
await self.service.user_service_db.set_cookie(user.id, data, cookies_command_data.service) await service.user_service_db.set_cookie(user.id, data, cookies_command_data.service)
Log.info(f"用户 {user.full_name}[{user.id}] 绑定账号成功") Log.info(f"用户 {user.full_name}[{user.id}] 绑定账号成功")
await update.message.reply_text("保存成功", reply_markup=ReplyKeyboardRemove()) await update.message.reply_text("保存成功", reply_markup=ReplyKeyboardRemove())
return ConversationHandler.END return ConversationHandler.END

View File

@ -5,8 +5,8 @@ import genshin
from genshin import GenshinException, DataNotPublic from genshin import GenshinException, DataNotPublic
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.constants import ChatAction from telegram.constants import ChatAction
from telegram.ext import CallbackContext, CommandHandler, MessageHandler, ConversationHandler, filters, \ from telegram.ext import CommandHandler, MessageHandler, ConversationHandler, filters, \
CallbackQueryHandler CallbackQueryHandler, CallbackContext
from logger import Log from logger import Log
from manager import listener_plugins_class from manager import listener_plugins_class
@ -21,7 +21,7 @@ class UidCommandData:
user_info: UserInfoData = UserInfoData() user_info: UserInfoData = UserInfoData()
@listener_plugins_class() @listener_plugins_class(need_service=True)
class DailyNote(BasePlugins): class DailyNote(BasePlugins):
""" """
每日便签 每日便签
@ -30,12 +30,12 @@ class DailyNote(BasePlugins):
COMMAND_RESULT, = range(10200, 10201) COMMAND_RESULT, = range(10200, 10201)
def __init__(self, service: BaseService): def __init__(self, service: BaseService):
super().__init__(service) self.service = service
self.current_dir = os.getcwd() self.current_dir = os.getcwd()
@staticmethod @classmethod
def create_handlers(service: BaseService) -> list: def create_handlers(cls, service: BaseService) -> list:
daily_note = DailyNote(service) daily_note = cls(service)
daily_note_handler = ConversationHandler( daily_note_handler = ConversationHandler(
entry_points=[CommandHandler('dailynote', daily_note.command_start, block=True), entry_points=[CommandHandler('dailynote', daily_note.command_start, block=True),
MessageHandler(filters.Regex(r"^当前状态(.*)"), daily_note.command_start, block=True)], MessageHandler(filters.Regex(r"^当前状态(.*)"), daily_note.command_start, block=True)],
@ -46,8 +46,8 @@ class DailyNote(BasePlugins):
) )
return [daily_note_handler] return [daily_note_handler]
async def _start_get_daily_note(self, user_info_data: UserInfoData, service: ServiceEnum) -> bytes: async def _get_daily_note_data(self, user_info_data: UserInfoData, game_service: ServiceEnum) -> bytes:
if service == ServiceEnum.HYPERION: if game_service == ServiceEnum.HYPERION:
client = genshin.ChineseClient(cookies=user_info_data.mihoyo_cookie) client = genshin.ChineseClient(cookies=user_info_data.mihoyo_cookie)
uid = user_info_data.mihoyo_game_uid uid = user_info_data.mihoyo_game_uid
else: else:

View File

@ -3,14 +3,14 @@ import os
from pyppeteer import launch from pyppeteer import launch
from telegram import Update from telegram import Update
from telegram.constants import ChatAction from telegram.constants import ChatAction
from telegram.ext import CallbackContext, ConversationHandler, filters, CommandHandler, MessageHandler from telegram.ext import ConversationHandler, filters, CommandHandler, MessageHandler
from logger import Log from logger import Log
from manager import listener_plugins_class from manager import listener_plugins_class
from plugins.base import BasePlugins, restricts from plugins.base import BasePlugins, restricts
from plugins.errorhandler import conversation_error_handler from plugins.errorhandler import conversation_error_handler
from service import BaseService
from service.wish import WishCountInfo, get_one from service.wish import WishCountInfo, get_one
from utils.base import PaimonContext
@listener_plugins_class() @listener_plugins_class()
@ -19,17 +19,16 @@ class Gacha(BasePlugins):
抽卡模拟器非首模拟器/减寿模拟器 抽卡模拟器非首模拟器/减寿模拟器
""" """
@staticmethod @classmethod
def create_handlers(service: BaseService) -> list: def create_handlers(cls) -> list:
gacha = Gacha(service) gacha = cls()
return [ return [
CommandHandler("gacha", gacha.command_start, block=False), CommandHandler("gacha", gacha.command_start, block=False),
MessageHandler(filters.Regex("^抽卡模拟器(.*)"), gacha.command_start, block=False), MessageHandler(filters.Regex("^抽卡模拟器(.*)"), gacha.command_start, block=False),
MessageHandler(filters.Regex("^非首模拟器(.*)"), gacha.command_start, block=False), MessageHandler(filters.Regex("^非首模拟器(.*)"), gacha.command_start, block=False),
] ]
def __init__(self, service: BaseService): def __init__(self):
super().__init__(service)
self.browser: launch = None self.browser: launch = None
self.current_dir = os.getcwd() self.current_dir = os.getcwd()
self.resources_dir = os.path.join(self.current_dir, "resources") self.resources_dir = os.path.join(self.current_dir, "resources")
@ -41,11 +40,12 @@ class Gacha(BasePlugins):
@conversation_error_handler @conversation_error_handler
@restricts(filters.ChatType.GROUPS, restricts_time=20, try_delete_message=True) @restricts(filters.ChatType.GROUPS, restricts_time=20, try_delete_message=True)
@restricts(filters.ChatType.PRIVATE) @restricts(filters.ChatType.PRIVATE)
async def command_start(self, update: Update, context: CallbackContext) -> None: async def command_start(self, update: Update, context: PaimonContext) -> None:
message = update.message message = update.message
user = update.effective_user user = update.effective_user
args = context.args args = context.args
match = context.match match = context.match
service = context.service
gacha_name = "角色活动" gacha_name = "角色活动"
if args is None: if args is None:
if match is not None: if match is not None:
@ -64,7 +64,7 @@ class Gacha(BasePlugins):
await message.reply_text(f"没有找到名为 {gacha_name} 的卡池") await message.reply_text(f"没有找到名为 {gacha_name} 的卡池")
return ConversationHandler.END return ConversationHandler.END
Log.info(f"用户 {user.full_name}[{user.id}] 抽卡模拟器命令请求 || 参数 {gacha_name}") Log.info(f"用户 {user.full_name}[{user.id}] 抽卡模拟器命令请求 || 参数 {gacha_name}")
gacha_info = await self.service.gacha.gacha_info(gacha_name) gacha_info = await service.gacha.gacha_info(gacha_name)
# 用户数据储存和处理 # 用户数据储存和处理
if gacha_info.get("gacha_id") is None: if gacha_info.get("gacha_id") is None:
await message.reply_text(f"没有找到名为 {gacha_name} 的卡池") await message.reply_text(f"没有找到名为 {gacha_name} 的卡池")
@ -104,8 +104,8 @@ class Gacha(BasePlugins):
data["items"].sort(key=take_rang, reverse=True) data["items"].sort(key=take_rang, reverse=True)
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO) await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
# 因为 gacha_info["title"] 返回的是 HTML 标签 尝试关闭自动转义 # 因为 gacha_info["title"] 返回的是 HTML 标签 尝试关闭自动转义
png_data = await self.service.template.render('genshin/gacha', "gacha.html", data, png_data = await service.template.render('genshin/gacha', "gacha.html", data,
{"width": 1157, "height": 603}, False, False) {"width": 1157, "height": 603}, False, False)
reply_message = await message.reply_photo(png_data) reply_message = await message.reply_photo(png_data)
if filters.ChatType.GROUPS.filter(message): if filters.ChatType.GROUPS.filter(message):

View File

@ -1,13 +1,16 @@
from telegram import Update from telegram import Update
from telegram.constants import ChatAction from telegram.constants import ChatAction
from telegram.error import BadRequest from telegram.error import BadRequest
from telegram.ext import CommandHandler
from config import config from config import config
from logger import Log from logger import Log
from manager import listener_plugins_class
from plugins.base import restricts from plugins.base import restricts
from utils.base import PaimonContext from utils.base import PaimonContext
@listener_plugins_class()
class Help: class Help:
""" """
帮助 帮助
@ -17,6 +20,13 @@ class Help:
self.help_png = None self.help_png = None
self.file_id = None self.file_id = None
@classmethod
def create_handlers(cls) -> list:
_help = cls()
return [
CommandHandler("help", _help.command_start, block=False),
]
@restricts() @restricts()
async def command_start(self, update: Update, context: PaimonContext) -> None: async def command_start(self, update: Update, context: PaimonContext) -> None:
message = update.message message = update.message

View File

@ -1,9 +1,9 @@
import os
import json import json
import genshin import os
import re import re
from datetime import datetime, timedelta from datetime import datetime, timedelta
import genshin
from genshin import GenshinException, DataNotPublic from genshin import GenshinException, DataNotPublic
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.constants import ChatAction from telegram.constants import ChatAction
@ -59,7 +59,7 @@ def process_ledger_month(context: CallbackContext) -> int:
return now_time.month return now_time.month
@listener_plugins_class() @listener_plugins_class(need_service=True)
class Ledger(BasePlugins): class Ledger(BasePlugins):
""" """
旅行札记 旅行札记
@ -68,12 +68,12 @@ class Ledger(BasePlugins):
COMMAND_RESULT, = range(10200, 10201) COMMAND_RESULT, = range(10200, 10201)
def __init__(self, service: BaseService): def __init__(self, service: BaseService):
super().__init__(service) self.service = service
self.current_dir = os.getcwd() self.current_dir = os.getcwd()
@staticmethod @classmethod
def create_handlers(service: BaseService): def create_handlers(cls, service: BaseService):
ledger = Ledger(service) ledger = cls(service)
return [ConversationHandler( return [ConversationHandler(
entry_points=[CommandHandler("ledger", ledger.command_start, block=True), entry_points=[CommandHandler("ledger", ledger.command_start, block=True),
MessageHandler(filters.Regex(r"^旅行扎记(.*)"), ledger.command_start, block=True)], MessageHandler(filters.Regex(r"^旅行扎记(.*)"), ledger.command_start, block=True)],
@ -83,8 +83,8 @@ class Ledger(BasePlugins):
fallbacks=[CommandHandler("cancel", ledger.cancel, block=True)] fallbacks=[CommandHandler("cancel", ledger.cancel, block=True)]
)] )]
async def _start_get_ledger(self, user_info_data: UserInfoData, service: ServiceEnum, month=None) -> bytes: async def _start_get_ledger(self, user_info_data: UserInfoData, game_service: ServiceEnum, month=None) -> bytes:
if service == ServiceEnum.HYPERION: if game_service == ServiceEnum.HYPERION:
client = genshin.ChineseClient(cookies=user_info_data.mihoyo_cookie) client = genshin.ChineseClient(cookies=user_info_data.mihoyo_cookie)
uid = user_info_data.mihoyo_game_uid uid = user_info_data.mihoyo_game_uid
else: else:

View File

@ -27,7 +27,7 @@ class PostHandlerData:
self.tags: Optional[List[str]] = [] self.tags: Optional[List[str]] = []
@listener_plugins_class() @listener_plugins_class(need_service=True)
class Post(BasePlugins): class Post(BasePlugins):
""" """
文章推送 文章推送
@ -39,26 +39,26 @@ class Post(BasePlugins):
MENU_KEYBOARD = ReplyKeyboardMarkup([["推送频道", "添加TAG"], ["编辑文字", "删除图片"], ["退出"]], True, True) MENU_KEYBOARD = ReplyKeyboardMarkup([["推送频道", "添加TAG"], ["编辑文字", "删除图片"], ["退出"]], True, True)
def __init__(self, service: BaseService): def __init__(self, service: BaseService):
super().__init__(service) self.service = service
self.bbs = Hyperion() self.bbs = Hyperion()
@staticmethod @classmethod
def create_handlers(service: BaseService): def create_handlers(cls, service: BaseService):
_post = Post(service) post = cls(service)
post_handler = ConversationHandler( post_handler = ConversationHandler(
entry_points=[CommandHandler('post', _post.command_start, block=True)], entry_points=[CommandHandler('post', post.command_start, block=True)],
states={ states={
_post.CHECK_POST: [MessageHandler(filters.TEXT & ~filters.COMMAND, _post.check_post, block=True)], post.CHECK_POST: [MessageHandler(filters.TEXT & ~filters.COMMAND, post.check_post, block=True)],
_post.SEND_POST: [MessageHandler(filters.TEXT & ~filters.COMMAND, _post.send_post, block=True)], post.SEND_POST: [MessageHandler(filters.TEXT & ~filters.COMMAND, post.send_post, block=True)],
_post.CHECK_COMMAND: [MessageHandler(filters.TEXT & ~filters.COMMAND, _post.check_command, block=True)], post.CHECK_COMMAND: [MessageHandler(filters.TEXT & ~filters.COMMAND, post.check_command, block=True)],
_post.GTE_DELETE_PHOTO: [ post.GTE_DELETE_PHOTO: [
MessageHandler(filters.TEXT & ~filters.COMMAND, _post.get_delete_photo, block=True)], MessageHandler(filters.TEXT & ~filters.COMMAND, post.get_delete_photo, block=True)],
_post.GET_POST_CHANNEL: [ post.GET_POST_CHANNEL: [
MessageHandler(filters.TEXT & ~filters.COMMAND, _post.get_post_channel, block=True)], MessageHandler(filters.TEXT & ~filters.COMMAND, post.get_post_channel, block=True)],
_post.GET_TAGS: [MessageHandler(filters.TEXT & ~filters.COMMAND, _post.get_tags, block=True)], post.GET_TAGS: [MessageHandler(filters.TEXT & ~filters.COMMAND, post.get_tags, block=True)],
_post.GET_TEXT: [MessageHandler(filters.TEXT & ~filters.COMMAND, _post.get_edit_text, block=True)] post.GET_TEXT: [MessageHandler(filters.TEXT & ~filters.COMMAND, post.get_edit_text, block=True)]
}, },
fallbacks=[CommandHandler('cancel', _post.cancel, block=True)] fallbacks=[CommandHandler('cancel', post.cancel, block=True)]
) )
return [post_handler] return [post_handler]

View File

@ -11,10 +11,10 @@ from telegram.helpers import escape_markdown
from logger import Log from logger import Log
from manager import listener_plugins_class from manager import listener_plugins_class
from utils.random import MT19937_Random
from plugins.base import BasePlugins, restricts from plugins.base import BasePlugins, restricts
from service import BaseService from service import BaseService
from service.base import QuestionData, AnswerData from service.base import QuestionData, AnswerData
from utils.random import MT19937_Random
class QuizCommandData: class QuizCommandData:
@ -25,7 +25,7 @@ class QuizCommandData:
status: int = 0 status: int = 0
@listener_plugins_class() @listener_plugins_class(need_service=True)
class Quiz(BasePlugins): class Quiz(BasePlugins):
""" """
派蒙的十万个为什么 派蒙的十万个为什么
@ -37,15 +37,14 @@ class Quiz(BasePlugins):
QUESTION_EDIT, SAVE_QUESTION = range(10300, 10308) QUESTION_EDIT, SAVE_QUESTION = range(10300, 10308)
def __init__(self, service: BaseService): def __init__(self, service: BaseService):
super().__init__(service)
self.user_time = {} self.user_time = {}
self.service = service self.service = service
self.time_out = 120 self.time_out = 120
self.random = MT19937_Random() self.random = MT19937_Random()
@staticmethod @classmethod
def create_handlers(service: BaseService): def create_handlers(cls, service: BaseService):
quiz = Quiz(service) quiz = cls(service)
quiz_handler = ConversationHandler( quiz_handler = ConversationHandler(
entry_points=[CommandHandler('quiz', quiz.command_start, block=True)], entry_points=[CommandHandler('quiz', quiz.command_start, block=True)],
states={ states={

View File

@ -13,8 +13,8 @@ from manager import listener_plugins_class
from model.base import ServiceEnum from model.base import ServiceEnum
from plugins.base import BasePlugins, restricts from plugins.base import BasePlugins, restricts
from plugins.errorhandler import conversation_error_handler from plugins.errorhandler import conversation_error_handler
from service import BaseService
from service.base import UserInfoData from service.base import UserInfoData
from utils.base import PaimonContext
class SignCommandData: class SignCommandData:
@ -31,9 +31,9 @@ class Sign(BasePlugins):
CHECK_SERVER, COMMAND_RESULT = range(10400, 10402) CHECK_SERVER, COMMAND_RESULT = range(10400, 10402)
@staticmethod @classmethod
def create_handlers(service: BaseService): def create_handlers(cls):
sign = Sign(service) sign = cls()
sign_handler = ConversationHandler( sign_handler = ConversationHandler(
entry_points=[CommandHandler('sign', sign.command_start, block=True), entry_points=[CommandHandler('sign', sign.command_start, block=True),
MessageHandler(filters.Regex(r"^每日签到(.*)"), sign.command_start, block=True)], MessageHandler(filters.Regex(r"^每日签到(.*)"), sign.command_start, block=True)],
@ -45,8 +45,8 @@ class Sign(BasePlugins):
return [sign_handler] return [sign_handler]
@staticmethod @staticmethod
async def _start_sign(user_info: UserInfoData, service: ServiceEnum) -> str: async def _start_sign(user_info: UserInfoData, game_service: ServiceEnum) -> str:
if service == ServiceEnum.HYPERION: if game_service == ServiceEnum.HYPERION:
client = genshin.ChineseClient(cookies=user_info.mihoyo_cookie) client = genshin.ChineseClient(cookies=user_info.mihoyo_cookie)
uid = user_info.mihoyo_game_uid uid = user_info.mihoyo_game_uid
else: else:
@ -93,9 +93,10 @@ class Sign(BasePlugins):
@conversation_error_handler @conversation_error_handler
@restricts(return_data=ConversationHandler.END) @restricts(return_data=ConversationHandler.END)
async def command_start(self, update: Update, context: CallbackContext) -> int: async def command_start(self, update: Update, context: PaimonContext) -> int:
user = update.effective_user user = update.effective_user
message = update.message message = update.message
service = context.service
Log.info(f"用户 {user.full_name}[{user.id}] 每日签到命令请求") Log.info(f"用户 {user.full_name}[{user.id}] 每日签到命令请求")
if filters.ChatType.GROUPS.filter(message): if filters.ChatType.GROUPS.filter(message):
self._add_delete_message_job(context, message.chat_id, message.message_id) self._add_delete_message_job(context, message.chat_id, message.message_id)
@ -103,7 +104,7 @@ class Sign(BasePlugins):
if sign_command_data is None: if sign_command_data is None:
sign_command_data = SignCommandData() sign_command_data = SignCommandData()
context.chat_data["sign_command_data"] = sign_command_data context.chat_data["sign_command_data"] = sign_command_data
user_info = await self.service.user_service_db.get_user_info(user.id) user_info = await service.user_service_db.get_user_info(user.id)
if user_info.user_id == 0: if user_info.user_id == 0:
await update.message.reply_text("未查询到账号信息,请先私聊派蒙绑定账号") await update.message.reply_text("未查询到账号信息,请先私聊派蒙绑定账号")
return ConversationHandler.END return ConversationHandler.END

View File

@ -2,12 +2,11 @@ from telegram import Update, ReplyKeyboardRemove
from telegram.ext import CallbackContext from telegram.ext import CallbackContext
from telegram.helpers import escape_markdown from telegram.helpers import escape_markdown
from utils.base import PaimonContext
from plugins.base import restricts from plugins.base import restricts
@restricts() @restricts()
async def start(update: Update, context: PaimonContext) -> None: async def start(update: Update, context: CallbackContext) -> None:
user = update.effective_user user = update.effective_user
message = update.message message = update.message
args = context.args args = context.args

View File

@ -1,6 +1,6 @@
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.constants import ChatAction, ParseMode from telegram.constants import ChatAction, ParseMode
from telegram.ext import CallbackContext, filters, ConversationHandler, CommandHandler, MessageHandler from telegram.ext import filters, ConversationHandler, CommandHandler, MessageHandler
from logger import Log from logger import Log
from manager import listener_plugins_class from manager import listener_plugins_class
@ -8,7 +8,7 @@ from metadata.shortname import roleToName
from model.helpers import url_to_file from model.helpers import url_to_file
from plugins.base import BasePlugins, restricts from plugins.base import BasePlugins, restricts
from plugins.errorhandler import conversation_error_handler from plugins.errorhandler import conversation_error_handler
from service import BaseService from utils.base import PaimonContext
@listener_plugins_class() @listener_plugins_class()
@ -19,9 +19,9 @@ class Strategy(BasePlugins):
KEYBOARD = [[InlineKeyboardButton(text="查看角色攻略列表并查询", switch_inline_query_current_chat="查看角色攻略列表并查询")]] KEYBOARD = [[InlineKeyboardButton(text="查看角色攻略列表并查询", switch_inline_query_current_chat="查看角色攻略列表并查询")]]
@staticmethod @classmethod
def create_handlers(service: BaseService) -> list: def create_handlers(cls) -> list:
strategy = Strategy(service) strategy = cls()
return [ return [
CommandHandler("strategy", strategy.command_start, block=False), CommandHandler("strategy", strategy.command_start, block=False),
MessageHandler(filters.Regex("^角色攻略查询(.*)"), strategy.command_start, block=False), MessageHandler(filters.Regex("^角色攻略查询(.*)"), strategy.command_start, block=False),
@ -29,11 +29,12 @@ class Strategy(BasePlugins):
@conversation_error_handler @conversation_error_handler
@restricts(return_data=ConversationHandler.END) @restricts(return_data=ConversationHandler.END)
async def command_start(self, update: Update, context: CallbackContext) -> None: async def command_start(self, update: Update, context: PaimonContext) -> None:
message = update.message message = update.message
user = update.effective_user user = update.effective_user
args = context.args args = context.args
match = context.match match = context.match
service = context.service
role_name: str = "" role_name: str = ""
if args is None: if args is None:
if match is not None: if match is not None:
@ -52,7 +53,7 @@ class Strategy(BasePlugins):
self._add_delete_message_job(context, reply_message.chat_id, reply_message.message_id) self._add_delete_message_job(context, reply_message.chat_id, reply_message.message_id)
return return
role_name = roleToName(role_name) role_name = roleToName(role_name)
url = await self.service.get_game_info.get_characters_cultivation_atlas(role_name) url = await service.get_game_info.get_characters_cultivation_atlas(role_name)
if url == "": if url == "":
reply_message = await message.reply_text(f"没有找到 {role_name} 的攻略", reply_message = await message.reply_text(f"没有找到 {role_name} 的攻略",
reply_markup=InlineKeyboardMarkup(self.KEYBOARD)) reply_markup=InlineKeyboardMarkup(self.KEYBOARD))

View File

@ -22,7 +22,7 @@ class UidCommandData:
user_info: UserInfoData = UserInfoData() user_info: UserInfoData = UserInfoData()
@listener_plugins_class() @listener_plugins_class(need_service=True)
class Uid(BasePlugins): class Uid(BasePlugins):
""" """
玩家查询 玩家查询
@ -31,12 +31,12 @@ class Uid(BasePlugins):
COMMAND_RESULT, = range(10200, 10201) COMMAND_RESULT, = range(10200, 10201)
def __init__(self, service: BaseService): def __init__(self, service: BaseService):
super().__init__(service) self.service = service
self.current_dir = os.getcwd() self.current_dir = os.getcwd()
@staticmethod @classmethod
def create_handlers(service: BaseService): def create_handlers(cls, service: BaseService):
uid = Uid(service) uid = cls(service)
uid_handler = ConversationHandler( uid_handler = ConversationHandler(
entry_points=[CommandHandler('uid', uid.command_start, block=True), entry_points=[CommandHandler('uid', uid.command_start, block=True),
MessageHandler(filters.Regex(r"^玩家查询(.*)"), uid.command_start, block=True)], MessageHandler(filters.Regex(r"^玩家查询(.*)"), uid.command_start, block=True)],

View File

@ -1,6 +1,6 @@
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.constants import ChatAction from telegram.constants import ChatAction
from telegram.ext import CallbackContext, filters, CommandHandler, MessageHandler from telegram.ext import filters, CommandHandler, MessageHandler
from logger import Log from logger import Log
from manager import listener_plugins_class from manager import listener_plugins_class
@ -8,7 +8,7 @@ from metadata.shortname import weaponToName
from model.helpers import url_to_file from model.helpers import url_to_file
from plugins.base import BasePlugins, restricts from plugins.base import BasePlugins, restricts
from plugins.errorhandler import conversation_error_handler from plugins.errorhandler import conversation_error_handler
from service import BaseService from utils.base import PaimonContext
@listener_plugins_class() @listener_plugins_class()
@ -19,9 +19,9 @@ class Weapon(BasePlugins):
KEYBOARD = [[InlineKeyboardButton(text="查看武器列表并查询", switch_inline_query_current_chat="查看武器列表并查询")]] KEYBOARD = [[InlineKeyboardButton(text="查看武器列表并查询", switch_inline_query_current_chat="查看武器列表并查询")]]
@staticmethod @classmethod
def create_handlers(service: BaseService) -> list: def create_handlers(cls) -> list:
weapon = Weapon(service) weapon = cls()
return [ return [
CommandHandler("weapon", weapon.command_start, block=False), CommandHandler("weapon", weapon.command_start, block=False),
MessageHandler(filters.Regex("^武器查询(.*)"), weapon.command_start, block=False) MessageHandler(filters.Regex("^武器查询(.*)"), weapon.command_start, block=False)
@ -29,11 +29,12 @@ class Weapon(BasePlugins):
@conversation_error_handler @conversation_error_handler
@restricts() @restricts()
async def command_start(self, update: Update, context: CallbackContext) -> None: async def command_start(self, update: Update, context: PaimonContext) -> None:
message = update.message message = update.message
user = update.effective_user user = update.effective_user
args = context.args args = context.args
match = context.match match = context.match
service = context.service
weapon_name: str = "" weapon_name: str = ""
if args is None: if args is None:
if match is not None: if match is not None:
@ -90,8 +91,8 @@ class Weapon(BasePlugins):
return _template_data return _template_data
template_data = await input_template_data(weapon_data) template_data = await input_template_data(weapon_data)
png_data = await self.service.template.render('genshin/weapon', "weapon.html", template_data, png_data = await service.template.render('genshin/weapon', "weapon.html", template_data,
{"width": 540, "height": 540}) {"width": 540, "height": 540})
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO) await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
await message.reply_photo(png_data, filename=f"{template_data['weapon_name']}.png", await message.reply_photo(png_data, filename=f"{template_data['weapon_name']}.png",
allow_sending_without_reply=True) allow_sending_without_reply=True)

View File

@ -1,10 +1,10 @@
from telegram import Update from telegram import Update
from telegram.ext import CallbackContext, CommandHandler from telegram.ext import CommandHandler
from manager import listener_plugins_class from manager import listener_plugins_class
from plugins.admin import bot_admins_only from plugins.admin import bot_admins_only
from plugins.base import BasePlugins from plugins.base import BasePlugins
from service import BaseService from utils.base import PaimonContext
@listener_plugins_class() @listener_plugins_class()
@ -13,16 +13,17 @@ class Wiki(BasePlugins):
有关WIKI 有关WIKI
""" """
@staticmethod @classmethod
def create_handlers(service: BaseService) -> list: def create_handlers(cls) -> list:
wiki = Wiki(service) wiki = cls()
return [ return [
CommandHandler("refresh_wiki", wiki.refresh_wiki, block=False), CommandHandler("refresh_wiki", wiki.refresh_wiki, block=False),
] ]
@bot_admins_only @bot_admins_only
async def refresh_wiki(self, update: Update, _: CallbackContext): async def refresh_wiki(self, update: Update, context: PaimonContext):
message = update.message message = update.message
service = context.service
await message.reply_text("正在刷新Wiki缓存请稍等") await message.reply_text("正在刷新Wiki缓存请稍等")
await self.service.wiki.refresh_wiki() await service.wiki.refresh_wiki()
await message.reply_text("刷新Wiki缓存成功") await message.reply_text("刷新Wiki缓存成功")

View File

@ -4,13 +4,15 @@ from service import BaseService
class PaimonContext(CallbackContext[ExtBot, dict, dict, dict]): class PaimonContext(CallbackContext[ExtBot, dict, dict, dict]):
""" """自定义的PaimoeContext"""
PaimoeContext
"""
@property @property
def service(self) -> BaseService: def service(self) -> BaseService:
value = self.bot_data.get("service") """在回调中从 bot_data 获取 service 实例
:return: BaseService 实例
"""
value = self.application.bot_data.get("service")
if value is None: if value is None:
raise RuntimeError("没有与此上下文对象关联的实例化服务") raise RuntimeError("没有找到与此上下文对象关联的实例化服务")
return value return value