package main import ( "context" "fmt" "net/http" "os" "os/signal" "syscall" "time" "github.com/gogenex/bridge-monitor/internal/config" "github.com/gogenex/bridge-monitor/internal/eth" "github.com/gogenex/bridge-monitor/internal/genex" "github.com/gogenex/bridge-monitor/internal/handler" "github.com/gogenex/bridge-monitor/internal/monitor" log "github.com/sirupsen/logrus" ) func main() { log.SetFormatter(&log.JSONFormatter{}) log.Info("Starting Genex Bridge Monitor...") cfg := config.Load() ethClient := eth.NewClient(cfg.EthereumRPCURL, cfg.AxelarGatewayAddress) genexClient := genex.NewClient(cfg.GenexRPCURL, cfg.GenexBridgeTokenAddress) alerter := monitor.NewAlerter(cfg.AlertWebhookURL) metrics := monitor.NewMetrics() reconciler := monitor.NewBridgeMonitor(ethClient, genexClient, alerter, metrics, cfg.DiscrepancyThreshold) // 启动定期对账 ctx, cancel := context.WithCancel(context.Background()) go func() { ticker := time.NewTicker(cfg.ReconcileInterval) defer ticker.Stop() for { select { case <-ticker.C: result, err := reconciler.Reconcile(ctx) if err != nil { log.WithError(err).Error("Reconciliation failed") } else { log.WithField("healthy", result.Healthy). WithField("ethLocked", result.EthLocked). WithField("genexMinted", result.GenexMinted). Info("Reconciliation completed") } case <-ctx.Done(): return } } }() // HTTP 服务器 router := handler.NewRouter(reconciler, metrics) srv := &http.Server{ Addr: fmt.Sprintf(":%d", cfg.Port), Handler: router, } go func() { log.Infof("Bridge Monitor HTTP server on :%d", cfg.Port) if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("Server error: %v", err) } }() // 优雅关闭 quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Info("Shutting down...") cancel() shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 10*time.Second) defer shutdownCancel() srv.Shutdown(shutdownCtx) }