mirror of
https://github.com//cppla/ServerStatus
synced 2026-08-06 11:13:56 +08:00
1.2.0
This commit is contained in:
+138
@@ -0,0 +1,138 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var opts Options
|
||||
var legacyBind string
|
||||
var legacyPort int
|
||||
var printVersion bool
|
||||
|
||||
flag.StringVar(&opts.ConfigPath, "config", envOr("CONFIG_PATH", "config.json"), "configuration file")
|
||||
flag.StringVar(&opts.ConfigPath, "c", envOr("CONFIG_PATH", "config.json"), "configuration file (shorthand)")
|
||||
flag.StringVar(&opts.StatsPath, "stats", os.Getenv("STATS_PATH"), "persistent stats JSON file")
|
||||
flag.StringVar(&opts.WebDir, "web-dir", envOr("WEB_DIR", "../web"), "WebUI directory")
|
||||
flag.StringVar(&opts.WebDir, "d", envOr("WEB_DIR", "../web"), "WebUI directory (shorthand)")
|
||||
flag.StringVar(&opts.HTTPAddr, "http", envOr("HTTP_ADDR", ":8080"), "HTTP listen address")
|
||||
flag.StringVar(&opts.AgentAddr, "agent", envOr("AGENT_ADDR", ":35601"), "agent TCP listen address")
|
||||
flag.StringVar(&legacyBind, "bind", "", "agent bind address (legacy compatibility)")
|
||||
flag.StringVar(&legacyBind, "b", "", "agent bind address (legacy shorthand)")
|
||||
flag.IntVar(&legacyPort, "port", 0, "agent TCP port (legacy compatibility)")
|
||||
flag.IntVar(&legacyPort, "p", 0, "agent TCP port (legacy shorthand)")
|
||||
flag.BoolVar(&opts.Verbose, "verbose", envBool("VERBOSE", false), "verbose HTTP logging")
|
||||
flag.BoolVar(&opts.Verbose, "v", envBool("VERBOSE", false), "verbose HTTP logging (shorthand)")
|
||||
flag.BoolVar(&printVersion, "version", false, "print version and exit")
|
||||
flag.Parse()
|
||||
|
||||
if printVersion {
|
||||
fmt.Printf("serverstatus %s commit=%s built=%s\n", version, commit, buildTime)
|
||||
return
|
||||
}
|
||||
if opts.StatsPath == "" {
|
||||
opts.StatsPath = filepath.Join(opts.WebDir, "json", "stats.json")
|
||||
}
|
||||
if legacyPort != 0 || legacyBind != "" {
|
||||
if legacyPort == 0 {
|
||||
legacyPort = 35601
|
||||
}
|
||||
opts.AgentAddr = net.JoinHostPort(legacyBind, strconv.Itoa(legacyPort))
|
||||
}
|
||||
opts.AdminToken = os.Getenv("ADMIN_TOKEN")
|
||||
opts.CORSOrigin = os.Getenv("ADMIN_CORS_ORIGIN")
|
||||
opts.InsecureCallbackTLS = envBool("INSECURE_CALLBACK_TLS", false)
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(opts.StatsPath), 0o755); err != nil {
|
||||
fatalf("create stats directory: %v", err)
|
||||
}
|
||||
app, err := NewApp(opts)
|
||||
if err != nil {
|
||||
fatalf("start: %v", err)
|
||||
}
|
||||
app.StartBackground()
|
||||
|
||||
httpServer := app.HTTPServer()
|
||||
agentServer := NewAgentServer(app)
|
||||
errorsChannel := make(chan error, 2)
|
||||
go func() {
|
||||
app.logger.Printf("HTTP listening on %s", opts.HTTPAddr)
|
||||
if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
errorsChannel <- fmt.Errorf("HTTP server: %w", err)
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
if err := agentServer.ListenAndServe(); err != nil {
|
||||
errorsChannel <- fmt.Errorf("agent server: %w", err)
|
||||
}
|
||||
}()
|
||||
|
||||
reloadSignals := make(chan os.Signal, 1)
|
||||
stopSignals := make(chan os.Signal, 1)
|
||||
signal.Notify(reloadSignals, syscall.SIGHUP)
|
||||
signal.Notify(stopSignals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||
defer signal.Stop(reloadSignals)
|
||||
defer signal.Stop(stopSignals)
|
||||
|
||||
go func() {
|
||||
for range reloadSignals {
|
||||
if apiErr := app.ReloadConfig(); apiErr != nil {
|
||||
app.logger.Printf("reload config: %s", apiErr.Message)
|
||||
continue
|
||||
}
|
||||
app.logger.Printf("configuration reloaded; generation=%d", app.generation.Load())
|
||||
}
|
||||
}()
|
||||
|
||||
var fatalErr error
|
||||
select {
|
||||
case signalValue := <-stopSignals:
|
||||
app.logger.Printf("received %s; shutting down", signalValue)
|
||||
case fatalErr = <-errorsChannel:
|
||||
app.logger.Printf("fatal: %v", fatalErr)
|
||||
}
|
||||
app.cancel()
|
||||
shutdownContext, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
_ = httpServer.Shutdown(shutdownContext)
|
||||
cancel()
|
||||
app.Close()
|
||||
if fatalErr != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func envOr(name, fallback string) string {
|
||||
if value := strings.TrimSpace(os.Getenv(name)); value != "" {
|
||||
return value
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func envBool(name string, fallback bool) bool {
|
||||
value := strings.TrimSpace(os.Getenv(name))
|
||||
if value == "" {
|
||||
return fallback
|
||||
}
|
||||
parsed, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return fallback
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
func fatalf(format string, args ...any) {
|
||||
fmt.Fprintf(os.Stderr, "serverstatus: "+format+"\n", args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
Reference in New Issue
Block a user