Files
sub2api/backend/cmd/server/main.go
2025-12-26 10:42:35 +08:00

146 lines
3.3 KiB
Go

package main
//go:generate go run github.com/google/wire/cmd/wire
import (
"context"
_ "embed"
"errors"
"flag"
"log"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"time"
"github.com/Wei-Shaw/sub2api/internal/config"
"github.com/Wei-Shaw/sub2api/internal/handler"
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
"github.com/Wei-Shaw/sub2api/internal/setup"
"github.com/Wei-Shaw/sub2api/internal/web"
"github.com/gin-gonic/gin"
)
//go:embed VERSION
var embeddedVersion string
// Build-time variables (can be set by ldflags)
var (
Version = ""
Commit = "unknown"
Date = "unknown"
BuildType = "source" // "source" for manual builds, "release" for CI builds (set by ldflags)
)
func init() {
// Read version from embedded VERSION file
Version = strings.TrimSpace(embeddedVersion)
if Version == "" {
Version = "0.0.0-dev"
}
}
func main() {
// Parse command line flags
setupMode := flag.Bool("setup", false, "Run setup wizard in CLI mode")
showVersion := flag.Bool("version", false, "Show version information")
flag.Parse()
if *showVersion {
log.Printf("Sub2API %s (commit: %s, built: %s)\n", Version, Commit, Date)
return
}
// CLI setup mode
if *setupMode {
if err := setup.RunCLI(); err != nil {
log.Fatalf("Setup failed: %v", err)
}
return
}
// Check if setup is needed
if setup.NeedsSetup() {
// Check if auto-setup is enabled (for Docker deployment)
if setup.AutoSetupEnabled() {
log.Println("Auto setup mode enabled...")
if err := setup.AutoSetupFromEnv(); err != nil {
log.Fatalf("Auto setup failed: %v", err)
}
// Continue to main server after auto-setup
} else {
log.Println("First run detected, starting setup wizard...")
runSetupServer()
return
}
}
// Normal server mode
runMainServer()
}
func runSetupServer() {
r := gin.New()
r.Use(middleware.Recovery())
r.Use(middleware.CORS())
// Register setup routes
setup.RegisterRoutes(r)
// Serve embedded frontend if available
if web.HasEmbeddedFrontend() {
r.Use(web.ServeEmbeddedFrontend())
}
// Get server address from config.yaml or environment variables (SERVER_HOST, SERVER_PORT)
// This allows users to run setup on a different address if needed
addr := config.GetServerAddress()
log.Printf("Setup wizard available at http://%s", addr)
log.Println("Complete the setup wizard to configure Sub2API")
if err := r.Run(addr); err != nil {
log.Fatalf("Failed to start setup server: %v", err)
}
}
func runMainServer() {
buildInfo := handler.BuildInfo{
Version: Version,
BuildType: BuildType,
}
app, err := initializeApplication(buildInfo)
if err != nil {
log.Fatalf("Failed to initialize application: %v", err)
}
defer app.Cleanup()
// 启动服务器
go func() {
if err := app.Server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("Failed to start server: %v", err)
}
}()
log.Printf("Server started on %s", app.Server.Addr)
// 等待中断信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := app.Server.Shutdown(ctx); err != nil {
log.Fatalf("Server forced to shutdown: %v", err)
}
log.Println("Server exited")
}