161 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			7.3 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"
 | ||
| 	domain_notify "git.huangwc.com/pig/pig-farm-controller/internal/domain/notify"
 | ||
| 	"git.huangwc.com/pig/pig-farm-controller/internal/domain/scheduler"
 | ||
| 	"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/labstack/echo/v4"
 | ||
| 	"github.com/labstack/echo/v4/middleware"
 | ||
| )
 | ||
| 
 | ||
| // API 结构体定义了 HTTP 服务器及其依赖
 | ||
| type API struct {
 | ||
| 	echo                *echo.Echo                         // Echo 引擎实例,用于处理 HTTP 请求
 | ||
| 	logger              *logs.Logger                       // 日志记录器,用于输出日志信息
 | ||
| 	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 *scheduler.AnalysisPlanTaskManager // 计划触发器管理器实例
 | ||
| }
 | ||
| 
 | ||
| // NewAPI 创建并返回一个新的 API 实例
 | ||
| // 负责初始化 Echo 引擎、设置全局中间件,并注入所有必要的依赖。
 | ||
| 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,
 | ||
| 	tokenService token.Service,
 | ||
| 	auditService audit.Service,
 | ||
| 	notifyService domain_notify.Service,
 | ||
| 	deviceService domain_device.Service,
 | ||
| 	listenHandler webhook.ListenHandler,
 | ||
| 	analysisTaskManager *scheduler.AnalysisPlanTaskManager) *API {
 | ||
| 	// 使用 echo.New() 创建一个 Echo 引擎实例
 | ||
| 	e := echo.New()
 | ||
| 
 | ||
| 	// 根据配置设置 Echo 的调试模式
 | ||
| 	e.Debug = cfg.Mode == "debug"
 | ||
| 
 | ||
| 	// 添加 Echo Recovery 中间件,用于捕获 panic 并恢复,防止服务崩溃
 | ||
| 	// Echo 的 Logger 中间件默认会记录请求信息,如果需要自定义,可以替换
 | ||
| 	e.Use(middleware.Recover())
 | ||
| 
 | ||
| 	// 初始化 API 结构体
 | ||
| 	api := &API{
 | ||
| 		echo:          e,
 | ||
| 		logger:        logger,
 | ||
| 		userRepo:      userRepo,
 | ||
| 		tokenService:  tokenService,
 | ||
| 		auditService:  auditService,
 | ||
| 		config:        cfg,
 | ||
| 		listenHandler: listenHandler,
 | ||
| 		// 在 NewAPI 中初始化用户控制器,并将其作为 API 结构体的成员
 | ||
| 		userController: user.NewController(userRepo, monitorService, logger, tokenService, notifyService),
 | ||
| 		// 在 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.echo, // 将 Echo 引擎作为 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 服务器已停止。")
 | ||
| }
 |