161 lines
7.4 KiB
Go
161 lines
7.4 KiB
Go
package api
|
||
|
||
// @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
|
||
// @securityDefinitions.apikey BearerAuth
|
||
// @in header
|
||
// @name Authorization
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"net/http"
|
||
"time"
|
||
|
||
_ "git.huangwc.com/pig/pig-farm-controller/docs" // 引入 swag 生成的 docs
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/device"
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/management"
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/monitor"
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/plan"
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/app/controller/user"
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/app/service"
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/app/webhook"
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/domain/audit"
|
||
domain_device "git.huangwc.com/pig/pig-farm-controller/internal/domain/device"
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/domain/task"
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/domain/token"
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/config"
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/logs"
|
||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// API 结构体定义了 HTTP 服务器及其依赖
|
||
type API struct {
|
||
engine *gin.Engine // Gin 引擎实例,用于处理 HTTP 请求
|
||
logger *logs.Logger // 日志记录器,用于输出日志信息
|
||
userRepo repository.UserRepository // 用户数据仓库接口,用于用户数据操作
|
||
tokenService token.TokenService // 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 *task.AnalysisPlanTaskManager // 计划触发器管理器实例
|
||
}
|
||
|
||
// NewAPI 创建并返回一个新的 API 实例
|
||
// 负责初始化 Gin 引擎、设置全局中间件,并注入所有必要的依赖。
|
||
func NewAPI(cfg config.ServerConfig,
|
||
logger *logs.Logger,
|
||
userRepo repository.UserRepository,
|
||
deviceRepository repository.DeviceRepository,
|
||
areaControllerRepository repository.AreaControllerRepository,
|
||
deviceTemplateRepository repository.DeviceTemplateRepository,
|
||
planRepository repository.PlanRepository,
|
||
pigFarmService service.PigFarmService,
|
||
pigBatchService service.PigBatchService,
|
||
monitorService service.MonitorService,
|
||
userActionLogRepository repository.UserActionLogRepository,
|
||
tokenService token.TokenService,
|
||
auditService audit.Service,
|
||
deviceService domain_device.Service,
|
||
listenHandler webhook.ListenHandler,
|
||
analysisTaskManager *task.AnalysisPlanTaskManager) *API {
|
||
// 设置 Gin 模式,例如 gin.ReleaseMode (生产模式) 或 gin.DebugMode (开发模式)
|
||
// 从配置中获取 Gin 模式
|
||
gin.SetMode(cfg.Mode)
|
||
|
||
// 使用 gin.New() 创建一个 Gin 引擎实例,而不是 gin.Default()
|
||
// 这样可以手动添加所需的中间件,避免 gin.Default() 默认包含的 Logger 和 Recovery 中间件
|
||
engine := gin.New()
|
||
|
||
// 添加 Gin Recovery 中间件,用于捕获 panic 并恢复,防止服务崩溃
|
||
// gin.Logger() 已移除,因为我们使用自定义的 logger
|
||
engine.Use(gin.Recovery())
|
||
|
||
// 初始化 API 结构体
|
||
api := &API{
|
||
engine: engine,
|
||
logger: logger,
|
||
userRepo: userRepo,
|
||
tokenService: tokenService,
|
||
auditService: auditService,
|
||
config: cfg,
|
||
listenHandler: listenHandler,
|
||
// 在 NewAPI 中初始化用户控制器,并将其作为 API 结构体的成员
|
||
userController: user.NewController(userRepo, monitorService, logger, tokenService),
|
||
// 在 NewAPI 中初始化设备控制器,并将其作为 API 结构体的成员
|
||
deviceController: device.NewController(deviceRepository, areaControllerRepository, deviceTemplateRepository, deviceService, logger),
|
||
// 在 NewAPI 中初始化计划控制器,并将其作为 API 结构体的成员
|
||
planController: plan.NewController(logger, planRepository, analysisTaskManager),
|
||
// 在 NewAPI 中初始化猪场管理控制器
|
||
pigFarmController: management.NewPigFarmController(logger, pigFarmService),
|
||
// 在 NewAPI 中初始化猪群控制器
|
||
pigBatchController: management.NewPigBatchController(logger, pigBatchService),
|
||
// 在 NewAPI 中初始化数据监控控制器
|
||
monitorController: monitor.NewController(monitorService, logger),
|
||
}
|
||
|
||
api.setupRoutes() // 设置所有路由
|
||
return api
|
||
}
|
||
|
||
// Start 启动 HTTP 服务器
|
||
// 接收一个地址字符串 (例如 ":8080"),并在一个新的 goroutine 中启动服务器,
|
||
// 以便主线程可以继续执行其他任务(例如监听操作系统信号)。
|
||
func (a *API) Start() {
|
||
// 构建监听地址字符串
|
||
addr := fmt.Sprintf(":%d", a.config.Port)
|
||
|
||
// 初始化标准库的 http.Server 实例
|
||
a.httpServer = &http.Server{
|
||
Addr: addr, // 服务器监听的地址从配置中获取
|
||
Handler: a.engine, // 将 Gin 引擎作为 HTTP 请求的处理程序
|
||
}
|
||
|
||
// 在独立的 goroutine 中启动服务器
|
||
// ListenAndServe 会阻塞,所以放在 goroutine 中可以避免阻塞主线程
|
||
go func() {
|
||
// 启动服务器,并检查错误。http.ErrServerClosed 是正常关闭时的错误,无需处理。
|
||
if err := a.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||
a.logger.Fatalf("HTTP 服务器监听失败: %s", err)
|
||
}
|
||
}()
|
||
// 记录服务器已启动的信息
|
||
a.logger.Infof("HTTP 服务器正在监听 %s", addr)
|
||
}
|
||
|
||
// Stop 优雅地停止 HTTP 服务器
|
||
// 在停止服务器时,会给一个超时时间,确保正在处理的请求能够完成。
|
||
func (a *API) Stop() {
|
||
// 记录服务器正在关闭的信息
|
||
a.logger.Info("正在关闭 HTTP 服务器...")
|
||
|
||
// 创建一个带有 5 秒超时时间的上下文
|
||
// 在此时间内,服务器会尝试完成所有活跃的连接。
|
||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||
defer cancel() // 确保上下文在函数退出时被取消,释放资源
|
||
|
||
// 尝试优雅地关闭 HTTP 服务器
|
||
// 如果在超时时间内未能关闭,Shutdown 会返回错误。
|
||
if err := a.httpServer.Shutdown(ctx); err != nil {
|
||
// 如果关闭失败,记录致命错误并退出
|
||
a.logger.Fatalf("HTTP 服务器关闭失败: %s", err)
|
||
}
|
||
// 记录服务器已停止的信息
|
||
a.logger.Info("HTTP 服务器已停止。")
|
||
}
|