feat:模块健康检查

This commit is contained in:
jxxghp
2024-03-06 13:23:51 +08:00
parent 01e08c8e69
commit 8cb061ff75
24 changed files with 248 additions and 28 deletions

View File

@ -197,33 +197,6 @@ def get_logging(token: str, length: int = 50, logfile: str = "moviepilot.log"):
return StreamingResponse(log_generator(), media_type="text/event-stream")
@router.get("/nettest", summary="测试网络连通性")
def nettest(url: str,
proxy: bool,
_: schemas.TokenPayload = Depends(verify_token)):
"""
测试网络连通性
"""
# 记录开始的毫秒数
start_time = datetime.now()
url = url.replace("{TMDBAPIKEY}", settings.TMDB_API_KEY)
result = RequestUtils(proxies=settings.PROXY if proxy else None,
ua=settings.USER_AGENT).get_res(url)
# 计时结束的毫秒数
end_time = datetime.now()
# 计算相关秒数
if result and result.status_code == 200:
return schemas.Response(success=True, data={
"time": round((end_time - start_time).microseconds / 1000)
})
elif result:
return schemas.Response(success=False, message=f"错误码:{result.status_code}", data={
"time": round((end_time - start_time).microseconds / 1000)
})
else:
return schemas.Response(success=False, message="网络连接失败!")
@router.get("/versions", summary="查询Github所有Release版本", response_model=schemas.Response)
def latest_version(_: schemas.TokenPayload = Depends(verify_token)):
"""
@ -269,6 +242,53 @@ def ruletest(title: str,
})
@router.get("/nettest", summary="测试网络连通性")
def nettest(url: str,
proxy: bool,
_: schemas.TokenPayload = Depends(verify_token)):
"""
测试网络连通性
"""
# 记录开始的毫秒数
start_time = datetime.now()
url = url.replace("{TMDBAPIKEY}", settings.TMDB_API_KEY)
result = RequestUtils(proxies=settings.PROXY if proxy else None,
ua=settings.USER_AGENT).get_res(url)
# 计时结束的毫秒数
end_time = datetime.now()
# 计算相关秒数
if result and result.status_code == 200:
return schemas.Response(success=True, data={
"time": round((end_time - start_time).microseconds / 1000)
})
elif result:
return schemas.Response(success=False, message=f"错误码:{result.status_code}", data={
"time": round((end_time - start_time).microseconds / 1000)
})
else:
return schemas.Response(success=False, message="网络连接失败!")
@router.get("/modulelist", summary="查询已加载的模块ID列表", response_model=schemas.Response)
def modulelist(_: schemas.TokenPayload = Depends(verify_token)):
"""
查询已加载的模块ID列表
"""
module_ids = [module.__name__ for module in ModuleManager().get_modules("test")]
return schemas.Response(success=True, data={
"ids": module_ids
})
@router.get("/moduletest/{moduleid}", summary="模块可用性测试", response_model=schemas.Response)
def moduletest(moduleid: str, _: schemas.TokenPayload = Depends(verify_token)):
"""
模块可用性测试接口
"""
state, errmsg = ModuleManager().test(moduleid)
return schemas.Response(success=state, message=errmsg)
@router.get("/restart", summary="重启系统", response_model=schemas.Response)
def restart_system(_: schemas.TokenPayload = Depends(verify_token)):
"""

View File

