diff --git a/plugins/analysis/webinterface/httpserver/plugin.go b/plugins/analysis/webinterface/httpserver/plugin.go index d32d9d3dbdcae12e7805c0350288da7ecb703d1d..2837fa8b91b5b295d13951df07dc92ffd5b945e7 100644 --- a/plugins/analysis/webinterface/httpserver/plugin.go +++ b/plugins/analysis/webinterface/httpserver/plugin.go @@ -20,16 +20,18 @@ var ( engine *echo.Echo ) -const name = "Analysis HTTP Server" +// PluginName is the name of the analysis server plugin. +const PluginName = "Analysis HTTP Server" var assetsBox = packr.New("Assets", "./static") // Configure configures the plugin. func Configure() { - log = logger.NewLogger(name) + log = logger.NewLogger(PluginName) engine = echo.New() engine.HideBanner = true + engine.HidePort = true // we only need this special flag, because we always keep a packed box in the same directory if config.Node.GetBool(CfgDev) { @@ -47,17 +49,19 @@ func Configure() { // Run runs the plugin. func Run() { - log.Infof("Starting %s ...", name) - if err := daemon.BackgroundWorker(name, start, shutdown.PriorityAnalysis); err != nil { + log.Infof("Starting %s ...", PluginName) + if err := daemon.BackgroundWorker(PluginName, worker, shutdown.PriorityAnalysis); err != nil { log.Errorf("Error starting as daemon: %s", err) } } -func start(shutdownSignal <-chan struct{}) { +func worker(shutdownSignal <-chan struct{}) { + defer log.Infof("Stopping %s ... done", PluginName) + stopped := make(chan struct{}) bindAddr := config.Node.GetString(CfgBindAddress) go func() { - log.Infof("Started %s: http://%s", name, bindAddr) + log.Infof("Started %s: http://%s", PluginName, bindAddr) if err := engine.Start(bindAddr); err != nil { if !errors.Is(err, http.ErrServerClosed) { log.Errorf("Error serving: %s", err) @@ -66,19 +70,18 @@ func start(shutdownSignal <-chan struct{}) { } }() + // stop if we are shutting down or the server could not be started select { case <-shutdownSignal: case <-stopped: } - log.Infof("Stopping %s ...", name) + log.Infof("Stopping %s ...", PluginName) ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() - if err := engine.Shutdown(ctx); err != nil { log.Errorf("Error stopping: %s", err) } - log.Info("Stopping %s ... done", name) } func index(e echo.Context) error { diff --git a/plugins/dashboard/plugin.go b/plugins/dashboard/plugin.go index b2b8e09f2a997ec62e7c0ce375daf7cd8265a60b..a64762776a7b7ff5ee34f6981d9e3b0beb18ca79 100644 --- a/plugins/dashboard/plugin.go +++ b/plugins/dashboard/plugin.go @@ -1,6 +1,8 @@ package dashboard import ( + "context" + "errors" "net" "net/http" "runtime" @@ -34,7 +36,9 @@ const PluginName = "Dashboard" var ( // Plugin is the plugin instance of the dashboard plugin. Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + log *logger.Logger + server *echo.Echo nodeStartAt = time.Now() @@ -60,54 +64,79 @@ func configure(plugin *node.Plugin) { configureLiveFeed() configureDrngLiveFeed() + + configureServer() } -func run(plugin *node.Plugin) { - notifyStatus := events.NewClosure(func(mps uint64) { - wsSendWorkerPool.TrySubmit(mps) - }) - - daemon.BackgroundWorker("Dashboard[WSSend]", func(shutdownSignal <-chan struct{}) { - metrics.Events.ReceivedMPSUpdated.Attach(notifyStatus) - wsSendWorkerPool.Start() - <-shutdownSignal - log.Info("Stopping Dashboard[WSSend] ...") - metrics.Events.ReceivedMPSUpdated.Detach(notifyStatus) - wsSendWorkerPool.Stop() - log.Info("Stopping Dashboard[WSSend] ... done") - }, shutdown.PriorityDashboard) +func configureServer() { + server = echo.New() + server.HideBanner = true + server.HidePort = true + server.Use(middleware.Recover()) - runLiveFeed() + if config.Node.GetBool(CfgBasicAuthEnabled) { + server.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) { + if username == config.Node.GetString(CfgBasicAuthUsername) && + password == config.Node.GetString(CfgBasicAuthPassword) { + return true, nil + } + return false, nil + })) + } + + setupRoutes(server) +} +func run(*node.Plugin) { + // rune the message live feed + runLiveFeed() // run dRNG live feed if dRNG plugin is enabled if !node.IsSkipped(drng.Plugin) { runDrngLiveFeed() } - // allow any origin for websocket connections - upgrader.CheckOrigin = func(r *http.Request) bool { - return true + log.Infof("Starting %s ...", PluginName) + if err := daemon.BackgroundWorker(PluginName, worker, shutdown.PriorityAnalysis); err != nil { + log.Errorf("Error starting as daemon: %s", err) } +} - e := echo.New() - e.HideBanner = true - e.Use(middleware.Recover()) - - if config.Node.GetBool(CfgBasicAuthEnabled) { - e.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) { - if username == config.Node.GetString(CfgBasicAuthUsername) && - password == config.Node.GetString(CfgBasicAuthPassword) { - return true, nil +func worker(shutdownSignal <-chan struct{}) { + defer log.Infof("Stopping %s ... done", PluginName) + + // start the web socket worker pool + wsSendWorkerPool.Start() + defer wsSendWorkerPool.Stop() + + // submit the mps to the worker pool when triggered + notifyStatus := events.NewClosure(func(mps uint64) { wsSendWorkerPool.TrySubmit(mps) }) + metrics.Events.ReceivedMPSUpdated.Attach(notifyStatus) + defer metrics.Events.ReceivedMPSUpdated.Detach(notifyStatus) + + stopped := make(chan struct{}) + bindAddr := config.Node.GetString(CfgBindAddress) + go func() { + log.Infof("Started %s: http://%s", PluginName, bindAddr) + if err := server.Start(bindAddr); err != nil { + if !errors.Is(err, http.ErrServerClosed) { + log.Errorf("Error serving: %s", err) } - return false, nil - })) - } + close(stopped) + } + }() - setupRoutes(e) - addr := config.Node.GetString(CfgBindAddress) + // stop if we are shutting down or the server could not be started + select { + case <-shutdownSignal: + case <-stopped: + } - log.Infof("You can now access the dashboard using: http://%s", addr) - go e.Start(addr) + log.Infof("Stopping %s ...", PluginName) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + if err := server.Shutdown(ctx); err != nil { + log.Errorf("Error stopping: %s", err) + } } // sends the given message to all connected websocket clients @@ -128,6 +157,7 @@ var webSocketWriteTimeout = time.Duration(3) * time.Second var ( upgrader = websocket.Upgrader{ HandshakeTimeout: webSocketWriteTimeout, + CheckOrigin: func(r *http.Request) bool { return true }, EnableCompression: true, } ) @@ -195,7 +225,7 @@ type neighbormetric struct { } func neighborMetrics() []neighbormetric { - stats := []neighbormetric{} + var stats []neighbormetric // gossip plugin might be disabled neighbors := gossip.Manager().AllNeighbors() diff --git a/plugins/webapi/plugin.go b/plugins/webapi/plugin.go index 24f5108febcb0ff0f959bf11f436095b2b07b50b..8e9944ba047c342accba6e75ee9b011556db8699 100644 --- a/plugins/webapi/plugin.go +++ b/plugins/webapi/plugin.go @@ -2,6 +2,8 @@ package webapi import ( "context" + "errors" + "net/http" "time" "github.com/iotaledger/goshimmer/packages/shutdown" @@ -18,38 +20,52 @@ const PluginName = "WebAPI" var ( // Plugin is the plugin instance of the web API plugin. Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) - log *logger.Logger // Server is the web API server. Server = echo.New() + + log *logger.Logger ) -func configure(plugin *node.Plugin) { +func configure(*node.Plugin) { log = logger.NewLogger(PluginName) + // configure the server Server.HideBanner = true Server.HidePort = true Server.GET("/", IndexRequest) } -func run(plugin *node.Plugin) { - log.Info("Starting Web Server ...") +func run(*node.Plugin) { + log.Infof("Starting %s ...", PluginName) + if err := daemon.BackgroundWorker("WebAPI Server", worker, shutdown.PriorityWebAPI); err != nil { + log.Errorf("Error starting as daemon: %s", err) + } +} - daemon.BackgroundWorker("WebAPI Server", func(shutdownSignal <-chan struct{}) { - log.Info("Starting Web Server ... done") +func worker(shutdownSignal <-chan struct{}) { + defer log.Infof("Stopping %s ... done", PluginName) - go func() { - if err := Server.Start(config.Node.GetString(CfgBindAddress)); err != nil { - log.Info("Stopping Web Server ... done") + stopped := make(chan struct{}) + bindAddr := config.Node.GetString(CfgBindAddress) + go func() { + log.Infof("Started %s: http://%s", PluginName, bindAddr) + if err := Server.Start(bindAddr); err != nil { + if !errors.Is(err, http.ErrServerClosed) { + log.Errorf("Error serving: %s", err) } - }() - - <-shutdownSignal + close(stopped) + } + }() - log.Info("Stopping Web Server ...") - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() + // stop if we are shutting down or the server could not be started + select { + case <-shutdownSignal: + case <-stopped: + } - if err := Server.Shutdown(ctx); err != nil { - log.Errorf("Couldn't stop server cleanly: %s", err.Error()) - } - }, shutdown.PriorityWebAPI) + log.Infof("Stopping %s ...", PluginName) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + if err := Server.Shutdown(ctx); err != nil { + log.Errorf("Error stopping: %s", err) + } }