package main import ( "fmt" "io" "log" "os" "time" "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() { // 配置日志:同时输出到文件和标准输出 logFileName := fmt.Sprintf("monitor-backend-%s.log", time.Now().Format("2006-01-02")) logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { log.Printf("Warning: Failed to open log file %s, logging only to stdout: %v", logFileName, err) } else { defer logFile.Close() // 创建一个多输出写入器,同时写入文件和标准输出 log.SetOutput(io.MultiWriter(os.Stdout, logFile)) } log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) // 加载配置 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的日志输出到文件和标准输出 ginLogger := log.New(io.MultiWriter(os.Stdout, logFile), "[GIN] ", log.Ldate|log.Ltime) r.Use(gin.LoggerWithWriter(ginLogger.Writer())) // 设置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) } }