ForcePilot/backend/package/yuxi/repositories/channel_binding_repo.py
Kris fb754d82f1 feat(channel): 添加全渠道网关核心基础架构
新增渠道扩展框架的核心基础层,为所有渠道扩展提供统一的基础设施。

主要变更:
- 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: 日志配置更新
2026-05-21 12:08:03 +08:00

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