package main import ( "flag" "fmt" "net/http" "os" "os/signal" "super-frpc/postLog" "syscall" "time" ) type SoftwareInfo struct { Name string Version string Developer string BuildVer int16 Description string BuildType string } var softwareInfo SoftwareInfo type StatusInfo struct { Status string } var isDebug bool var isOnline bool func main() { softwareInfo = SoftwareInfo{ Name: "Super-frpc", Version: "0.0.1", Developer: "Madobi Nanami", BuildVer: 1, BuildType: "debug", } postLog.Info(fmt.Sprintf("%s %s (Build %d.%s) by %s", softwareInfo.Name, softwareInfo.Version, softwareInfo.BuildVer, softwareInfo.BuildType, softwareInfo.Developer)) configPath := flag.String("config", "./config.json", "path to config file") dbPath_data := flag.String("db", "./database.db", "path to database file") dbPath_log := flag.String("log", "./logs.db", "path to logs database file") flag.Parse() if _, err := os.Stat(*configPath); os.IsNotExist(err) { defaultConfig := `{ "listenAddr": "0.0.0.0", "listenPort": "8080", "configDir": "./configs" }` if err := os.WriteFile(*configPath, []byte(defaultConfig), 0644); err != nil { postLog.Warning(fmt.Sprintf("Failed to create default config file: %v", err)) } postLog.Info(fmt.Sprintf("Created default config file at %s", *configPath)) } config, err := LoadConfig(*configPath) if err != nil { postLog.Fatal(fmt.Sprintf("Failed to load config: %v", err)) } postLog.SetDebugMode(config.Debug) isDebug = config.Debug if err := postLog.InitLogsDatabase(*dbPath_log); err != nil { postLog.Fatal(fmt.Sprintf("Failed to initialize logs database: %v", err)) } postLog.Info("Logs database initialized successfully") if err := InitDatabase(*dbPath_data, *dbPath_log); err != nil { postLog.Fatal(fmt.Sprintf("Failed to initialize database: %v", err)) } postLog.Info("Database initialized successfully") if err := InitFrpcDatabase(*dbPath_data); err != nil { postLog.Warning(fmt.Sprintf("Failed to initialize frpc database: %v", err)) } _, err = GetConfig() if err != nil { postLog.Fatal(fmt.Sprintf("Failed to get config: %v", err)) } postLog.InitLogBroadcaster() setupRoutes() addr := fmt.Sprintf("%s:%s", config.ListenAddr, config.ListenPort) server := &http.Server{ Addr: addr, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, } go func() { postLog.Info(fmt.Sprintf("Server starting on %s", addr)) isOnline = true if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { postLog.Fatal(fmt.Sprintf("Failed to start server: %v", err)) } }() go func() { ticker := time.NewTicker(1 * time.Hour) defer ticker.Stop() for range ticker.C { CleanupExpiredTokens() CleanupExpiredSessions() } }() quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit postLog.Info("Shutting down server...") if err := server.Close(); err != nil { postLog.Error(fmt.Sprintf("Server closed with error: %v", err)) } if err := CloseDatabase(); err != nil { postLog.Error(fmt.Sprintf("Error closing database: %v", err)) } if err := CloseFrpcDatabase(); err != nil { postLog.Error(fmt.Sprintf("Error closing frpc database: %v", err)) } postLog.Info("Server stopped") } func GetStatusHandler(w http.ResponseWriter, r *http.Request) { statusInfo := StatusInfo{ Status: "Online", } if !isOnline { statusInfo.Status = "Offline" } SendSuccessResponse(w, "getStatus", statusInfo) } func GetSoftwareInfoHandler(w http.ResponseWriter, r *http.Request) { SendSuccessResponse(w, "getSoftwareInfo", softwareInfo) }