mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-29 20:17:13 +08:00
226 lines
8.3 KiB
Python
226 lines
8.3 KiB
Python
"""站点 Chain 端口的显式会话与事务适配器。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Awaitable, Callable
|
|
from contextlib import AbstractAsyncContextManager
|
|
from typing import Any, TypeVar
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.db.oper.site import SiteOper
|
|
from app.db.uow import SqlAlchemyAsyncUnitOfWork, SqlAlchemyUnitOfWork
|
|
|
|
|
|
T = TypeVar("T")
|
|
|
|
|
|
class TransactionalSiteRepository:
|
|
"""为同步 Chain 站点端口和异步健康统计提供短生命周期会话。"""
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
sync_session: Callable[[], Session],
|
|
async_session: Callable[[], AbstractAsyncContextManager[AsyncSession]],
|
|
) -> None:
|
|
"""保存同步会话工厂和异步会话上下文工厂。"""
|
|
self._sync_session = sync_session
|
|
self._async_session = async_session
|
|
|
|
def _read(self, operation: Callable[[SiteOper], T]) -> T:
|
|
"""在独立同步会话中执行只读站点操作。"""
|
|
with self._sync_session() as session:
|
|
return operation(SiteOper(db=session))
|
|
|
|
def _write(self, operation: Callable[[SiteOper], T]) -> T:
|
|
"""在独立同步 UoW 中执行站点写操作。"""
|
|
with self._sync_session() as session:
|
|
session.expire_on_commit = False
|
|
unit_of_work = SqlAlchemyUnitOfWork(session)
|
|
try:
|
|
result = operation(SiteOper(db=session))
|
|
unit_of_work.commit()
|
|
return result
|
|
except Exception:
|
|
unit_of_work.rollback()
|
|
raise
|
|
|
|
async def _async_write(
|
|
self,
|
|
operation: Callable[[SiteOper], Awaitable[T]],
|
|
) -> T:
|
|
"""在独立异步 UoW 中执行站点写操作。"""
|
|
async with self._async_session() as session:
|
|
session.sync_session.expire_on_commit = False
|
|
unit_of_work = SqlAlchemyAsyncUnitOfWork(session)
|
|
try:
|
|
result = await operation(SiteOper(db=session))
|
|
await unit_of_work.commit()
|
|
return result
|
|
except Exception:
|
|
await unit_of_work.rollback()
|
|
raise
|
|
|
|
async def _async_read(self, operation: Callable[[SiteOper], Awaitable[T]]) -> T:
|
|
"""在独立异步会话中执行只读站点操作。"""
|
|
async with self._async_session() as session:
|
|
return await operation(SiteOper(db=session))
|
|
|
|
def add(self, **kwargs: Any) -> tuple[bool, str]:
|
|
"""新增站点并提交事务。"""
|
|
return self._write(lambda repository: repository.add(**kwargs))
|
|
|
|
def get(self, site_id: int) -> Any:
|
|
"""按 ID 查询站点。"""
|
|
return self._read(lambda repository: repository.get(site_id))
|
|
|
|
def get_by_domain(self, domain: str) -> Any:
|
|
"""按域名查询站点。"""
|
|
return self._read(lambda repository: repository.get_by_domain(domain))
|
|
|
|
def get_domains_by_ids(self, ids: list[int]) -> list[str | None]:
|
|
"""查询一组站点 ID 对应的域名。"""
|
|
return self._read(lambda repository: repository.get_domains_by_ids(ids))
|
|
|
|
def list(self) -> list[Any]:
|
|
"""查询全部站点。"""
|
|
return self._read(lambda repository: repository.list())
|
|
|
|
def list_order_by_pri(self) -> list[Any]:
|
|
"""同步按优先级查询站点。"""
|
|
return self._read(lambda repository: repository.list_order_by_pri())
|
|
|
|
def get_userdata_latest(self) -> list[Any]:
|
|
"""同步查询各站点最新用户数据。"""
|
|
return self._read(lambda repository: repository.get_userdata_latest())
|
|
|
|
async def async_get(self, site_id: int) -> Any:
|
|
"""异步按 ID 查询站点。"""
|
|
return await self._async_read(lambda repository: repository.async_get(site_id))
|
|
|
|
async def async_get_by_domain(self, domain: str) -> Any:
|
|
"""异步按域名查询站点。"""
|
|
return await self._async_read(
|
|
lambda repository: repository.async_get_by_domain(domain)
|
|
)
|
|
|
|
async def async_get_by_name(self, name: str) -> Any:
|
|
"""异步按名称查询站点。"""
|
|
return await self._async_read(
|
|
lambda repository: repository.async_get_by_name(name)
|
|
)
|
|
|
|
async def async_list(self) -> list[Any]:
|
|
"""异步查询全部站点。"""
|
|
return await self._async_read(lambda repository: repository.async_list())
|
|
|
|
async def async_list_order_by_pri(self) -> list[Any]:
|
|
"""异步按优先级查询站点。"""
|
|
return await self._async_read(
|
|
lambda repository: repository.async_list_order_by_pri()
|
|
)
|
|
|
|
async def async_update(self, site_id: int, payload: dict[str, Any]) -> Any:
|
|
"""异步更新站点并提交事务。"""
|
|
return await self._async_write(
|
|
lambda repository: repository.async_update(site_id, payload)
|
|
)
|
|
|
|
async def async_get_userdata_by_domain(
|
|
self,
|
|
domain: str,
|
|
workdate: str | None = None,
|
|
) -> list[Any]:
|
|
"""异步查询站点用户数据。"""
|
|
return await self._async_read(
|
|
lambda repository: repository.async_get_userdata_by_domain(domain, workdate)
|
|
)
|
|
|
|
async def async_get_userdata_latest(self) -> list[Any]:
|
|
"""异步查询各站点最新用户数据。"""
|
|
return await self._async_read(
|
|
lambda repository: repository.async_get_userdata_latest()
|
|
)
|
|
|
|
async def async_get_icon_by_domain(self, domain: str) -> Any:
|
|
"""异步按域名查询站点图标。"""
|
|
return await self._async_read(
|
|
lambda repository: repository.async_get_icon_by_domain(domain)
|
|
)
|
|
|
|
async def async_get_statistic_by_domain(self, domain: str) -> Any:
|
|
"""异步按域名查询站点统计。"""
|
|
return await self._async_read(
|
|
lambda repository: repository.async_get_statistic_by_domain(domain)
|
|
)
|
|
|
|
async def async_list_statistics(self) -> list[Any]:
|
|
"""异步查询全部站点统计。"""
|
|
return await self._async_read(
|
|
lambda repository: repository.async_list_statistics()
|
|
)
|
|
|
|
def update(self, site_id: int, payload: dict[str, Any]) -> Any:
|
|
"""更新站点并提交事务。"""
|
|
return self._write(lambda repository: repository.update(site_id, payload))
|
|
|
|
def update_cookie(self, domain: str, cookies: str) -> tuple[bool, str]:
|
|
"""更新站点 Cookie 并提交事务。"""
|
|
return self._write(
|
|
lambda repository: repository.update_cookie(domain, cookies)
|
|
)
|
|
|
|
def update_rss(self, domain: str, rss: str) -> tuple[bool, str]:
|
|
"""更新站点 RSS 地址并提交事务。"""
|
|
return self._write(lambda repository: repository.update_rss(domain, rss))
|
|
|
|
def update_userdata(
|
|
self,
|
|
domain: str,
|
|
name: str,
|
|
payload: dict[str, Any],
|
|
) -> tuple[bool, str]:
|
|
"""更新站点用户数据并提交事务。"""
|
|
return self._write(
|
|
lambda repository: repository.update_userdata(domain, name, payload)
|
|
)
|
|
|
|
def update_icon(
|
|
self,
|
|
name: str,
|
|
domain: str,
|
|
icon_url: str,
|
|
icon_base64: str,
|
|
) -> bool:
|
|
"""更新站点图标并提交事务。"""
|
|
return self._write(
|
|
lambda repository: repository.update_icon(
|
|
name,
|
|
domain,
|
|
icon_url,
|
|
icon_base64,
|
|
)
|
|
)
|
|
|
|
def success(self, domain: str, seconds: int | None = None) -> Any:
|
|
"""记录站点访问成功并提交事务。"""
|
|
return self._write(lambda repository: repository.success(domain, seconds))
|
|
|
|
def fail(self, domain: str) -> Any:
|
|
"""记录站点访问失败并提交事务。"""
|
|
return self._write(lambda repository: repository.fail(domain))
|
|
|
|
async def async_success(self, domain: str, seconds: int | None = None) -> Any:
|
|
"""异步记录站点访问成功并提交事务。"""
|
|
return await self._async_write(
|
|
lambda repository: repository.async_success(domain, seconds)
|
|
)
|
|
|
|
async def async_fail(self, domain: str) -> Any:
|
|
"""异步记录站点访问失败并提交事务。"""
|
|
return await self._async_write(
|
|
lambda repository: repository.async_fail(domain)
|
|
)
|