package vip.mate.channel.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import vip.mate.channel.ChannelManager;
import vip.mate.channel.model.ChannelEntity;
import vip.mate.channel.service.ChannelService;
import vip.mate.channel.verifier.ChannelVerifierRegistry;
import vip.mate.channel.verifier.VerificationRequest;
import vip.mate.channel.verifier.VerificationResult;
import vip.mate.audit.service.AuditEventService;
import vip.mate.common.result.R;
import vip.mate.exception.MateClawException;
import vip.mate.workspace.core.annotation.RequireWorkspaceRole;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* 渠道管理接口
*
* 提供渠道的 CRUD、启用/禁用(联动 ChannelManager 生命周期)、状态查询等能力。
* 对应前端 Channel 管理页面。
*
* @author MateClaw Team
*/
@Slf4j
@Tag(name = "渠道管理")
@RestController
@RequestMapping("/api/v1/channels")
@RequiredArgsConstructor
public class ChannelController {
private final ChannelService channelService;
private final ChannelManager channelManager;
private final AuditEventService auditEventService;
private final ChannelVerifierRegistry verifierRegistry;
private final ObjectMapper objectMapper;
@RequireWorkspaceRole("viewer")
@Operation(summary = "获取渠道列表")
@GetMapping
public R> list(
@RequestHeader(value = "X-Workspace-Id", required = false) Long workspaceId) {
long wsId = workspaceId != null ? workspaceId : 1L;
return R.ok(channelService.listChannelsByWorkspace(wsId));
}
@RequireWorkspaceRole("viewer")
@Operation(summary = "按类型获取渠道列表")
@GetMapping("/type/{channelType}")
public R> listByType(@PathVariable String channelType,
@RequestHeader(value = "X-Workspace-Id", required = false) Long workspaceId) {
long wsId = workspaceId != null ? workspaceId : 1L;
return R.ok(channelService.listChannelsByTypeAndWorkspace(channelType, wsId));
}
@RequireWorkspaceRole("viewer")
@Operation(summary = "获取渠道详情")
@GetMapping("/{id}")
public R get(@PathVariable Long id,
@RequestHeader(value = "X-Workspace-Id", required = false) Long workspaceId) {
ChannelEntity channel = channelService.getChannel(id);
verifyResourceWorkspace(channel.getWorkspaceId(), workspaceId);
return R.ok(channel);
}
@RequireWorkspaceRole("admin")
@Operation(summary = "创建渠道")
@PostMapping
public R create(
@RequestHeader(value = "X-Workspace-Id", required = false) Long workspaceId,
@RequestBody ChannelEntity channel) {
channel.setWorkspaceId(workspaceId != null ? workspaceId : 1L);
ChannelEntity created = channelService.createChannel(channel);
// 创建后如果渠道已启用,自动启动(与 toggle 行为对齐)
if (Boolean.TRUE.equals(created.getEnabled())) {
channelManager.startChannel(created);
}
auditEventService.record("CREATE", "CHANNEL", String.valueOf(created.getId()), created.getName(), null);
return R.ok(created);
}
@RequireWorkspaceRole("admin")
@Operation(summary = "更新渠道")
@PutMapping("/{id}")
public R update(@PathVariable Long id, @RequestBody ChannelEntity channel,
@RequestHeader(value = "X-Workspace-Id", required = false) Long workspaceId) {
ChannelEntity existing = channelService.getChannel(id);
verifyResourceWorkspace(existing.getWorkspaceId(), workspaceId);
channel.setId(id);
channel.setWorkspaceId(existing.getWorkspaceId());
ChannelEntity updated = channelService.updateChannel(channel);
channelManager.restartChannel(id);
auditEventService.record("UPDATE", "CHANNEL", String.valueOf(id), updated.getName(), null);
return R.ok(updated);
}
@RequireWorkspaceRole("admin")
@Operation(summary = "删除渠道")
@DeleteMapping("/{id}")
public R delete(@PathVariable Long id,
@RequestHeader(value = "X-Workspace-Id", required = false) Long workspaceId) {
ChannelEntity channel = channelService.getChannel(id);
verifyResourceWorkspace(channel.getWorkspaceId(), workspaceId);
channelManager.stopChannel(id);
channelService.deleteChannel(id);
auditEventService.record("DELETE", "CHANNEL", String.valueOf(id), channel.getName(), null);
return R.ok();
}
@RequireWorkspaceRole("admin")
@Operation(summary = "启用/禁用渠道")
@PutMapping("/{id}/toggle")
public R toggle(@PathVariable Long id, @RequestParam boolean enabled,
@RequestHeader(value = "X-Workspace-Id", required = false) Long workspaceId) {
ChannelEntity existing = channelService.getChannel(id);
verifyResourceWorkspace(existing.getWorkspaceId(), workspaceId);
ChannelEntity channel = channelService.toggleChannel(id, enabled);
// 联动 ChannelManager:启用时启动,禁用时停止
if (enabled) {
channelManager.startChannel(channel);
} else {
channelManager.stopChannel(id);
}
auditEventService.record(enabled ? "ENABLE" : "DISABLE", "CHANNEL", String.valueOf(id), channel.getName(), null);
return R.ok(channel);
}
@RequireWorkspaceRole("admin")
@Operation(summary = "获取渠道运行状态(全局系统视图,仅管理员可见)")
@GetMapping("/status")
public R