diff --git a/GenshinUID/__init__.py b/GenshinUID/__init__.py index 6427a61f..29864c60 100644 --- a/GenshinUID/__init__.py +++ b/GenshinUID/__init__.py @@ -11,11 +11,16 @@ from nonebot.adapters import Bot from nonebot.matcher import Matcher from nonebot.permission import SUPERUSER from nonebot.internal.adapter import Event -from nonebot import on_notice, get_driver, on_message, on_fullmatch +from websockets.exceptions import ConnectionClosed +from nonebot import require, on_notice, on_message, on_fullmatch -from .client import GsClient -from .auto_install import start, install -from .models import Message, MessageReceive +require('nonebot_plugin_apscheduler') + +from nonebot_plugin_apscheduler import scheduler # noqa:E402 + +from .client import GsClient, driver # noqa:E402 +from .auto_install import start, install # noqa:E402 +from .models import Message, MessageReceive # noqa:E402 get_message = on_message(priority=999) get_notice = on_notice(priority=999) @@ -24,15 +29,24 @@ start_core = on_fullmatch('启动core', permission=SUPERUSER, block=True) connect_core = on_fullmatch( ('连接core', '链接core'), permission=SUPERUSER, block=True ) -driver = get_driver() -gsclient: Optional[GsClient] = None +gsclient: Optional[GsClient] = None command_start = driver.config.command_start +if hasattr(driver.config, 'gsuid_core_repeat'): + is_repeat = True +else: + is_repeat = False + @get_notice.handle() async def get_notice_message(bot: Bot, ev: Event): - if gsclient is None or not gsclient.is_alive: + if gsclient is None: + return await connect() + + try: + await gsclient.ws.ping() + except ConnectionClosed: return await connect() raw_data = ev.dict() @@ -377,11 +391,24 @@ async def connect(): global gsclient try: gsclient = await GsClient().async_connect() - await gsclient.start() except ConnectionRefusedError: logger.error('Core服务器连接失败...请稍后使用[启动core]命令启动...') +@scheduler.scheduled_job('cron', second='*/10') +async def repeat_connect(): + if is_repeat: + global gsclient + if gsclient is None: + await connect() + else: + try: + await gsclient.ws.ensure_open() + except ConnectionClosed: + return await connect() + return + + def convert_message(_msg: Any, message: List[Message], index: int): if _msg.type == 'text': data: str = ( diff --git a/GenshinUID/client.py b/GenshinUID/client.py index a73f8814..7b292fbd 100644 --- a/GenshinUID/client.py +++ b/GenshinUID/client.py @@ -1,6 +1,7 @@ import os import json import time +import uuid import base64 import asyncio from pathlib import Path @@ -15,10 +16,14 @@ from websockets.exceptions import ConnectionClosedError from .models import MessageSend, MessageReceive -BOT_ID = 'NoneBot2' bots: Dict[str, str] = {} driver = get_driver() +if hasattr(driver.config, 'gsuid_core_botid'): + BOT_ID = str(uuid.uuid4())[:10] +else: + BOT_ID = 'NoneBot2' + if hasattr(driver.config, 'gsuid_core_host'): HOST = driver.config.gsuid_core_host else: @@ -44,6 +49,8 @@ def _get_bot(bot_id: str) -> Bot: class GsClient: + _instance = None + @classmethod async def async_connect(cls, IP: str = HOST, PORT: Union[str, int] = PORT): self = GsClient() @@ -55,8 +62,16 @@ class GsClient: ) logger.success(f'与[gsuid-core]成功连接! Bot_ID: {BOT_ID}') cls.msg_list = asyncio.queues.Queue() + cls.pending = [] + await self.start() return self + def __new__(cls, *args, **kwargs): + # 判断sv是否已经被初始化 + if cls._instance is None: + cls._instance = super(GsClient, cls).__new__(cls, *args, **kwargs) + return cls._instance + async def recv_msg(self): try: global bots @@ -199,8 +214,17 @@ class GsClient: except RuntimeError as e: logger.error(e) except ConnectionClosedError: + for task in self.pending: + task.cancel() logger.warning(f'与[gsuid-core]断开连接! Bot_ID: {BOT_ID}') - self.is_alive = False + for _ in range(30): + await asyncio.sleep(5) + try: + await self.async_connect() + await self.start() + break + except: # noqa + logger.debug('自动连接core服务器失败...五秒后重新连接...') async def _input(self, msg: MessageReceive): await self.msg_list.put(msg) @@ -214,12 +238,10 @@ class GsClient: async def start(self): recv_task = asyncio.create_task(self.recv_msg()) send_task = asyncio.create_task(self.send_msg()) - _, pending = await asyncio.wait( + _, self.pending = await asyncio.wait( [recv_task, send_task], return_when=asyncio.FIRST_COMPLETED, ) - for task in pending: - task.cancel() def to_json(msg: str, name: str, uin: int): @@ -252,9 +274,10 @@ async def onebot_send( ): async def _send(content: Optional[str], image: Optional[str]): from nonebot.adapters.onebot.v11 import MessageSegment + result_image = MessageSegment.image(image) if image else '' - content = MessageSegment.text(content) if content else '' - result_msg = content + result_image + _content = MessageSegment.text(content) if content else '' + result_msg = _content + result_image if at_list and target_type == 'group': for at in at_list: result_msg += MessageSegment.at(at) diff --git a/poetry.lock b/poetry.lock index 884ebade..98069d27 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand. [[package]] name = "aiofiles" @@ -12,6 +12,65 @@ files = [ {file = "aiofiles-23.1.0.tar.gz", hash = "sha256:edd247df9a19e0db16534d4baaf536d6609a43e1de5401d7a4c1c148753a1635"}, ] +[[package]] +name = "apscheduler" +version = "3.10.1" +description = "In-process task scheduler with Cron-like capabilities" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "APScheduler-3.10.1-py3-none-any.whl", hash = "sha256:e813ad5ada7aff36fb08cdda746b520531eaac7757832abc204868ba78e0c8f6"}, + {file = "APScheduler-3.10.1.tar.gz", hash = "sha256:0293937d8f6051a0f493359440c1a1b93e882c57daf0197afeff0e727777b96e"}, +] + +[package.dependencies] +pytz = "*" +setuptools = ">=0.7" +six = ">=1.4.0" +tzlocal = ">=2.0,<3.0.0 || >=4.0.0" + +[package.extras] +doc = ["sphinx", "sphinx-rtd-theme"] +gevent = ["gevent"] +mongodb = ["pymongo (>=3.0)"] +redis = ["redis (>=3.0)"] +rethinkdb = ["rethinkdb (>=2.4.0)"] +sqlalchemy = ["sqlalchemy (>=1.4)"] +testing = ["pytest", "pytest-asyncio", "pytest-cov", "pytest-tornado5"] +tornado = ["tornado (>=4.3)"] +twisted = ["twisted"] +zookeeper = ["kazoo"] + +[[package]] +name = "backports-zoneinfo" +version = "0.2.1" +description = "Backport of the standard library zoneinfo module" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, + {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, +] + +[package.extras] +tzdata = ["tzdata"] + [[package]] name = "black" version = "22.12.0" @@ -443,6 +502,22 @@ files = [ [package.dependencies] setuptools = "*" +[[package]] +name = "nonebot-plugin-apscheduler" +version = "0.2.0" +description = "APScheduler Support for NoneBot2" +category = "main" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "nonebot-plugin-apscheduler-0.2.0.tar.gz", hash = "sha256:7b63e99a611b657533b48fcf1f8c6627c18c2eb3fa820a906cd4ec4666c0ceb0"}, + {file = "nonebot_plugin_apscheduler-0.2.0-py3-none-any.whl", hash = "sha256:9285ee84ca1cfa4db73c86cedb5911bbbd25a21ec0cd5f22447cd12f89e48fb4"}, +] + +[package.dependencies] +apscheduler = ">=3.7.0,<4.0.0" +nonebot2 = ">=2.0.0-rc.1,<3.0.0" + [[package]] name = "nonebot2" version = "2.0.0rc4" @@ -722,6 +797,34 @@ files = [ [package.extras] cli = ["click (>=5.0)"] +[[package]] +name = "pytz" +version = "2023.3" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, + {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, +] + +[[package]] +name = "pytz-deprecation-shim" +version = "0.1.0.post0" +description = "Shims to make deprecation of pytz easier" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "pytz_deprecation_shim-0.1.0.post0-py2.py3-none-any.whl", hash = "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6"}, + {file = "pytz_deprecation_shim-0.1.0.post0.tar.gz", hash = "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d"}, +] + +[package.dependencies] +"backports.zoneinfo" = {version = "*", markers = "python_version >= \"3.6\" and python_version < \"3.9\""} +tzdata = {version = "*", markers = "python_version >= \"3.6\""} + [[package]] name = "pyyaml" version = "6.0" @@ -776,7 +879,7 @@ files = [ name = "setuptools" version = "67.6.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -789,6 +892,18 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-g testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + [[package]] name = "smmap" version = "5.0.0" @@ -874,6 +989,38 @@ files = [ mypy-extensions = ">=0.3.0" typing-extensions = ">=3.7.4" +[[package]] +name = "tzdata" +version = "2023.3" +description = "Provider of IANA time zone data" +category = "main" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, + {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, +] + +[[package]] +name = "tzlocal" +version = "4.3" +description = "tzinfo object for the local timezone" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tzlocal-4.3-py3-none-any.whl", hash = "sha256:b44c4388f3d34f25862cfbb387578a4d70fec417649da694a132f628a23367e2"}, + {file = "tzlocal-4.3.tar.gz", hash = "sha256:3f21d09e1b2aa9f2dacca12da240ca37de3ba5237a93addfd6d593afe9073355"}, +] + +[package.dependencies] +"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} +pytz-deprecation-shim = "*" +tzdata = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +devenv = ["black", "check-manifest", "flake8", "pyroma", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] + [[package]] name = "virtualenv" version = "20.21.0" @@ -1081,4 +1228,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "d49e84b5eb2a29ca82a116c6fb3887eb5e5a4c634c9813aeccef8edfe1cdb5e8" +content-hash = "018ab686902eb17df6a5280eb1366aed1ba69999257a0741ef2fbcbe766533d6" diff --git a/pyproject.toml b/pyproject.toml index c97e6dc5..768c9695 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "nonebot-plugin-genshinuid" -version = "4.0.2" +version = "4.0.3" description = "支持OneBot(QQ)、OneBotV12、QQ频道、微信、KOOK(开黑啦)、Telegram(电报)、FeiShu(飞书)的全功能NoneBot2原神插件" authors = ["KimigaiiWuyi <444835641@qq.com>"] license = "GPL-3.0-or-later" @@ -47,6 +47,7 @@ gitpython = ">=3.1.27" msgspec = ">=0.13.1" aiofiles = ">=23.1.0" websockets = ">=11.0.1" +nonebot-plugin-apscheduler = "^0.2.0" [[tool.poetry.source]] name = "USTC" diff --git a/requirements.txt b/requirements.txt index 61b7f339..ff19cd0f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,6 @@ aiofiles==23.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +apscheduler==3.10.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +backports-zoneinfo==0.2.1 ; python_full_version >= "3.8.1" and python_version < "3.9" colorama==0.4.6 ; python_full_version >= "3.8.1" and python_version < "4.0" and sys_platform == "win32" gitdb==4.0.10 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" gitpython==3.1.31 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" @@ -6,14 +8,21 @@ idna==3.4 ; python_full_version >= "3.8.1" and python_version < "4.0" loguru==0.6.0 ; python_full_version >= "3.8.1" and python_version < "4.0" msgspec==0.14.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" multidict==6.0.4 ; python_full_version >= "3.8.1" and python_version < "4.0" +nonebot-plugin-apscheduler==0.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0" nonebot2==2.0.0rc4 ; python_full_version >= "3.8.1" and python_version < "4.0" pillow==9.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" pydantic[dotenv]==1.10.7 ; python_full_version >= "3.8.1" and python_version < "4.0" pygtrie==2.5.0 ; python_full_version >= "3.8.1" and python_version < "4.0" python-dotenv==1.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +pytz-deprecation-shim==0.1.0.post0 ; python_full_version >= "3.8.1" and python_version < "4.0" +pytz==2023.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +setuptools==67.6.1 ; python_full_version >= "3.8.1" and python_version < "4.0" +six==1.16.0 ; python_full_version >= "3.8.1" and python_version < "4.0" smmap==5.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" tomli==2.0.1 ; python_full_version >= "3.8.1" and python_version < "3.11" typing-extensions==4.5.0 ; python_full_version >= "3.8.1" and python_version < "4.0" +tzdata==2023.3 ; python_full_version >= "3.8.1" and python_version < "4.0" +tzlocal==4.3 ; python_full_version >= "3.8.1" and python_version < "4.0" websockets==11.0.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" win32-setctime==1.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" and sys_platform == "win32" yarl==1.8.2 ; python_full_version >= "3.8.1" and python_version < "4.0"