新增渠道扩展框架的核心基础层,为所有渠道扩展提供统一的基础设施。 主要变更: - channel/extensions/__init__.py: 渠道扩展包初始化与注册 - channel/extensions/base.py: 渠道插件基类,定义统一接口规范 - channel_service.py: 渠道服务核心业务逻辑 - models_channels.py: 渠道相关数据库模型 - 8 个 channel_*_repo.py: 渠道数据仓库层 - storage/postgres/manager.py: 数据库管理器,新增渠道表 - models_business.py: 业务模型更新 - config/app.py: 应用配置更新 - conversation_repository.py: 会话仓库更新 - oidc_service.py: OIDC 服务更新 - logging_config.py: 日志配置更新
95 lines
3.8 KiB
Python
95 lines
3.8 KiB
Python
from typing import Any
|
|
|
|
from sqlalchemy import select
|
|
|
|
from yuxi.channel.routing.models import BindingMatch, PeerConstraint, PeerKind, RouteBinding
|
|
from yuxi.storage.postgres.manager import pg_manager
|
|
from yuxi.storage.postgres.models_channels import ChannelBinding
|
|
|
|
|
|
def to_route_binding(binding: ChannelBinding) -> RouteBinding:
|
|
peer_constraint = None
|
|
if binding.peer_kind and binding.peer_id:
|
|
peer_constraint = PeerConstraint(
|
|
kind=PeerKind(binding.peer_kind),
|
|
peer_id=binding.peer_id,
|
|
)
|
|
|
|
match = BindingMatch(
|
|
channel=binding.channel_type,
|
|
channel_config_id=binding.channel_config_id,
|
|
account_id=binding.account_id,
|
|
peer=peer_constraint,
|
|
guild_id=binding.guild_id,
|
|
team_id=binding.team_id,
|
|
roles=list(binding.roles or []),
|
|
)
|
|
|
|
return RouteBinding(
|
|
agent_config_id=binding.agent_config_id,
|
|
match=match,
|
|
dm_scope=binding.dm_scope,
|
|
priority=binding.priority,
|
|
session_dm_scope=binding.session_dm_scope,
|
|
)
|
|
|
|
|
|
class ChannelBindingRepository:
|
|
async def get_by_id(self, binding_id: str) -> ChannelBinding | None:
|
|
async with pg_manager.get_async_session_context() as session:
|
|
result = await session.execute(select(ChannelBinding).where(ChannelBinding.id == binding_id))
|
|
return result.scalar_one_or_none()
|
|
|
|
async def list_by_agent(self, agent_config_id: int) -> list[ChannelBinding]:
|
|
async with pg_manager.get_async_session_context() as session:
|
|
result = await session.execute(
|
|
select(ChannelBinding)
|
|
.where(ChannelBinding.agent_config_id == agent_config_id)
|
|
.order_by(ChannelBinding.priority.desc())
|
|
)
|
|
return list(result.scalars().all())
|
|
|
|
async def list_all(self) -> list[ChannelBinding]:
|
|
async with pg_manager.get_async_session_context() as session:
|
|
result = await session.execute(select(ChannelBinding).order_by(ChannelBinding.priority.desc()))
|
|
return list(result.scalars().all())
|
|
|
|
async def list_by_channel_type(self, channel_type: str) -> list[ChannelBinding]:
|
|
async with pg_manager.get_async_session_context() as session:
|
|
result = await session.execute(
|
|
select(ChannelBinding)
|
|
.where(ChannelBinding.channel_type == channel_type)
|
|
.order_by(ChannelBinding.priority.desc())
|
|
)
|
|
return list(result.scalars().all())
|
|
|
|
async def create(self, data: dict[str, Any]) -> ChannelBinding:
|
|
async with pg_manager.get_async_session_context() as session:
|
|
binding = ChannelBinding(**data)
|
|
session.add(binding)
|
|
await session.commit()
|
|
await session.refresh(binding)
|
|
return binding
|
|
|
|
async def update(self, binding_id: str, data: dict[str, Any]) -> ChannelBinding | None:
|
|
async with pg_manager.get_async_session_context() as session:
|
|
result = await session.execute(select(ChannelBinding).where(ChannelBinding.id == binding_id))
|
|
binding = result.scalar_one_or_none()
|
|
if binding is None:
|
|
return None
|
|
for key, value in data.items():
|
|
if key != "id":
|
|
setattr(binding, key, value)
|
|
await session.commit()
|
|
await session.refresh(binding)
|
|
return binding
|
|
|
|
async def delete(self, binding_id: str) -> bool:
|
|
async with pg_manager.get_async_session_context() as session:
|
|
result = await session.execute(select(ChannelBinding).where(ChannelBinding.id == binding_id))
|
|
binding = result.scalar_one_or_none()
|
|
if binding is None:
|
|
return False
|
|
await session.delete(binding)
|
|
return True
|