mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-06 16:07:01 +08:00
refactor: expand async and type safety gates
This commit is contained in:
Vendored
+11
-2
@@ -2772,8 +2772,11 @@ class PluginHelper(metaclass=WeakSingleton):
|
||||
await async_dest_path.mkdir(parents=True, exist_ok=True)
|
||||
continue
|
||||
await async_dest_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with zf.open(info, 'r') as src:
|
||||
data = src.read()
|
||||
data = await asyncio.to_thread(
|
||||
self.__read_release_zip_member,
|
||||
zf,
|
||||
info,
|
||||
)
|
||||
async with aiofiles.open(dest_path, 'wb') as dst:
|
||||
await dst.write(data)
|
||||
wrote_any = True
|
||||
@@ -2784,6 +2787,12 @@ class PluginHelper(metaclass=WeakSingleton):
|
||||
logger.error(f"解压 Release 压缩包失败:{e}")
|
||||
return False, f"解压 Release 压缩包失败:{e}"
|
||||
|
||||
@staticmethod
|
||||
def __read_release_zip_member(zf: zipfile.ZipFile, info: zipfile.ZipInfo) -> bytes:
|
||||
"""在线程池读取并解压单个 Release 文件,避免阻塞事件循环。"""
|
||||
with zf.open(info, "r") as source:
|
||||
return source.read()
|
||||
|
||||
|
||||
# 公开 Release 查询的缓存管理统一指向仓库级分页缓存。
|
||||
PluginHelper.get_plugin_release_versions.cache_clear = PluginHelper._get_plugin_repo_releases.cache_clear
|
||||
|
||||
@@ -87,6 +87,17 @@ SUMMARY_PROMPT = """请判断以下 AI 助手与用户的对话是否值得写
|
||||
ACTIVITY_ENTRY_PATTERN = re.compile(r"^-\s+\*\*(?P<time>\d{2}:\d{2})\*\*\s+(?P<summary>.+)$")
|
||||
|
||||
|
||||
def _write_activity_log_exclusive(path: Path, content: str) -> bool:
|
||||
"""同步独占创建日志文件;调用方必须在线程池中执行本函数。"""
|
||||
try:
|
||||
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)
|
||||
except FileExistsError:
|
||||
return False
|
||||
with os.fdopen(fd, "w", encoding="utf-8") as stream:
|
||||
stream.write(content)
|
||||
return True
|
||||
|
||||
|
||||
class QueryActivityLogInput(BaseModel):
|
||||
"""查询活动日志工具的输入参数模型。"""
|
||||
|
||||
@@ -565,18 +576,18 @@ class ActivityLogMiddleware(AgentMiddleware[ActivityLogState, ContextT, Response
|
||||
await stream.write(entry)
|
||||
else:
|
||||
header = f"# {today_str} 活动日志\n\n"
|
||||
try:
|
||||
fd = os.open(log_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)
|
||||
except FileExistsError:
|
||||
created = await anyio.to_thread.run_sync(
|
||||
_write_activity_log_exclusive,
|
||||
Path(log_path),
|
||||
header + entry,
|
||||
)
|
||||
if not created:
|
||||
async with await anyio.open_file(
|
||||
log_path,
|
||||
mode="a",
|
||||
encoding="utf-8",
|
||||
) as stream:
|
||||
await stream.write(entry)
|
||||
else:
|
||||
with os.fdopen(fd, "w", encoding="utf-8") as stream:
|
||||
stream.write(header + entry)
|
||||
logger.debug(f"Activity logged: {summarize_result(summary, max_chars=80)}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to append activity log: {summarize_error(e)}")
|
||||
|
||||
@@ -16,7 +16,7 @@ from app.api.context import (
|
||||
from app.api.data import get_async_db, get_db
|
||||
from app.api.dependencies.data import repository
|
||||
from app.application.outbox import AsyncOutboxTransaction
|
||||
from app.application.scheduling import Scheduler
|
||||
from app.application.scheduling import start_scheduler_job
|
||||
from app.application.servarr import ServarrSubscriptionService
|
||||
from app.application.subscription.delete import (
|
||||
AsyncUnitOfWork as DeleteUnitOfWork,
|
||||
@@ -99,7 +99,7 @@ def get_search_subscriptions_command(
|
||||
def schedule_search(subscribe_id: int | None, state: str | None) -> None:
|
||||
"""按历史参数提交订阅搜索调度任务。"""
|
||||
background_tasks.add_task(
|
||||
Scheduler().start,
|
||||
start_scheduler_job,
|
||||
job_id="subscribe_search",
|
||||
sid=subscribe_id,
|
||||
state=state,
|
||||
|
||||
@@ -12,7 +12,7 @@ Scheduler 实现由 startup 组合根在导入期注册,避免 application 层
|
||||
import asyncio
|
||||
from dataclasses import dataclass, field
|
||||
from enum import StrEnum
|
||||
from typing import Any, Awaitable, Callable, List, Optional
|
||||
from typing import Any, Awaitable, Callable, List, Optional, cast
|
||||
|
||||
# Agent 自主定时任务在运行时调度器中的任务 ID 前缀。
|
||||
AGENT_TASK_JOB_PREFIX = "agent-task"
|
||||
@@ -143,12 +143,12 @@ class Scheduler:
|
||||
|
||||
def list_scheduler_jobs() -> List[Any]:
|
||||
"""列出运行时调度器的全部任务。"""
|
||||
return get_scheduler().list()
|
||||
return cast(List[Any], get_scheduler().list())
|
||||
|
||||
|
||||
def start_scheduler_job(job_id: str) -> None:
|
||||
def start_scheduler_job(job_id: str, **kwargs: Any) -> None:
|
||||
"""立即运行指定的运行时定时任务。"""
|
||||
get_scheduler().start(job_id)
|
||||
get_scheduler().start(job_id, **kwargs)
|
||||
|
||||
|
||||
def update_plugin_job(plugin_id: str) -> None:
|
||||
@@ -163,7 +163,7 @@ def remove_plugin_job(plugin_id: str) -> None:
|
||||
|
||||
def start_agent_task(task_id: int) -> bool:
|
||||
"""立即执行 Agent 自主定时任务。"""
|
||||
return get_scheduler().start_agent_task(task_id)
|
||||
return cast(bool, get_scheduler().start_agent_task(task_id))
|
||||
|
||||
|
||||
def get_agent_task_next_run(task_id: int) -> Optional[Any]:
|
||||
|
||||
@@ -20,7 +20,7 @@ class EventErrorPolicy:
|
||||
self,
|
||||
*,
|
||||
notifier: Callable[[], Optional[EventErrorNotifier]],
|
||||
emit_system_error: Callable[[dict], object],
|
||||
emit_system_error: Callable[[dict[str, Any]], object],
|
||||
) -> None:
|
||||
"""注入通知读取器和 SystemError 发送回调。"""
|
||||
self._notifier = notifier
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
from collections.abc import Callable, Mapping
|
||||
from typing import Any, Protocol
|
||||
from typing import Any, Protocol, cast
|
||||
|
||||
from app.foundation.reflection import ObjectUtils
|
||||
from app.runtime.execution import run_in_threadpool
|
||||
@@ -324,7 +324,7 @@ class ModuleInvocationDispatcher:
|
||||
def _module_name(module: Any, fallback: str) -> str:
|
||||
"""读取模块展示名,失败时回退到稳定类名。"""
|
||||
try:
|
||||
return module.get_name()
|
||||
return cast(str, module.get_name())
|
||||
except Exception as err:
|
||||
logger.debug("获取模块名称出错:%s", str(err))
|
||||
return fallback
|
||||
|
||||
Reference in New Issue
Block a user