Files
pig-farm-controller/internal/api/api.go
huang 008677467b 1. 定义Detail接口
2. 实现ListPlans接口
2025-09-10 13:41:24 +08:00

265 lines
7.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package api 提供统一的API接口层
// 负责处理所有外部请求包括HTTP和WebSocket接口
// 将请求路由到相应的服务层进行处理
package api
import (
"context"
"fmt"
"net/http"
"strings"
"time"
"git.huangwc.com/pig/pig-farm-controller/internal/api/middleware"
"git.huangwc.com/pig/pig-farm-controller/internal/config"
"git.huangwc.com/pig/pig-farm-controller/internal/controller/device"
"git.huangwc.com/pig/pig-farm-controller/internal/controller/feed"
"git.huangwc.com/pig/pig-farm-controller/internal/controller/operation"
"git.huangwc.com/pig/pig-farm-controller/internal/controller/remote"
"git.huangwc.com/pig/pig-farm-controller/internal/controller/user"
"git.huangwc.com/pig/pig-farm-controller/internal/logs"
"git.huangwc.com/pig/pig-farm-controller/internal/service"
"git.huangwc.com/pig/pig-farm-controller/internal/storage/repository"
"git.huangwc.com/pig/pig-farm-controller/internal/websocket"
"github.com/gin-gonic/gin"
)
// API 代表API接口层的结构
// 包含Gin引擎和HTTP服务器实例
type API struct {
// engine Gin引擎实例
engine *gin.Engine
// server HTTP服务器实例
server *http.Server
// config 应用配置
config *config.Config
// userController 用户控制器
userController *user.Controller
// operationController 操作历史控制器
operationController *operation.Controller
// deviceController 设备控制控制器
deviceController *device.Controller
// feedController 饲喂管理控制器
feedController *feed.Controller
// remoteController 远程控制控制器
remoteController *remote.Controller
// authMiddleware 鉴权中间件
authMiddleware *middleware.AuthMiddleware
// websocketManager WebSocket管理器
websocketManager *websocket.Manager
// heartbeatService 心跳服务
heartbeatService *service.HeartbeatService
// deviceStatusPool 设备状态池
deviceStatusPool *service.DeviceStatusPool
// logger 日志记录器
logger *logs.Logger
}
// NewAPI 创建并返回一个新的API实例
// 初始化Gin引擎和相关配置
func NewAPI(cfg *config.Config, userRepo repository.UserRepo, operationHistoryRepo repository.OperationHistoryRepo, deviceControlRepo repository.DeviceControlRepo, deviceRepo repository.DeviceRepo, websocketManager *websocket.Manager, heartbeatService *service.HeartbeatService, deviceStatusPool *service.DeviceStatusPool) *API {
// 设置Gin为发布模式
gin.SetMode(gin.DebugMode)
// 创建Gin引擎实例
engine := gin.New()
// 添加日志和恢复中间件
engine.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
return fmt.Sprintf("[API] %s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
param.ClientIP,
time.Now().Format(time.RFC3339),
param.Method,
param.Path,
param.Request.Proto,
param.StatusCode,
param.Latency,
param.Request.UserAgent(),
param.ErrorMessage,
)
}))
engine.Use(gin.Recovery())
// 创建用户控制器
userController := user.NewController(userRepo)
// 创建操作历史控制器
operationController := operation.NewController(operationHistoryRepo)
// 创建设备控制控制器
deviceController := device.NewController(deviceControlRepo, deviceRepo, websocketManager, heartbeatService, deviceStatusPool)
// 创建饲喂管理控制器
feedController := feed.NewController()
// 创建远程控制控制器
remoteController := remote.NewController(websocketManager)
// 创建鉴权中间件
authMiddleware := middleware.NewAuthMiddleware(userRepo)
return &API{
engine: engine,
config: cfg,
userController: userController,
operationController: operationController,
deviceController: deviceController,
feedController: feedController,
remoteController: remoteController,
authMiddleware: authMiddleware,
websocketManager: websocketManager,
heartbeatService: heartbeatService,
deviceStatusPool: deviceStatusPool,
logger: logs.NewLogger(),
}
}
// Start 启动HTTP服务器
func (a *API) Start() error {
// 配置路由
a.setupRoutes()
// 创建HTTP服务器
a.server = &http.Server{
Addr: fmt.Sprintf("%s:%d", a.config.Server.Host, a.config.Server.Port),
Handler: a.engine,
// 添加服务器配置
ReadTimeout: time.Duration(a.config.Server.ReadTimeout) * time.Second,
WriteTimeout: time.Duration(a.config.Server.WriteTimeout) * time.Second,
IdleTimeout: time.Duration(a.config.Server.IdleTimeout) * time.Second,
}
// 启动HTTP服务器
a.logger.Info(fmt.Sprintf("正在启动HTTP服务器 %s:%d", a.config.Server.Host, a.config.Server.Port))
go func() {
if err := a.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
a.logger.Error(fmt.Sprintf("HTTP服务器启动失败: %v", err))
}
}()
return nil
}
// Stop 停止HTTP服务器
func (a *API) Stop() error {
a.logger.Info("正在停止HTTP服务器")
// 创建一个5秒的超时上下文
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// 优雅地关闭服务器
if err := a.server.Shutdown(ctx); err != nil {
a.logger.Error(fmt.Sprintf("HTTP服务器关闭错误: %v", err))
return err
}
a.logger.Info("HTTP服务器已停止")
return nil
}
// setupRoutes 配置路由
func (a *API) setupRoutes() {
// 基础路由示例
a.engine.GET("/health", a.healthHandler)
// WebSocket路由
a.engine.GET("/ws/device", a.websocketManager.HandleConnection)
// 用户相关路由
userGroup := a.engine.Group("/api/v1/user")
{
userGroup.POST("/register", a.userController.Register)
userGroup.POST("/login", a.userController.Login)
}
// 配置静态文件服务
a.engine.Static("/assets/", "./frontend/dist/assets/")
// 使用NoRoute处理器处理前端路由
a.engine.NoRoute(func(c *gin.Context) {
path := c.Request.URL.Path
// 判断是否为API路径
if strings.HasPrefix(path, "/api/") || strings.HasPrefix(path, "/ws/") || path == "/health" {
// API路径返回404
c.JSON(http.StatusNotFound, gin.H{
"error": "API路径未找到",
})
return
}
// 对于前端路由提供index.html支持Vue Router的history模式
c.File("./frontend/dist/index.html")
})
// 需要鉴权的路由组
protectedGroup := a.engine.Group("/api/v1")
protectedGroup.Use(a.authMiddleware.Handle())
{
// 操作历史相关路由
operationGroup := protectedGroup.Group("/operation")
{
operationGroup.POST("/", a.operationController.Create)
operationGroup.GET("/list", a.operationController.ListByUser)
operationGroup.GET("/:id", a.operationController.Get)
}
// 设备控制相关路由
deviceGroup := protectedGroup.Group("/device")
{
deviceGroup.POST("/switch", a.deviceController.Switch)
deviceGroup.GET("/list", a.deviceController.List)
deviceGroup.POST("/create", a.deviceController.Create)
deviceGroup.POST("/update", a.deviceController.Update)
deviceGroup.POST("/delete", a.deviceController.Delete)
deviceGroup.GET("/status", a.deviceController.GetDeviceStatus)
}
// 饲喂相关路由
feedGroup := protectedGroup.Group("/feed")
{
feedGroup.GET("/plan/list", a.feedController.ListPlans)
feedGroup.GET("/plan/detail", a.feedController.Detail)
}
// 远程控制相关路由
remoteGroup := protectedGroup.Group("/remote")
{
remoteGroup.POST("/command", a.remoteController.SendCommand)
remoteGroup.GET("/devices", a.remoteController.ListConnectedDevices)
}
}
// TODO: 添加更多路由
}
// healthHandler 健康检查处理函数
// @Summary 健康检查
// @Description 检查API服务是否正常运行
// @Tags health
// @Accept json
// @Produce json
// @Success 200 {object} map[string]interface{}
// @Router /health [get]
func (a *API) healthHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "ok",
"message": "猪场控制器API正在运行",
})
}