@ -1,4 +1,4 @@
from typing import Generator, Optional
from typing import Generator, Optional, Tuple
from app.core.config import settings
from app.helper.module import ModuleHelper
@ -51,6 +51,18 @@ class ModuleManager(metaclass=Singleton):
if hasattr(module, "stop"):
module.stop()
def test(self, modleid: str) -> Tuple[bool, str]:
"""
测试模块
"""
if modleid not in self._running_modules:
return False, "模块未加载,请检查参数设置"
module = self._running_modules[modleid]
if hasattr(module, "test") \
and ObjectUtils.check_method(getattr(module, "test")):
return module.test()
return True, "模块不支持测试"
@staticmethod
def check_setting(setting: Optional[tuple]) -> bool:
"""

View File

@ -35,6 +35,13 @@ class _ModuleBase(metaclass=ABCMeta):
"""
pass
@abstractmethod
def test(self) -> Tuple[bool, str]:
"""
模块测试, 返回测试结果和错误信息
"""
pass
def checkMessage(channel_type: MessageChannel):
"""

View File

@ -13,6 +13,7 @@ from app.modules.douban.douban_cache import DoubanCache
from app.modules.douban.scraper import DoubanScraper
from app.schemas.types import MediaType
from app.utils.common import retry
from app.utils.http import RequestUtils
from app.utils.system import SystemUtils
@ -29,6 +30,17 @@ class DoubanModule(_ModuleBase):
def stop(self):
pass
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
ret = RequestUtils().get_res("https://movie.douban.com/")
if ret and ret.status_code == 200:
return True, ""
elif ret:
return False, f"无法连接豆瓣,错误码:{ret.status_code}"
return False, "豆瓣网络连接失败"
def init_setting(self) -> Tuple[str, Union[str, bool]]:
pass

View File

@ -17,6 +17,16 @@ class EmbyModule(_ModuleBase):
def stop(self):
pass
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
if self.emby.is_inactive():
self.emby.reconnect()
if self.emby.is_inactive():
return False, "无法连接Emby请检查参数配置"
return True, ""
def init_setting(self) -> Tuple[str, Union[str, bool]]:
return "MEDIASERVER", "emby"

View File

@ -317,6 +317,17 @@ class FanartModule(_ModuleBase):
def stop(self):
pass
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
ret = RequestUtils().get_res("https://webservice.fanart.tv")
if ret and ret.status_code == 200:
return True, ""
elif ret:
return False, f"无法连接fanart错误码{ret.status_code}"
return False, "fanart网络连接失败"
def init_setting(self) -> Tuple[str, Union[str, bool]]:
return "FANART_API_KEY", True

View File

@ -27,6 +27,9 @@ class FileTransferModule(_ModuleBase):
def stop(self):
pass
def test(self):
pass
def init_setting(self) -> Tuple[str, Union[str, bool]]:
pass

View File

@ -132,6 +132,9 @@ class FilterModule(_ModuleBase):
def stop(self):
pass
def test(self):
pass
def init_setting(self) -> Tuple[str, Union[str, bool]]:
pass

View File

@ -4,6 +4,7 @@ from typing import List, Optional, Tuple, Union
from ruamel.yaml import CommentedMap
from app.core.context import TorrentInfo
from app.helper.sites import SitesHelper
from app.log import logger
from app.modules import _ModuleBase
from app.modules.indexer.mtorrent import MTorrentSpider
@ -25,6 +26,15 @@ class IndexerModule(_ModuleBase):
def stop(self):
pass
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
sites = SitesHelper().get_indexers()
if not sites:
return False, "未配置站点或未通过用户认证"
return True, ""
def init_setting(self) -> Tuple[str, Union[str, bool]]:
return "INDEXER", "builtin"

View File

@ -28,6 +28,16 @@ class JellyfinModule(_ModuleBase):
def stop(self):
pass
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
if self.jellyfin.is_inactive():
self.jellyfin.reconnect()
if self.jellyfin.is_inactive():
return False, "无法连接Jellyfin请检查参数配置"
return True, ""
def user_authenticate(self, name: str, password: str) -> Optional[str]:
"""
使用Emby用户辅助完成用户认证

View File

@ -17,6 +17,16 @@ class PlexModule(_ModuleBase):
def stop(self):
pass
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
if self.plex.is_inactive():
self.plex.reconnect()
if self.plex.is_inactive():
return False, "无法连接Plex请检查参数配置"
return True, ""
def init_setting(self) -> Tuple[str, Union[str, bool]]:
return "MEDIASERVER", "plex"

View File

@ -26,6 +26,16 @@ class QbittorrentModule(_ModuleBase):
def stop(self):
pass
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
if self.qbittorrent.is_inactive():
self.qbittorrent.reconnect()
if self.qbittorrent.is_inactive():
return False, "无法连接Qbittorrent请检查参数配置"
return True, ""
def init_setting(self) -> Tuple[str, Union[str, bool]]:
return "DOWNLOADER", "qbittorrent"

View File

@ -19,6 +19,15 @@ class SlackModule(_ModuleBase):
def stop(self):
self.slack.stop()
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
state = self.slack.get_state()
if state:
return True, ""
return False, "Slack未就续请检查参数设置和网络连接"
def init_setting(self) -> Tuple[str, Union[str, bool]]:
return "MESSAGER", "slack"

View File

@ -87,6 +87,12 @@ class Slack:
except Exception as err:
logger.error("Slack消息接收服务停止失败: %s" % str(err))
def get_state(self) -> bool:
"""
获取状态
"""
return True if self._client else False
def send_msg(self, title: str, text: str = "", image: str = "", url: str = "", userid: str = ""):
"""
发送Telegram消息

View File

@ -34,6 +34,9 @@ class SubtitleModule(_ModuleBase):
def stop(self) -> None:
pass
def test(self):
pass
def download_added(self, context: Context, download_dir: Path, torrent_path: Path = None) -> None:
"""
添加下载任务成功后,从站点下载字幕,保存到下载目录

