package main import ( "flag" "fmt" "time" "github.com/jinzhu/gorm" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "github.com/labstack/gommon/log" "github.com/spf13/viper" "github.com/libretro/netplay-lobby-server-go/controller" "github.com/libretro/netplay-lobby-server-go/domain" "github.com/libretro/netplay-lobby-server-go/model" "github.com/libretro/netplay-lobby-server-go/model/entity" "github.com/libretro/netplay-lobby-server-go/model/repository" ) func main() { var verbose = flag.Bool("v", false, "详细日志记录") flag.Parse() server := echo.New() server.HideBanner = true server.Server.ReadTimeout = 5 * time.Second server.Server.WriteTimeout = 5 * time.Second config, err := readConfig() if err != nil { server.Logger.Fatalf("无法获取配置值: %v", err) } // 初始化领域逻辑和模型 db, err := initDatabase(config.Database.Type, config.Database.Connection) if err != nil { server.Logger.Fatalf("无法初始化数据库: %v", err) } db = db.AutoMigrate(&entity.Session{}) if *verbose { server.Logger.SetLevel(log.INFO) } else { server.Logger.SetLevel(log.WARN) } sessionDomain, err := initDomain(db, config) if err != nil { server.Logger.Fatalf("无法初始化领域逻辑: %v", err) } sessionCotroller := controller.NewSessionController(sessionDomain) // 启动清理作业以清除旧会话 go func() { for true { err := sessionDomain.PurgeOld() if err != nil { server.Logger.Fatalf("无法清除旧会话: %v", err) } time.Sleep(2 * time.Minute) } }() // 服务器设置 server.Use(middleware.Logger()) server.Use(middleware.Recover()) server.Use(middleware.BodyLimit("64K")) // 设置路由和预渲染模板 sessionCotroller.RegisterRoutes(server) templatePath := fmt.Sprintf("%s/*.html", config.Server.TemplatePath) if err = sessionCotroller.PrerenderTemplates(server, templatePath); err != nil { server.Logger.Fatalf("无法预渲染模板: %v", err) } // 开始服务 server.Logger.Fatal(server.Start(config.Server.Address)) } func readConfig() (*Config, error) { viper := viper.New() viper.SetConfigName("lobby") viper.SetConfigType("yaml") viper.AddConfigPath("/etc/lobby") viper.AddConfigPath("$HOME/.lobby") viper.AddConfigPath("./config") if err := viper.ReadInConfig(); err != nil { return nil, fmt.Errorf("无法读取配置文件: %w", err) } var conf Config if err := viper.Unmarshal(&conf); err != nil { return nil, fmt.Errorf("无法解组配置文件: %w", err) } return &conf, nil } func initDatabase(databaseType string, connectionString string) (*gorm.DB, error) { switch databaseType { case "mysql": return model.GetMysqlDB(connectionString) case "postgres": return model.GetPostgreDB(connectionString) case "sqlite": return model.GetSqliteDB(connectionString) } return nil, fmt.Errorf("配置中未知的数据库类型: %s", databaseType) } func initDomain(db *gorm.DB, config *Config) (*domain.SessionDomain, error) { repo := repository.NewSessionRepository(db) geo2Domain, err := domain.NewGeoIP2Domain(config.Server.GeoLite2Path) if err != nil { return nil, fmt.Errorf("无法初始化 GeoLite2 数据库: %w", err) } validationDomain, err := domain.NewValidationDomain(config.Blacklist.Strings, config.Blacklist.IPs) if err != nil { return nil, fmt.Errorf("无法初始化验证域: %w", err) } mitmDomain := domain.NewMitmDomain(config.Relay) sessionDomain := domain.NewSessionDomain(repo, geo2Domain, validationDomain, mitmDomain) return sessionDomain, nil }