Files
monitor/backend/main.go
2025-12-05 00:03:44 +08:00

167 lines
4.5 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 main
import (
"fmt"
"log"
"os"
"github.com/gin-gonic/gin"
"github.com/monitor/backend/config"
"github.com/monitor/backend/internal/db"
"github.com/monitor/backend/internal/device"
"github.com/monitor/backend/internal/handler"
"github.com/monitor/backend/internal/storage"
)
// 检查配置文件是否存在
func configFileExists() bool {
configFile := os.Getenv("SERVER_CONFIG_FILE")
if configFile == "" {
configFile = "./config.json"
}
_, err := os.Stat(configFile)
return err == nil
}
// 检查数据库配置是否为默认值
func isDefaultDBConfig(cfg *config.Config) bool {
return cfg.DB.Host == "localhost" &&
cfg.DB.Port == 3306 &&
cfg.DB.Username == "root" &&
cfg.DB.Password == "" &&
cfg.DB.Database == "monitor"
}
// main 函数启动服务器
func main() {
// 配置日志:只输出必要的信息,禁用调试日志
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
log.SetOutput(os.Stdout)
// 加载配置
cfg, err := config.LoadConfig()
if err != nil {
log.Fatalf("Failed to load config: %v", err)
}
// 检查配置文件是否存在
if !configFileExists() {
// 生成配置文件
if err := config.SaveConfig(cfg); err != nil {
log.Fatalf("Failed to generate config file: %v", err)
}
// 退出并提示用户配置
fmt.Println("配置文件已生成, 请进行配置然后启动服务.")
os.Exit(0)
}
// 检查数据库配置是否为默认值
if isDefaultDBConfig(cfg) {
// 退出并提示用户配置
fmt.Println("检测到数据库为默认配置, 请进行配置然后启动服务.")
os.Exit(0)
}
// 创建存储实例
store := storage.NewStorage(cfg)
defer store.Close()
// 初始化数据库连接(内部使用,不对外暴露)
dbConfig := db.Config{
Type: cfg.DB.Type,
Host: cfg.DB.Host,
Port: cfg.DB.Port,
Username: cfg.DB.Username,
Password: cfg.DB.Password,
Database: cfg.DB.Database,
SSLMode: cfg.DB.SSLMode,
Charset: cfg.DB.Charset,
}
// 尝试连接数据库,如果连接失败,只记录警告,不影响服务器启动
database, err := db.NewDB(dbConfig)
if err != nil {
log.Printf("Warning: Failed to connect to database: %v", err)
log.Printf("Server will continue without database connection")
} else {
defer database.Close()
log.Printf("Database connection initialized successfully")
// 这里可以将database传递给需要使用的组件
// 例如handler.SetDB(database)
}
// 创建Gin引擎禁用调试模式
gin.SetMode(gin.ReleaseMode)
r := gin.New()
// 添加必要的中间件
r.Use(gin.Recovery())
// 禁用Gin的默认日志
r.Use(gin.LoggerWithWriter(gin.DefaultWriter, "/health"))
// 设置CORS
r.Use(func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
})
// 设置全局存储实例
handler.SetStorage(store)
// 初始化设备存储实例
var deviceStore device.Storage
if database != nil {
// 使用MySQL存储
mysqlStore, err := device.NewMySQLStorage(database.GetDB())
if err != nil {
log.Printf("Warning: Failed to create MySQL device storage: %v", err)
// 回退到内存存储
deviceStore = device.NewMemoryStorage()
} else {
log.Printf("MySQL device storage initialized successfully")
deviceStore = mysqlStore
}
} else {
// 使用内存存储
deviceStore = device.NewMemoryStorage()
log.Printf("Using in-memory device storage")
}
handler.SetDeviceStorage(deviceStore)
// 配置静态文件服务
// 从backend/static目录提供静态文件
// 先注册API路由再处理静态文件避免路由冲突
// 注册API路由
handler.RegisterRoutes(r)
// 处理所有未匹配的路由返回静态文件或index.html
r.NoRoute(func(c *gin.Context) {
// 尝试提供静态文件
file := c.Request.URL.Path
if file == "/" {
file = "/index.html"
}
// 从static目录提供文件
c.File("./static" + file)
})
// 启动服务器
addr := fmt.Sprintf(":%d", cfg.Server.Port)
log.Printf("Server starting on %s", addr)
log.Printf("Static files served from ./static")
if err := r.Run(addr); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
}