View File

@ -16,6 +16,15 @@ class SynologyChatModule(_ModuleBase):
def stop(self):
pass
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
state = self.synologychat.get_state()
if state:
return True, ""
return False, "SynologyChat未就续请检查参数设置、网络连接以及机器人是否可见"
def init_setting(self) -> Tuple[str, Union[str, bool]]:
return "MESSAGER", "synologychat"

View File

@ -25,6 +25,17 @@ class SynologyChat:
def check_token(self, token: str) -> bool:
return True if token == self._token else False
def get_state(self) -> bool:
"""
获取状态
"""
if not self._webhook_url or not self._token:
return False
ret = self.__get_bot_users()
if ret:
return True
return False
def send_msg(self, title: str, text: str = "", image: str = "", userid: str = "") -> Optional[bool]:
"""
发送Telegram消息

View File

@ -18,6 +18,15 @@ class TelegramModule(_ModuleBase):
def stop(self):
self.telegram.stop()
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
state = self.telegram.get_state()
if state:
return True, ""
return False, "Telegram未就续请检查参数设置和网络连接"
def init_setting(self) -> Tuple[str, Union[str, bool]]:
return "MESSAGER", "telegram"

View File

@ -61,6 +61,12 @@ class Telegram:
self._polling_thread.start()
logger.info("Telegram消息接收服务启动")
def get_state(self) -> bool:
"""
获取状态
"""
return self._bot is not None
def send_msg(self, title: str, text: str = "", image: str = "", userid: str = "") -> Optional[bool]:
"""
发送Telegram消息

View File

@ -12,6 +12,7 @@ from app.modules.themoviedb.scraper import TmdbScraper
from app.modules.themoviedb.tmdb_cache import TmdbCache
from app.modules.themoviedb.tmdbapi import TmdbHelper
from app.schemas.types import MediaType, MediaImageType
from app.utils.http import RequestUtils
from app.utils.system import SystemUtils
@ -38,6 +39,17 @@ class TheMovieDbModule(_ModuleBase):
def stop(self):
self.cache.save()
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
ret = RequestUtils().get_res(f"https://{settings.TMDB_API_DOMAIN}/3/movie/550?api_key={settings.TMDB_API_KEY}")
if ret and ret.status_code == 200:
return True, ""
elif ret:
return False, f"无法连接 {settings.TMDB_API_DOMAIN},错误码:{ret.status_code}"
return False, f"{settings.TMDB_API_DOMAIN} 网络连接失败"
def init_setting(self) -> Tuple[str, Union[str, bool]]:
pass

View File

@ -5,6 +5,7 @@ from app.core.config import settings
from app.log import logger
from app.modules import _ModuleBase
from app.modules.thetvdb import tvdbapi
from app.utils.http import RequestUtils
class TheTvDbModule(_ModuleBase):
@ -20,6 +21,17 @@ class TheTvDbModule(_ModuleBase):
def stop(self):
pass
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
ret = RequestUtils().get_res("https://api.thetvdb.com/series/81189")
if ret and ret.status_code == 200:
return True, ""
elif ret:
return False, f"无法连接 api.thetvdb.com错误码{ret.status_code}"
return False, "api.thetvdb.com 网络连接失败"
def init_setting(self) -> Tuple[str, Union[str, bool]]:
pass

View File

@ -26,6 +26,16 @@ class TransmissionModule(_ModuleBase):
def stop(self):
pass
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
if self.transmission.is_inactive():
self.transmission.reconnect()
if self.transmission.is_inactive():
return False, "无法连接Transmission请检查参数配置"
return True, ""
def init_setting(self) -> Tuple[str, Union[str, bool]]:
return "DOWNLOADER", "transmission"

View File

@ -20,6 +20,15 @@ class WechatModule(_ModuleBase):
def stop(self):
pass
def test(self) -> Tuple[bool, str]:
"""
测试模块连接性
"""
state = self.wechat.get_state()
if state:
return True, ""
return False, "获取微信token失败"
def init_setting(self) -> Tuple[str, Union[str, bool]]:
return "MESSAGER", "wechat"

View File

@ -47,6 +47,12 @@ class WeChat:
if self._corpid and self._appsecret and self._appid:
self.__get_access_token()
def get_state(self):
"""
获取状态
"""
return True if self.__get_access_token else False
@retry(Exception, logger=logger)
def __get_access_token(self, force=False):
"""