package bootstrap import ( "context" "fmt" "time" "go.uber.org/zap" edgeevents "iop/apps/edge/internal/events" edgeinput "iop/apps/edge/internal/input" edgenode "iop/apps/edge/internal/node" edgeservice "iop/apps/edge/internal/service" "iop/apps/edge/internal/transport" "iop/packages/config" "iop/packages/observability" ) // Runtime is the shared edge runtime assembly used by both `serve` and // `console` entrypoints. NewRuntime wires logger, registry, node store, // event bus, service, and transport server; Start performs handler wiring // and binds the server and metrics endpoint. type Runtime struct { Cfg *config.EdgeConfig Logger *zap.Logger Registry *edgenode.Registry NodeStore *edgenode.NodeStore EventBus *edgeevents.Bus Service *edgeservice.Service Server *transport.Server Input *edgeinput.Manager } func NewRuntime(cfg *config.EdgeConfig) (*Runtime, error) { logger, err := observability.NewLogger(cfg.Logging.Level, cfg.Logging.Pretty) if err != nil { return nil, err } registry := edgenode.NewRegistry() nodeStore, err := edgenode.LoadFromConfig(cfg.Nodes) if err != nil { return nil, fmt.Errorf("edge: seed node store: %w", err) } bus := edgeevents.NewBus() svc := edgeservice.New(registry, bus) inputManager := edgeinput.NewManager(*cfg, svc, logger.Named("input")) server, err := transport.NewServer(cfg.Server.Listen, registry, nodeStore, logger) if err != nil { return nil, err } return &Runtime{ Cfg: cfg, Logger: logger, Registry: registry, NodeStore: nodeStore, EventBus: bus, Service: svc, Server: server, Input: inputManager, }, nil } func (r *Runtime) wireHandlers() { r.Server.SetRunEventHandler(r.EventBus.PublishRun) r.Server.SetNodeEventHandler(r.EventBus.PublishNode) } func (r *Runtime) Start(ctx context.Context) error { r.wireHandlers() if err := r.Server.Start(ctx); err != nil { return err } if err := r.Input.Start(ctx); err != nil { _ = r.Server.Stop() return err } go func() { if err := observability.ServeMetrics(r.Cfg.Metrics.Port); err != nil { r.Logger.Warn("metrics server exited", zap.Error(err)) } }() return nil } func (r *Runtime) Stop() error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() inputErr := r.Input.Stop(ctx) err := r.Server.Stop() _ = r.Logger.Sync() if err == nil { err = inputErr } return err }