Files
pig-farm-controller/internal/app/api/api.go

158 lines
7.0 KiB
Go
Raw Normal View History

2025-09-12 14:39:44 +08:00
package api
2025-09-12 20:32:29 +08:00
// @title 猪场管理系统 API
// @version 1.0
// @description 这是一个用于管理猪场设备的后端服务。
// @contact.name Divano
// @contact.url http://www.example.com
// @contact.email divano@example.com
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
2025-10-13 14:15:38 +08:00
// @securityDefinitions.apikey BearerAuth
// @in header
// @name Authorization
2025-09-12 14:39:44 +08:00
import (
"context"
"fmt"
"net/http"
"time"
2025-09-27 23:17:23 +08:00
_ "git.huangwc.com/pig/pig-farm-controller/docs" // 引入 swag 生成的 docs
2025-09-12 17:18:14 +08:00
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/device"
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/management"
2025-10-19 20:24:01 +08:00
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/monitor"
2025-09-13 14:09:22 +08:00
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/plan"
2025-09-12 14:39:44 +08:00
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/user"
"git.huangwc.com/pig/pig-farm-controller/internal/app/service"
2025-10-02 00:18:13 +08:00
"git.huangwc.com/pig/pig-farm-controller/internal/app/webhook"
"git.huangwc.com/pig/pig-farm-controller/internal/domain/audit"
2025-11-02 18:16:44 +08:00
domain_plan "git.huangwc.com/pig/pig-farm-controller/internal/domain/plan"
2025-10-02 00:18:13 +08:00
"git.huangwc.com/pig/pig-farm-controller/internal/domain/token"
2025-09-12 16:58:39 +08:00
"git.huangwc.com/pig/pig-farm-controller/internal/infra/config"
2025-09-12 14:39:44 +08:00
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
2025-09-12 14:39:44 +08:00
)
// API 结构体定义了 HTTP 服务器及其依赖
type API struct {
2025-11-02 18:16:44 +08:00
echo *echo.Echo // Echo 引擎实例,用于处理 HTTP 请求
2025-11-05 16:10:46 +08:00
Ctx context.Context // API 组件的上下文,包含日志记录器
2025-11-02 18:16:44 +08:00
userRepo repository.UserRepository // 用户数据仓库接口,用于用户数据操作
tokenService token.Service // Token 服务接口,用于 JWT token 的生成和解析
auditService audit.Service // 审计服务,用于记录用户操作
httpServer *http.Server // 标准库的 HTTP 服务器实例,用于启动和停止服务
config config.ServerConfig // API 服务器的配置,使用 infra/config 包中的 ServerConfig
userController *user.Controller // 用户控制器实例
deviceController *device.Controller // 设备控制器实例
planController *plan.Controller // 计划控制器实例
pigFarmController *management.PigFarmController // 猪场管理控制器实例
pigBatchController *management.PigBatchController // 猪群控制器实例
monitorController *monitor.Controller // 数据监控控制器实例
listenHandler webhook.ListenHandler // 设备上行事件监听器
analysisTaskManager *domain_plan.AnalysisPlanTaskManager // 计划触发器管理器实例
2025-09-12 14:39:44 +08:00
}
// NewAPI 创建并返回一个新的 API 实例
// 负责初始化 Echo 引擎、设置全局中间件,并注入所有必要的依赖。
func NewAPI(cfg config.ServerConfig,
2025-11-05 16:10:46 +08:00
ctx context.Context,
userRepo repository.UserRepository,
pigFarmService service.PigFarmService,
2025-10-13 10:39:51 +08:00
pigBatchService service.PigBatchService,
2025-10-19 20:24:01 +08:00
monitorService service.MonitorService,
2025-10-31 16:00:55 +08:00
deviceService service.DeviceService,
2025-10-31 16:28:26 +08:00
planService service.PlanService,
2025-10-31 16:49:35 +08:00
userService service.UserService,
2025-10-26 15:48:38 +08:00
tokenService token.Service,
2025-10-13 10:39:51 +08:00
auditService audit.Service,
2025-10-02 00:18:13 +08:00
listenHandler webhook.ListenHandler,
2025-10-31 16:28:26 +08:00
) *API {
// 使用 echo.New() 创建一个 Echo 引擎实例
e := echo.New()
2025-09-12 14:39:44 +08:00
// 根据配置设置 Echo 的调试模式
e.Debug = cfg.Mode == "debug"
2025-09-12 14:39:44 +08:00
// 添加 Echo Recovery 中间件,用于捕获 panic 并恢复,防止服务崩溃
// Echo 的 Logger 中间件默认会记录请求信息,如果需要自定义,可以替换
e.Use(middleware.Recover())
2025-09-12 14:39:44 +08:00
// 初始化 API 结构体
2025-11-05 16:10:46 +08:00
baseCtx := context.Background()
2025-09-12 14:39:44 +08:00
api := &API{
echo: e,
2025-11-05 16:10:46 +08:00
Ctx: ctx,
2025-09-15 22:01:00 +08:00
userRepo: userRepo,
tokenService: tokenService,
2025-09-28 00:13:47 +08:00
auditService: auditService,
2025-09-15 22:01:00 +08:00
config: cfg,
listenHandler: listenHandler,
2025-09-12 14:39:44 +08:00
// 在 NewAPI 中初始化用户控制器,并将其作为 API 结构体的成员
2025-11-05 17:24:19 +08:00
userController: user.NewController(baseCtx, userService),
2025-09-12 17:18:14 +08:00
// 在 NewAPI 中初始化设备控制器,并将其作为 API 结构体的成员
2025-11-05 17:24:19 +08:00
deviceController: device.NewController(baseCtx, deviceService),
2025-09-13 14:09:22 +08:00
// 在 NewAPI 中初始化计划控制器,并将其作为 API 结构体的成员
2025-11-05 16:10:46 +08:00
planController: plan.NewController(baseCtx, planService),
// 在 NewAPI 中初始化猪场管理控制器
2025-11-05 16:10:46 +08:00
pigFarmController: management.NewPigFarmController(baseCtx, pigFarmService),
2025-10-07 13:31:56 +08:00
// 在 NewAPI 中初始化猪群控制器
2025-11-05 16:10:46 +08:00
pigBatchController: management.NewPigBatchController(baseCtx, pigBatchService),
2025-10-19 20:24:01 +08:00
// 在 NewAPI 中初始化数据监控控制器
2025-11-05 17:24:19 +08:00
monitorController: monitor.NewController(baseCtx, monitorService),
2025-09-12 14:39:44 +08:00
}
api.setupRoutes() // 设置所有路由
return api
}
// Start 启动 HTTP 服务器
// 接收一个地址字符串 (例如 ":8080"),并在一个新的 goroutine 中启动服务器,
// 以便主线程可以继续执行其他任务(例如监听操作系统信号)。
func (a *API) Start() {
2025-11-05 16:10:46 +08:00
logger := logs.TraceLogger(a.Ctx, a.Ctx, "Start")
2025-09-12 14:39:44 +08:00
// 构建监听地址字符串
addr := fmt.Sprintf(":%d", a.config.Port)
// 初始化标准库的 http.Server 实例
a.httpServer = &http.Server{
Addr: addr, // 服务器监听的地址从配置中获取
Handler: a.echo, // 将 Echo 引擎作为 HTTP 请求的处理程序
2025-09-12 14:39:44 +08:00
}
// 在独立的 goroutine 中启动服务器
// ListenAndServe 会阻塞,所以放在 goroutine 中可以避免阻塞主线程
go func() {
// 启动服务器并检查错误。http.ErrServerClosed 是正常关闭时的错误,无需处理。
if err := a.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
2025-11-05 16:10:46 +08:00
logger.Fatalf("HTTP 服务器监听失败: %s", err)
2025-09-12 14:39:44 +08:00
}
}()
// 记录服务器已启动的信息
2025-11-05 16:10:46 +08:00
logger.Infof("HTTP 服务器正在监听 %s", addr)
2025-09-12 14:39:44 +08:00
}
// Stop 优雅地停止 HTTP 服务器
// 在停止服务器时,会给一个超时时间,确保正在处理的请求能够完成。
func (a *API) Stop() {
2025-11-05 16:10:46 +08:00
logger := logs.TraceLogger(a.Ctx, a.Ctx, "Stop")
2025-09-12 14:39:44 +08:00
// 记录服务器正在关闭的信息
2025-11-05 16:10:46 +08:00
logger.Info("正在关闭 HTTP 服务器...")
2025-09-12 14:39:44 +08:00
// 创建一个带有 5 秒超时时间的上下文
// 在此时间内,服务器会尝试完成所有活跃的连接。
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() // 确保上下文在函数退出时被取消,释放资源
// 尝试优雅地关闭 HTTP 服务器
// 如果在超时时间内未能关闭Shutdown 会返回错误。
if err := a.httpServer.Shutdown(ctx); err != nil {
// 如果关闭失败,记录致命错误并退出
2025-11-05 16:10:46 +08:00
logger.Fatalf("HTTP 服务器关闭失败: %s", err)
2025-09-12 14:39:44 +08:00
}
// 记录服务器已停止的信息
2025-11-05 16:10:46 +08:00
logger.Info("HTTP 服务器已停止。")
2025-09-12 14:39:44 +08:00
}