// Package cli 命令行入口。 package cli import ( "context" "errors" "log" "net/http" "os" "os/signal" "strconv" "syscall" "time" "github.com/openteam/server/internal/api" "github.com/openteam/server/internal/app" "github.com/openteam/server/internal/config" "github.com/openteam/server/internal/proxy" ) // serve 启动 HTTP 服务(默认子命令)。 func serve() error { cfg, err := config.Load() if err != nil { return err } a, err := app.New(cfg) if err != nil { return err } defer a.Shutdown(context.Background()) gw := proxy.NewGateway(a.DB, a.Enc, a.Usage, a.Limit, cfg.RateLimit.UserRPS, cfg.Proxy.LogRaw) router := api.NewRouter(a, gw) srv := &http.Server{ Addr: ":" + strconv.Itoa(cfg.Port), Handler: router, ReadHeaderTimeout: 10 * time.Second, } go func() { log.Printf("openteam listening on %s (env=%s)", srv.Addr, cfg.Env) if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Fatalf("server: %v", err) } }() quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Println("shutting down...") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Printf("server shutdown: %v", err) } a.Usage.Close() return nil }