package main import ( "context" "log" "net/http" "os" "os/signal" "strings" "syscall" "time" "evobgp/internal/birdfmt" "evobgp/internal/config" "evobgp/internal/httpapi" "evobgp/internal/observability" "evobgp/internal/platform" ) func main() { cfg := config.Load() seedDemo := os.Getenv("EVOBGP_SEED_DEMO") != "0" opts := httpapi.Options{ APIKeys: os.Getenv("EVOBGP_API_KEYS"), DatabaseURL: cfg.DatabaseURL, InsecureDev: os.Getenv("EVOBGP_DEV_INSECURE") == "1", SeedDemo: seedDemo, BundleSeedHex: strings.TrimSpace(os.Getenv("EVOBGP_BUNDLE_SEED_HEX")), CORSAllowedOrigins: strings.TrimSpace(os.Getenv("EVOBGP_CORS_ORIGINS")), } srv, err := httpapi.New(opts) if err != nil { log.Fatal(err) } defer srv.Close() observability.SetBuildInfo("0.1.0", strings.TrimSpace(os.Getenv("EVOBGP_GIT_SHA"))) startBirdMetricsPoller() ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() httpSrv := &http.Server{ Addr: cfg.HTTPAddr, Handler: srv.Handler(), } go func() { svc := platform.ServiceName("evobgp-api") log.Printf("%s listening on %s", svc, cfg.HTTPAddr) log.Printf("bundle signing public key (base64, set on evobgp-node): %s", srv.BundlePublicKeyBase64()) if opts.SeedDemo { tid, mCDN, mIP, rev, sp := srv.Store().DemoIDs() log.Printf("demo tenant=%s module_cdn=%s module_ip_ranges=%s revision=%s speaker=%s", tid, mCDN, mIP, rev, sp) log.Printf("example: EVOBGP_API_KEYS=op|%s|operator,node|%s|node", tid, tid) log.Printf("with EVOBGP_DEV_INSECURE=1 use Authorization: Bearer dev (operator, demo tenant only)") } if err := httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatal(err) } }() <-ctx.Done() shutdownCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() if err := httpSrv.Shutdown(shutdownCtx); err != nil { log.Printf("HTTP shutdown: %v", err) } log.Printf("%s stopped", platform.ServiceName("evobgp-api")) } func startBirdMetricsPoller() { sock := strings.TrimSpace(os.Getenv("EVOBGP_BIRDC_SOCKET")) if sock == "" { return } interval := 30 * time.Second if d, err := time.ParseDuration(strings.TrimSpace(os.Getenv("EVOBGP_BIRDC_INTERVAL"))); err == nil && d > 0 { interval = d } bin := strings.TrimSpace(os.Getenv("EVOBGP_BIRDC_BIN")) observability.StartBirdProtocolsPoller(sock, bin, interval, func(ctx context.Context, socket, birdcBin string) (string, error) { return birdfmt.ShowProtocols(ctx, socket, birdcBin) }, birdfmt.CountEstablishedBGPSessions, ) log.Printf("birdc protocols poller enabled (socket=%s interval=%s)", sock, interval) }