Skip to content
Snippets Groups Projects
plugin.go 2.71 KiB
package dashboard

import (
	"context"
	"errors"
	"net/http"
	"time"

	"github.com/iotaledger/goshimmer/packages/shutdown"
	"github.com/iotaledger/goshimmer/plugins/config"
	"github.com/iotaledger/hive.go/daemon"
	"github.com/iotaledger/hive.go/logger"
	"github.com/iotaledger/hive.go/node"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

// PluginName is the name of the dashboard plugin.
const PluginName = "Analysis-Dashboard"

var (
	// Plugin is the plugin instance of the dashboard plugin.
	Plugin = node.NewPlugin(PluginName, node.Disabled, configure, run)

	log    *logger.Logger
	server *echo.Echo
)

func configure(plugin *node.Plugin) {
	log = logger.NewLogger(plugin.Name)
	configureFPCLiveFeed()
	configureAutopeeringWorkerPool()
	configureEventsRecording()
	configureServer()
}

func configureServer() {
	server = echo.New()
	server.HideBanner = true
	server.HidePort = true
	server.Use(middleware.Recover())

	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) {
	// run FPC stat reporting
	runFPCLiveFeed()
	// run data reporting for autopeering visualizer
	runAutopeeringFeed()
	// records and organizes data that was received by analysis-server
	runEventsRecordManager()

	log.Infof("Starting %s ...", PluginName)
	if err := daemon.BackgroundWorker(PluginName, worker, shutdown.PriorityAnalysis); err != nil {
		log.Panicf("Error starting as daemon: %s", err)
	}
}

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("%s started, bind-address=%s", PluginName, bindAddr)
		if err := server.Start(bindAddr); err != nil {
			if !errors.Is(err, http.ErrServerClosed) {
				log.Errorf("Error serving: %s", err)
			}
			close(stopped)
		}
	}()

	// ping all connected ws clients every second to keep the connections alive.
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()
	// stop if we are shutting down or the server could not be started
	func() {
		for {
			select {
			case <-ticker.C:
				broadcastWsMessage(&wsmsg{MsgTypePing, ""})
			case <-shutdownSignal:
				return
			case <-stopped:
				return
			}
		}
	}()

	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)
	}
}