refactor: 优化后端服务结构

- 统一使用 orz 响应格式
- 优化 handler 和 service 层代码
- 改进上下文传递

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
yumusbandClaude Opus 4.6 committed 2026-04-10 12:53:13 +08:00
1 parent 85a55af6a5
commit b9ec210542
11 files changed
+67 -122

No files matched your search

-9
View File
@@ -238,15 +238,6 @@ func (h *AgentHandler) Delete(c echo.Context) error {
return err
}
// 删除探针及其所有相关数据
if err := h.agentService.DeleteAgent(ctx, agentID); err != nil {
h.logger.Error("删除探针失败",
zap.String("agentID", agentID),
zap.String("name", agent.Name),
zap.Error(err))
return err
}
h.logger.Info("探针已删除",
zap.String("agentID", agentID),
zap.String("name", agent.Name))
+2 -6
View File
@@ -1,8 +1,6 @@
package handler
import (
"net/http"
"github.com/dushixiang/pika/internal/service"
"github.com/go-orz/orz"
"github.com/labstack/echo/v4"
@@ -48,10 +46,8 @@ func (h *AlertHandler) ListAlertRecords(c echo.Context) error {
func (h *AlertHandler) ClearAlertRecords(c echo.Context) error {
if err := h.alertService.Clear(c.Request().Context()); err != nil {
h.logger.Error("清空告警记录失败", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "清空告警记录失败",
})
return orz.NewError(500, "清空告警记录失败")
}
return c.JSON(http.StatusOK, echo.Map{})
return orz.Ok(c, orz.Map{})
}
+1 -1
View File
@@ -178,7 +178,7 @@ func (h *MonitorHandler) GetAgentStatsByID(c echo.Context) error {
return err
}
stats := h.metricService.GetMonitorAgentStats(id)
stats := h.metricService.GetMonitorAgentStats(ctx, id)
for i := range stats {
stats[i].Target = "" // 隐藏目标地址
}
+13 -33
View File
@@ -33,9 +33,7 @@ func (h *PropertyHandler) GetProperty(c echo.Context) error {
property, err := h.service.Get(c.Request().Context(), id)
if err != nil {
h.logger.Error("获取属性失败", zap.String("id", id), zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "获取属性失败",
})
return orz.NewError(500, "获取属性失败")
}
// 解析 JSON 值
@@ -43,13 +41,11 @@ func (h *PropertyHandler) GetProperty(c echo.Context) error {
if property.Value != "" {
if err := json.Unmarshal([]byte(property.Value), &value); err != nil {
h.logger.Error("解析属性值失败", zap.String("id", id), zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "解析属性值失败",
})
return orz.NewError(500, "解析属性值失败")
}
}
return c.JSON(http.StatusOK, map[string]interface{}{
return orz.Ok(c, map[string]interface{}{
"id": property.ID,
"name": property.Name,
"value": value,
@@ -66,9 +62,7 @@ func (h *PropertyHandler) SetProperty(c echo.Context) error {
}
if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{
"message": "无效的请求参数",
})
return orz.NewError(400, "无效的请求参数")
}
// 特殊校验:系统配置
@@ -85,21 +79,17 @@ func (h *PropertyHandler) SetProperty(c echo.Context) error {
}
if nameZh == "" && nameEn == "" {
return c.JSON(http.StatusBadRequest, map[string]string{
"message": "系统名称(中文)和系统名称(英文)不能同时为空",
})
return orz.NewError(400, "系统名称(中文)和系统名称(英文)不能同时为空")
}
}
}
if err := h.service.Set(c.Request().Context(), id, req.Name, req.Value); err != nil {
h.logger.Error("设置属性失败", zap.String("id", id), zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "设置属性失败",
})
return orz.NewError(500, "设置属性失败")
}
return c.JSON(http.StatusOK, orz.Map{})
return orz.Ok(c, orz.Map{})
}
// GetLogo 获取系统 Logo(公开访问,返回图片文件流)
@@ -174,9 +164,7 @@ func (h *PropertyHandler) GetLogo(c echo.Context) error {
func (h *PropertyHandler) TestNotificationChannel(c echo.Context) error {
channelType := c.Param("type")
if channelType == "" {
return c.JSON(http.StatusBadRequest, map[string]string{
"message": "缺少渠道类型参数",
})
return orz.NewError(400, "缺少渠道类型参数")
}
ctx := c.Request().Context()
@@ -184,9 +172,7 @@ func (h *PropertyHandler) TestNotificationChannel(c echo.Context) error {
channels, err := h.service.GetNotificationChannelConfigs(c.Request().Context())
if err != nil {
h.logger.Error("获取通知渠道配置失败", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "获取通知渠道配置失败",
})
return orz.NewError(500, "获取通知渠道配置失败")
}
// 查找指定类型的渠道
@@ -199,15 +185,11 @@ func (h *PropertyHandler) TestNotificationChannel(c echo.Context) error {
}
if targetChannel == nil {
return c.JSON(http.StatusNotFound, map[string]string{
"message": "通知渠道不存在,请先配置",
})
return orz.NewError(404, "通知渠道不存在,请先配置")
}
if !targetChannel.Enabled {
return c.JSON(http.StatusBadRequest, map[string]string{
"message": "通知渠道未启用",
})
return orz.NewError(400, "通知渠道未启用")
}
// 发送测试消息(动态匹配通知渠道类型)
@@ -216,10 +198,8 @@ func (h *PropertyHandler) TestNotificationChannel(c echo.Context) error {
if sendErr != nil {
h.logger.Error("发送测试通知失败", zap.String("type", channelType), zap.Error(sendErr))
return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "发送测试通知失败: " + sendErr.Error(),
})
return orz.NewError(500, "发送测试通知失败: "+sendErr.Error())
}
return c.JSON(http.StatusOK, echo.Map{})
return orz.Ok(c, orz.Map{})
}
+13 -30
View File
@@ -1,9 +1,6 @@
package handler
import (
"context"
"net/http"
"github.com/dushixiang/pika/internal/models"
"github.com/dushixiang/pika/internal/service"
"github.com/go-orz/orz"
@@ -30,20 +27,16 @@ func NewSSHLoginHandler(logger *zap.Logger, service *service.SSHLoginService) *S
func (h *SSHLoginHandler) GetConfig(c echo.Context) error {
agentID := c.Param("id")
if agentID == "" {
return c.JSON(http.StatusBadRequest, map[string]string{
"message": "探针ID不能为空",
})
return orz.NewError(400, "探针ID不能为空")
}
config, err := h.service.GetConfig(c.Request().Context(), agentID)
if err != nil {
h.logger.Error("获取SSH登录监控配置失败", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "获取配置失败",
})
return orz.NewError(500, "获取配置失败")
}
return c.JSON(http.StatusOK, config)
return orz.Ok(c, config)
}
// UpdateConfig 更新SSH登录监控配置
@@ -59,12 +52,10 @@ func (h *SSHLoginHandler) UpdateConfig(c echo.Context) error {
err := h.service.UpdateConfig(c.Request().Context(), agentID, &req)
if err != nil {
h.logger.Error("更新SSH登录监控配置失败", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "更新配置失败",
})
return orz.NewError(500, "更新配置失败")
}
return c.JSON(http.StatusOK, orz.Map{})
return orz.Ok(c, orz.Map{})
}
// ListEvents 查询SSH登录事件
@@ -81,7 +72,7 @@ func (h *SSHLoginHandler) ListEvents(c echo.Context) error {
Equal("ip", c.QueryParam("ip")).
Equal("status", c.QueryParam("status"))
ctx := context.Background()
ctx := c.Request().Context()
page, err := builder.Execute(ctx)
if err != nil {
return err
@@ -95,27 +86,21 @@ func (h *SSHLoginHandler) ListEvents(c echo.Context) error {
func (h *SSHLoginHandler) GetEvent(c echo.Context) error {
eventID := c.Param("id")
if eventID == "" {
return c.JSON(http.StatusBadRequest, map[string]string{
"message": "事件ID不能为空",
})
return orz.NewError(400, "事件ID不能为空")
}
ctx := context.Background()
ctx := c.Request().Context()
event, exists, err := h.service.SSHLoginEventRepo.FindByIdExists(ctx, eventID)
if err != nil {
h.logger.Error("获取SSH登录事件失败", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "获取事件失败",
})
return orz.NewError(500, "获取事件失败")
}
if !exists {
return c.JSON(http.StatusNotFound, map[string]string{
"message": "事件不存在",
})
return orz.NewError(404, "事件不存在")
}
return c.JSON(http.StatusOK, event)
return orz.Ok(c, event)
}
// DeleteEvents 删除探针的所有SSH登录事件
@@ -123,12 +108,10 @@ func (h *SSHLoginHandler) GetEvent(c echo.Context) error {
func (h *SSHLoginHandler) DeleteEvents(c echo.Context) error {
agentID := c.Param("id")
ctx := context.Background()
ctx := c.Request().Context()
if err := h.service.DeleteEventsByAgentID(ctx, agentID); err != nil {
h.logger.Error("删除SSH登录事件失败", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"message": "删除失败",
})
return orz.NewError(500, "删除失败")
}
return orz.Ok(c, orz.Map{})
+7 -16
View File
@@ -1,9 +1,6 @@
package handler
import (
"context"
"net/http"
"github.com/dushixiang/pika/internal/models"
"github.com/dushixiang/pika/internal/service"
"github.com/go-orz/orz"
@@ -37,12 +34,10 @@ func (h *TamperHandler) UpdateConfig(c echo.Context) error {
err := h.tamperService.UpdateConfig(c.Request().Context(), agentID, &req)
if err != nil {
h.logger.Error("更新防篡改配置失败", zap.Error(err), zap.String("agentId", agentID))
return c.JSON(http.StatusInternalServerError, map[string]interface{}{
"message": "更新配置失败",
})
return orz.NewError(500, "更新配置失败")
}
return c.JSON(http.StatusOK, orz.Map{})
return orz.Ok(c, orz.Map{})
}
// GetConfig 获取探针的防篡改配置
@@ -53,12 +48,10 @@ func (h *TamperHandler) GetConfig(c echo.Context) error {
config, err := h.tamperService.GetConfigByAgentID(c.Request().Context(), agentID)
if err != nil {
h.logger.Error("获取防篡改配置失败", zap.Error(err), zap.String("agentId", agentID))
return c.JSON(http.StatusInternalServerError, map[string]interface{}{
"message": "获取配置失败",
})
return orz.NewError(500, "获取配置失败")
}
return c.JSON(http.StatusOK, config)
return orz.Ok(c, config)
}
// ListEvents 获取探针的防篡改事件
@@ -75,7 +68,7 @@ func (h *TamperHandler) ListEvents(c echo.Context) error {
Equal("operation", c.QueryParam("operation")).
Contains("details", c.QueryParam("details"))
ctx := context.Background()
ctx := c.Request().Context()
page, err := builder.Execute(ctx)
if err != nil {
return err
@@ -89,9 +82,7 @@ func (h *TamperHandler) DeleteEvents(c echo.Context) error {
err := h.tamperService.DeleteEventsByAgentID(c.Request().Context(), agentID)
if err != nil {
h.logger.Error("删除防篡改事件失败", zap.Error(err), zap.String("agentId", agentID))
return c.JSON(http.StatusInternalServerError, map[string]interface{}{
"message": "删除事件失败",
})
return orz.NewError(500, "删除事件失败")
}
return c.JSON(http.StatusOK, orz.Map{})
return orz.Ok(c, orz.Map{})
}
+18 -12
View File
@@ -356,8 +356,8 @@ func (s *AgentService) GetStatistics(ctx context.Context) (map[string]interface{
// DeleteAgent 删除探针及其所有相关数据
func (s *AgentService) DeleteAgent(ctx context.Context, agentID string) error {
// 在事务中执行所有删除操作
return s.Transaction(ctx, func(ctx context.Context) error {
// 在事务中执行所有数据库删除操作
err := s.Transaction(ctx, func(ctx context.Context) error {
// 1. 删除探针的审计结果
if err := s.AgentRepo.DeleteAuditResults(ctx, agentID); err != nil {
s.logger.Error("删除探针审计结果失败", zap.String("agentId", agentID), zap.Error(err))
@@ -376,23 +376,29 @@ func (s *AgentService) DeleteAgent(ctx context.Context, agentID string) error {
return err
}
// 4. 清理 VictoriaMetrics 中的指标数据(非事务操作,失败不阻止删除)
if s.metricService != nil {
if err := s.metricService.CleanAgentMetrics(ctx, agentID); err != nil {
s.logger.Error("清理VictoriaMetrics中的探针指标数据失败", zap.String("agentId", agentID), zap.Error(err))
// 记录错误但不停止删除流程
}
}
// 5. 最后删除探针本身
// 4. 最后删除探针本身
if err := s.AgentRepo.DeleteById(ctx, agentID); err != nil {
s.logger.Error("删除探针失败", zap.String("agentId", agentID), zap.Error(err))
return err
}
s.logger.Info("探针删除成功", zap.String("agentId", agentID))
return nil
})
if err != nil {
return err
}
// 5. 清理 VictoriaMetrics 中的指标数据(事务外执行,失败不影响数据库删除结果)
if s.metricService != nil {
if err := s.metricService.CleanAgentMetrics(ctx, agentID); err != nil {
s.logger.Error("清理VictoriaMetrics中的探针指标数据失败", zap.String("agentId", agentID), zap.Error(err))
// 记录错误但不返回,因为数据库删除已成功
}
}
s.logger.Info("探针删除成功", zap.String("agentId", agentID))
return nil
}
// ListByAuth 根据认证状态列出探针(已登录返回全部,未登录返回公开可见)
+2 -4
View File
@@ -803,7 +803,7 @@ func (s *MetricService) GetMonitorHistory(ctx context.Context, monitorID string,
}
// GetMonitorAgentStats 获取监控任务各探针的统计数据(只从缓存读取)
func (s *MetricService) GetMonitorAgentStats(monitorID string) []protocol.MonitorData {
func (s *MetricService) GetMonitorAgentStats(ctx context.Context, monitorID string) []protocol.MonitorData {
// 从缓存读取监控数据
latestMetrics, ok := s.monitorLatestCache.Get(monitorID)
if !ok {
@@ -812,7 +812,6 @@ func (s *MetricService) GetMonitorAgentStats(monitorID string) []protocol.Monito
}
// 查询监控任务配置
ctx := context.Background()
monitorTask, err := s.monitorRepo.FindById(ctx, monitorID)
if err != nil {
s.logger.Error("查询监控任务失败", zap.String("monitorID", monitorID), zap.Error(err))
@@ -872,7 +871,7 @@ func (s *MetricService) GetMonitorAgentStats(monitorID string) []protocol.Monito
}
// GetMonitorStats 获取监控任务的聚合统计数据(只从缓存读取)
func (s *MetricService) GetMonitorStats(monitorID string) *metric.MonitorStatsResult {
func (s *MetricService) GetMonitorStats(ctx context.Context, monitorID string) *metric.MonitorStatsResult {
// 从缓存读取监控数据
latestMetrics, ok := s.monitorLatestCache.Get(monitorID)
if !ok {
@@ -883,7 +882,6 @@ func (s *MetricService) GetMonitorStats(monitorID string) *metric.MonitorStatsRe
}
// 查询监控任务配置
ctx := context.Background()
monitorTask, err := s.monitorRepo.FindById(ctx, monitorID)
if err != nil {
s.logger.Error("查询监控任务失败", zap.String("monitorID", monitorID), zap.Error(err))
+4 -4
View File
@@ -219,7 +219,7 @@ func (s *MonitorService) ListByAuth(ctx context.Context, isAuthenticated bool) (
items := make([]metric.PublicMonitorOverview, 0, len(monitors))
for _, monitor := range monitors {
// 查询统计数据
stats := s.metricService.GetMonitorStats(monitor.ID)
stats := s.metricService.GetMonitorStats(ctx, monitor.ID)
// 构建监控概览对象
item := s.buildMonitorOverview(monitor, stats)
items = append(items, item)
@@ -341,7 +341,7 @@ func (s *MonitorService) GetMonitorStatsByID(ctx context.Context, monitorID stri
}
// 查询统计数据
stats := s.metricService.GetMonitorStats(monitorID)
stats := s.metricService.GetMonitorStats(ctx, monitorID)
// 构建监控概览对象
overview := s.buildMonitorOverview(monitor, stats)
@@ -381,7 +381,7 @@ func (s *MonitorService) GetLatestMonitorMetricsByType(ctx context.Context, moni
// 在缓存中查询最新的监控数据
var result []protocol.MonitorData
for _, task := range monitorTasks {
monitorData := s.metricService.GetMonitorAgentStats(task.ID)
monitorData := s.metricService.GetMonitorAgentStats(ctx, task.ID)
// 填充监控任务名称
for i := range monitorData {
monitorData[i].MonitorName = task.Name
@@ -403,7 +403,7 @@ func (s *MonitorService) GetAllLatestMonitorMetrics(ctx context.Context) ([]prot
// 在缓存中查询最新的监控数据
var result []protocol.MonitorData
for _, task := range monitorTasks {
monitorData := s.metricService.GetMonitorAgentStats(task.ID)
monitorData := s.metricService.GetMonitorAgentStats(ctx, task.ID)
// 填充监控任务名称
for i := range monitorData {
monitorData[i].MonitorName = task.Name
+4 -4
View File
@@ -172,17 +172,17 @@ func (s *SSHLoginService) HandleEvent(ctx context.Context, agentID string, event
s.logger.Info("IP在白名单中,忽略事件", zap.String("agentId", agentID), zap.String("ip", eventData.IP))
return nil
}
s.sendLoginSuccessNotification(agentID, eventData, ipLocation)
s.sendLoginSuccessNotification(ctx, agentID, eventData, ipLocation)
return nil
}
func (s *SSHLoginService) sendLoginSuccessNotification(agentID string, eventData protocol.SSHLoginEvent, ipLocation string) {
func (s *SSHLoginService) sendLoginSuccessNotification(ctx context.Context, agentID string, eventData protocol.SSHLoginEvent, ipLocation string) {
if s.notificationSvc == nil {
return
}
agent, err := s.agentRepo.FindById(context.Background(), agentID)
agent, err := s.agentRepo.FindById(ctx, agentID)
if err != nil {
s.logger.Error("获取探针信息失败", zap.String("agentId", agentID), zap.Error(err))
return
@@ -195,7 +195,7 @@ func (s *SSHLoginService) sendLoginSuccessNotification(agentID string, eventData
sourceIP := eventData.IP
if s.notificationSvc != nil {
if maskIP, err := s.notificationSvc.IsMaskIPEnabled(context.Background()); err == nil && maskIP {
if maskIP, err := s.notificationSvc.IsMaskIPEnabled(ctx); err == nil && maskIP {
sourceIP = maskIPAddress(sourceIP)
}
}
+3 -3
View File
@@ -208,16 +208,16 @@ func (s *TamperService) CreateEvent(ctx context.Context, agentID string, eventDa
return err
}
s.sendTamperEventNotification(agentID, eventData)
s.sendTamperEventNotification(ctx, agentID, eventData)
return nil
}
func (s *TamperService) sendTamperEventNotification(agentID string, eventData *protocol.TamperEventData) {
func (s *TamperService) sendTamperEventNotification(ctx context.Context, agentID string, eventData *protocol.TamperEventData) {
if s.notificationSvc == nil {
return
}
agent, err := s.agentRepo.FindById(context.Background(), agentID)
agent, err := s.agentRepo.FindById(ctx, agentID)
if err != nil {
s.logger.Error("获取探针信息失败", zap.String("agentId", agentID), zap.Error(err))
return