diff --git a/dapps/networkdelay/dapp.go b/dapps/networkdelay/dapp.go index 36611d18db9398465168fe0d19358021db196b9f..9e45e4a8f39b916e41ba0653cb2568ee9d366643 100644 --- a/dapps/networkdelay/dapp.go +++ b/dapps/networkdelay/dapp.go @@ -2,6 +2,7 @@ package networkdelay import ( "fmt" + "sync" "time" "github.com/iotaledger/goshimmer/packages/binary/messagelayer/message" @@ -29,7 +30,8 @@ const ( var ( // App is the "plugin" instance of the network delay application. - App = node.NewPlugin(PluginName, node.Disabled, configure) + app *node.Plugin + once sync.Once // log holds a reference to the logger used by this app. log *logger.Logger @@ -41,6 +43,14 @@ var ( originPublicKey ed25519.PublicKey ) +// App gets the plugin instance. +func App() *node.Plugin { + once.Do(func () { + app = node.NewPlugin(PluginName, node.Disabled, configure) + }) + return app +} + func configure(_ *node.Plugin) { // configure logger log = logger.NewLogger(PluginName) @@ -53,7 +63,7 @@ func configure(_ *node.Plugin) { } // get origin public key from config - bytes, err := base58.Decode(config.Node.GetString(CfgNetworkDelayOriginPublicKey)) + bytes, err := base58.Decode(config.Node().GetString(CfgNetworkDelayOriginPublicKey)) if err != nil { log.Fatalf("could not parse %s config entry as base58. %v", CfgNetworkDelayOriginPublicKey, err) } @@ -65,7 +75,7 @@ func configure(_ *node.Plugin) { configureWebAPI() // subscribe to message-layer - messagelayer.Tangle.Events.MessageSolid.Attach(events.NewClosure(onReceiveMessageFromMessageLayer)) + messagelayer.Tangle().Events.MessageSolid.Attach(events.NewClosure(onReceiveMessageFromMessageLayer)) } func onReceiveMessageFromMessageLayer(cachedMessage *message.CachedMessage, cachedMessageMetadata *messageTangle.CachedMessageMetadata) { diff --git a/dapps/networkdelay/webapi.go b/dapps/networkdelay/webapi.go index b7ecf54f5fbf20c0e81e33c3e7dd0a5473f00727..53f72ea6f2da3336e2bc5f3153ab95fff80fbab0 100644 --- a/dapps/networkdelay/webapi.go +++ b/dapps/networkdelay/webapi.go @@ -11,7 +11,7 @@ import ( ) func configureWebAPI() { - webapi.Server.POST("networkdelay", broadcastNetworkDelayObject) + webapi.Server().POST("networkdelay", broadcastNetworkDelayObject) } // broadcastNetworkDelayObject creates a message with a network delay object and diff --git a/dapps/valuetransfers/dapp.go b/dapps/valuetransfers/dapp.go index 9015d18aff916c08e2ce82c343c449a6b2e507ba..88be707b0de3b23eedca4c5840c8716b7634edd9 100644 --- a/dapps/valuetransfers/dapp.go +++ b/dapps/valuetransfers/dapp.go @@ -44,17 +44,19 @@ func init() { } var ( - // App is the "plugin" instance of the value-transfers application. - App = node.NewPlugin(PluginName, node.Enabled, configure, run) + // app is the "plugin" instance of the value-transfers application. + app *node.Plugin + appOnce sync.Once - // Tangle represents the value tangle that is used to express votes on value transactions. - Tangle *tangle.Tangle + // _tangle represents the value tangle that is used to express votes on value transactions. + _tangle *tangle.Tangle + tangleOnce sync.Once - // FCOB contains the fcob consensus logic. - FCOB *consensus.FCOB + // fcob contains the fcob consensus logic. + fcob *consensus.FCOB - // LedgerState represents the ledger state, that keeps track of the liked branches and offers an API to access funds. - LedgerState *tangle.LedgerState + // ledgerState represents the ledger state, that keeps track of the liked branches and offers an API to access funds. + ledgerState *tangle.LedgerState // log holds a reference to the logger used by this app. log *logger.Logger @@ -66,15 +68,44 @@ var ( valueObjectFactoryOnce sync.Once ) +// App gets the plugin instance. +func App() *node.Plugin { + appOnce.Do(func() { + app = node.NewPlugin(PluginName, node.Enabled, configure, run) + }) + return app +} + +// Tangle gets the tangle instance. +// tangle represents the value tangle that is used to express votes on value transactions. +func Tangle() *tangle.Tangle { + tangleOnce.Do(func() { + _tangle = tangle.New(database.Store()) + }) + return _tangle +} + +// FCOB gets the fcob instance. +// fcob contains the fcob consensus logic. +func FCOB() *consensus.FCOB { + return fcob +} + +// LedgerState gets the ledgerState instance. +// ledgerState represents the ledger state, that keeps track of the liked branches and offers an API to access funds. +func LedgerState() *tangle.LedgerState { + return ledgerState +} + func configure(_ *node.Plugin) { // configure logger log = logger.NewLogger(PluginName) // configure Tangle - Tangle = tangle.New(database.Store()) + _tangle = Tangle() // read snapshot file - snapshotFilePath := config.Node.GetString(CfgValueLayerSnapshotFile) + snapshotFilePath := config.Node().GetString(CfgValueLayerSnapshotFile) if len(snapshotFilePath) != 0 { snapshot := tangle.Snapshot{} f, err := os.Open(snapshotFilePath) @@ -84,11 +115,11 @@ func configure(_ *node.Plugin) { if _, err := snapshot.ReadFrom(f); err != nil { log.Panic("could not read snapshot file:", err) } - Tangle.LoadSnapshot(snapshot) + _tangle.LoadSnapshot(snapshot) log.Infof("read snapshot from %s", snapshotFilePath) } - Tangle.Events.Error.Attach(events.NewClosure(func(err error) { + _tangle.Events.Error.Attach(events.NewClosure(func(err error) { log.Error(err) })) @@ -96,31 +127,31 @@ func configure(_ *node.Plugin) { tipManager = TipManager() valueObjectFactory = ValueObjectFactory() - Tangle.Events.PayloadLiked.Attach(events.NewClosure(func(cachedPayload *payload.CachedPayload, cachedMetadata *tangle.CachedPayloadMetadata) { + _tangle.Events.PayloadLiked.Attach(events.NewClosure(func(cachedPayload *payload.CachedPayload, cachedMetadata *tangle.CachedPayloadMetadata) { cachedMetadata.Release() cachedPayload.Consume(tipManager.AddTip) })) - Tangle.Events.PayloadDisliked.Attach(events.NewClosure(func(cachedPayload *payload.CachedPayload, cachedMetadata *tangle.CachedPayloadMetadata) { + _tangle.Events.PayloadDisliked.Attach(events.NewClosure(func(cachedPayload *payload.CachedPayload, cachedMetadata *tangle.CachedPayloadMetadata) { cachedMetadata.Release() cachedPayload.Consume(tipManager.RemoveTip) })) // configure FCOB consensus rules - cfgAvgNetworkDelay := config.Node.GetInt(CfgValueLayerFCOBAverageNetworkDelay) + cfgAvgNetworkDelay := config.Node().GetInt(CfgValueLayerFCOBAverageNetworkDelay) log.Infof("avg. network delay configured to %d seconds", cfgAvgNetworkDelay) - FCOB = consensus.NewFCOB(Tangle, time.Duration(cfgAvgNetworkDelay)*time.Second) - FCOB.Events.Vote.Attach(events.NewClosure(func(id string, initOpn vote.Opinion) { + fcob = consensus.NewFCOB(_tangle, time.Duration(cfgAvgNetworkDelay)*time.Second) + fcob.Events.Vote.Attach(events.NewClosure(func(id string, initOpn vote.Opinion) { if err := voter.Vote(id, initOpn); err != nil { log.Warnf("FPC vote: %s", err) } })) - FCOB.Events.Error.Attach(events.NewClosure(func(err error) { + fcob.Events.Error.Attach(events.NewClosure(func(err error) { log.Errorf("FCOB error: %s", err) })) // configure FPC + link to consensus configureFPC() - voter.Events().Finalized.Attach(events.NewClosure(FCOB.ProcessVoteResult)) + voter.Events().Finalized.Attach(events.NewClosure(fcob.ProcessVoteResult)) voter.Events().Finalized.Attach(events.NewClosure(func(ev *vote.OpinionEvent) { log.Infof("FPC finalized for transaction with id '%s' - final opinion: '%s'", ev.ID, ev.Opinion) })) @@ -129,16 +160,16 @@ func configure(_ *node.Plugin) { })) // register SignatureFilter in Parser - messagelayer.MessageParser.AddMessageFilter(tangle.NewSignatureFilter()) + messagelayer.MessageParser().AddMessageFilter(tangle.NewSignatureFilter()) // subscribe to message-layer - messagelayer.Tangle.Events.MessageSolid.Attach(events.NewClosure(onReceiveMessageFromMessageLayer)) + messagelayer.Tangle().Events.MessageSolid.Attach(events.NewClosure(onReceiveMessageFromMessageLayer)) } func run(*node.Plugin) { if err := daemon.BackgroundWorker("ValueTangle", func(shutdownSignal <-chan struct{}) { <-shutdownSignal - Tangle.Shutdown() + _tangle.Shutdown() }, shutdown.PriorityTangle); err != nil { log.Panicf("Failed to start as daemon: %s", err) } @@ -169,7 +200,7 @@ func onReceiveMessageFromMessageLayer(cachedMessage *message.CachedMessage, cach return } - Tangle.AttachPayload(valuePayload) + _tangle.AttachPayload(valuePayload) } // TipManager returns the TipManager singleton. diff --git a/dapps/valuetransfers/fpc.go b/dapps/valuetransfers/fpc.go index 4f975b213327b30c3af696fee81f47cafd5e3bf6..23d271f79a08f2ba7cb29c76df3eb40b15cb15b2 100644 --- a/dapps/valuetransfers/fpc.go +++ b/dapps/valuetransfers/fpc.go @@ -79,7 +79,7 @@ func configureFPC() { log = logger.NewLogger(FpcPluginName) lPeer := local.GetInstance() - bindAddr := config.Node.GetString(CfgFPCBindAddress) + bindAddr := config.Node().GetString(CfgFPCBindAddress) _, portStr, err := net.SplitHostPort(bindAddr) if err != nil { log.Fatalf("FPC bind address '%s' is invalid: %s", bindAddr, err) @@ -104,7 +104,7 @@ func runFPC() { const ServerWorkerName = "FPCVoterServer" if err := daemon.BackgroundWorker(ServerWorkerName, func(shutdownSignal <-chan struct{}) { stopped := make(chan struct{}) - bindAddr := config.Node.GetString(CfgFPCBindAddress) + bindAddr := config.Node().GetString(CfgFPCBindAddress) voterServer = votenet.New(Voter(), func(id string) vote.Opinion { branchID, err := branchmanager.BranchIDFromBase58(id) if err != nil { @@ -113,7 +113,7 @@ func runFPC() { return vote.Unknown } - cachedBranch := Tangle.BranchManager().Branch(branchID) + cachedBranch := _tangle.BranchManager().Branch(branchID) defer cachedBranch.Release() branch := cachedBranch.Unwrap() diff --git a/pluginmgr/core/plugins.go b/pluginmgr/core/plugins.go index 7bdae01c301a5d6f8945a630cd98dd18c57c0fbf..13e028867a30dda7a6867aecf7d5042315dad238 100644 --- a/pluginmgr/core/plugins.go +++ b/pluginmgr/core/plugins.go @@ -24,22 +24,22 @@ import ( ) var PLUGINS = node.Plugins( - banner.Plugin, - config.Plugin, - logger.Plugin, - cli.Plugin, - portcheck.Plugin, - profiling.Plugin, - database.Plugin, - autopeering.Plugin, + banner.Plugin(), + config.Plugin(), + logger.Plugin(), + cli.Plugin(), + portcheck.Plugin(), + profiling.Plugin(), + database.Plugin(), + autopeering.Plugin(), pow.Plugin, - messagelayer.Plugin, - gossip.Plugin, - issuer.Plugin, - bootstrap.Plugin, - sync.Plugin, - gracefulshutdown.Plugin, - metrics.Plugin, - drng.Plugin, - valuetransfers.App, + messagelayer.Plugin(), + gossip.Plugin(), + issuer.Plugin(), + bootstrap.Plugin(), + sync.Plugin(), + gracefulshutdown.Plugin(), + metrics.Plugin(), + drng.Plugin(), + valuetransfers.App(), ) diff --git a/pluginmgr/research/plugins.go b/pluginmgr/research/plugins.go index 1275898c7d35401f7db62d3c804f88b50e8bd019..66e4037f1494e4443988c35e824e20376e4b8ca1 100644 --- a/pluginmgr/research/plugins.go +++ b/pluginmgr/research/plugins.go @@ -11,10 +11,10 @@ import ( ) var PLUGINS = node.Plugins( - remotelog.Plugin, - analysisserver.Plugin, - analysisclient.Plugin, - analysisdashboard.Plugin, + remotelog.Plugin(), + analysisserver.Plugin(), + analysisclient.Plugin(), + analysisdashboard.Plugin(), prometheus.Plugin, - networkdelay.App, + networkdelay.App(), ) diff --git a/pluginmgr/ui/plugins.go b/pluginmgr/ui/plugins.go index 0cb1418a869694682102adac11fa348d95722a32..e3a2dc1a71c2b565e34b1eb8e9ec545e95872863 100644 --- a/pluginmgr/ui/plugins.go +++ b/pluginmgr/ui/plugins.go @@ -6,5 +6,5 @@ import ( ) var PLUGINS = node.Plugins( - dashboard.Plugin, + dashboard.Plugin(), ) diff --git a/pluginmgr/webapi/plugins.go b/pluginmgr/webapi/plugins.go index 11df33b279241384ec2669b08f688b43ff2ea6f1..807a01e7a9beb2502b6071e53b9a2fff62834ac9 100644 --- a/pluginmgr/webapi/plugins.go +++ b/pluginmgr/webapi/plugins.go @@ -15,14 +15,14 @@ import ( ) var PLUGINS = node.Plugins( - webapi.Plugin, - webauth.Plugin, - spammer.Plugin, - data.Plugin, - drng.Plugin, - healthz.Plugin, - message.Plugin, - autopeering.Plugin, - info.Plugin, - value.Plugin, + webapi.Plugin(), + webauth.Plugin(), + spammer.Plugin(), + data.Plugin(), + drng.Plugin(), + healthz.Plugin(), + message.Plugin(), + autopeering.Plugin(), + info.Plugin(), + value.Plugin(), ) diff --git a/plugins/analysis/client/plugin.go b/plugins/analysis/client/plugin.go index 7108fd4b44fa39464e03db3c62eda509dc3df1e3..734e3507fe7d6e8db04e0899f8e5d536758c93e3 100644 --- a/plugins/analysis/client/plugin.go +++ b/plugins/analysis/client/plugin.go @@ -1,6 +1,7 @@ package client import ( + "sync" "time" "github.com/iotaledger/goshimmer/dapps/valuetransfers" @@ -30,16 +31,26 @@ func init() { } var ( - // Plugin is the plugin instance of the analysis client plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, run) - conn *Connector - log *logger.Logger + // plugin is the plugin instance of the analysis client plugin. + plugin *node.Plugin + once sync.Once + log *logger.Logger + conn *Connector + connLock sync.Mutex ) +// Plugin gets the plugin instance +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, run) + }) + return plugin +} + func run(_ *node.Plugin) { finalized = make(map[string]vote.Opinion) log = logger.NewLogger(PluginName) - conn = NewConnector("tcp", config.Node.GetString(CfgServerAddress)) + conn = NewConnector("tcp", config.Node().GetString(CfgServerAddress)) if err := daemon.BackgroundWorker(PluginName, func(shutdownSignal <-chan struct{}) { conn.Start() diff --git a/plugins/analysis/dashboard/fpc_livefeed.go b/plugins/analysis/dashboard/fpc_livefeed.go index 73160c6de346d55db83ed814b3ddbeb0535d5cc7..00ee50a81447c4cb0aa6bb4f4c651bbda09ce56a 100644 --- a/plugins/analysis/dashboard/fpc_livefeed.go +++ b/plugins/analysis/dashboard/fpc_livefeed.go @@ -41,7 +41,7 @@ type FPCUpdate struct { func configureFPCLiveFeed() { - if config.Node.GetBool(CfgMongoDBEnabled) { + if config.Node().GetBool(CfgMongoDBEnabled) { mongoDB() } @@ -51,7 +51,7 @@ func configureFPCLiveFeed() { task.Return(nil) }, workerpool.WorkerCount(fpcLiveFeedWorkerCount), workerpool.QueueSize(fpcLiveFeedWorkerQueueSize)) - if config.Node.GetBool(CfgMongoDBEnabled) { + if config.Node().GetBool(CfgMongoDBEnabled) { fpcStoreFinalizedWorkerPool = workerpool.New(func(task workerpool.Task) { storeFinalizedVoteContext(task.Param(0).(FPCRecords)) task.Return(nil) @@ -69,7 +69,7 @@ func runFPCLiveFeed() { fpcLiveFeedWorkerPool.Start() defer fpcLiveFeedWorkerPool.Stop() - if config.Node.GetBool(CfgMongoDBEnabled) { + if config.Node().GetBool(CfgMongoDBEnabled) { fpcStoreFinalizedWorkerPool.Start() defer fpcStoreFinalizedWorkerPool.Stop() } @@ -150,7 +150,7 @@ func createFPCUpdate(hb *packet.FPCHeartbeat) *FPCUpdate { }) } - if config.Node.GetBool(CfgMongoDBEnabled) { + if config.Node().GetBool(CfgMongoDBEnabled) { fpcStoreFinalizedWorkerPool.TrySubmit(finalizedConflicts) } diff --git a/plugins/analysis/dashboard/fpc_storage.go b/plugins/analysis/dashboard/fpc_storage.go index 47607b627b38049247d09353e2ed69719f1236be..66506742d89d6f184630889b3fd40a5561acde25 100644 --- a/plugins/analysis/dashboard/fpc_storage.go +++ b/plugins/analysis/dashboard/fpc_storage.go @@ -56,9 +56,9 @@ func mongoDB() *mongo.Database { } func newMongoDB() (*mongo.Client, error) { - username := config.Node.GetString(CfgMongoDBUsername) - password := config.Node.GetString(CfgMongoDBPassword) - hostAddr := config.Node.GetString(CfgMongoDBHostAddress) + username := config.Node().GetString(CfgMongoDBUsername) + password := config.Node().GetString(CfgMongoDBPassword) + hostAddr := config.Node().GetString(CfgMongoDBHostAddress) client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://" + username + ":" + password + "@" + hostAddr)) if err != nil { diff --git a/plugins/analysis/dashboard/plugin.go b/plugins/analysis/dashboard/plugin.go index 0d3817b561b24ffc0ecbc05f99bdcaab8c29fb3d..da6ab6e0ad79f52d2e44cb33bd9b8e83fde8720c 100644 --- a/plugins/analysis/dashboard/plugin.go +++ b/plugins/analysis/dashboard/plugin.go @@ -19,13 +19,18 @@ import ( const PluginName = "Analysis-Dashboard" var ( - // Plugin is the plugin instance of the dashboard plugin. - Plugin = node.NewPlugin(PluginName, node.Disabled, configure, run) + // plugin is the plugin instance of the dashboard plugin. + plugin = node.NewPlugin(PluginName, node.Disabled, configure, run) log *logger.Logger server *echo.Echo ) +// Plugin gets the plugin instance +func Plugin() *node.Plugin { + return plugin +} + func configure(plugin *node.Plugin) { log = logger.NewLogger(plugin.Name) configureFPCLiveFeed() @@ -40,10 +45,10 @@ func configureServer() { server.HidePort = true server.Use(middleware.Recover()) - if config.Node.GetBool(CfgBasicAuthEnabled) { + 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) { + if username == config.Node().GetString(CfgBasicAuthUsername) && + password == config.Node().GetString(CfgBasicAuthPassword) { return true, nil } return false, nil @@ -71,7 +76,7 @@ func worker(shutdownSignal <-chan struct{}) { defer log.Infof("Stopping %s ... done", PluginName) stopped := make(chan struct{}) - bindAddr := config.Node.GetString(CfgBindAddress) + bindAddr := config.Node().GetString(CfgBindAddress) go func() { log.Infof("%s started, bind-address=%s", PluginName, bindAddr) if err := server.Start(bindAddr); err != nil { diff --git a/plugins/analysis/dashboard/routes.go b/plugins/analysis/dashboard/routes.go index 1ffc810bafdb4ac2e7c151873ecfef0da2c0bf0a..442af15b3f604d66c1c97a10437d51c5d1725e23 100644 --- a/plugins/analysis/dashboard/routes.go +++ b/plugins/analysis/dashboard/routes.go @@ -28,7 +28,7 @@ var appBox = packr.New("AnalysisDashboard_App", "./frontend/build") var assetsBox = packr.New("AnalysisDashboard_Assets", "./frontend/src/assets") func indexRoute(e echo.Context) error { - if config.Node.GetBool(CfgDev) { + if config.Node().GetBool(CfgDev) { res, err := http.Get("http://127.0.0.1:9090/") if err != nil { return err @@ -48,7 +48,7 @@ func indexRoute(e echo.Context) error { func setupRoutes(e *echo.Echo) { - if config.Node.GetBool("analysis.dashboard.dev") { + if config.Node().GetBool("analysis.dashboard.dev") { e.Static("/assets", "./plugins/analysis/dashboard/frontend/src/assets") } else { diff --git a/plugins/analysis/packet/fpc_heartbeat.go b/plugins/analysis/packet/fpc_heartbeat.go index 2746abe2b91af1d48d0c22c519f0817dd5d5cb5a..3c64aafc285011f91258e7717798225508a1adbd 100644 --- a/plugins/analysis/packet/fpc_heartbeat.go +++ b/plugins/analysis/packet/fpc_heartbeat.go @@ -5,7 +5,6 @@ import ( "encoding/binary" "encoding/gob" "errors" - "github.com/iotaledger/goshimmer/packages/vote" "github.com/iotaledger/hive.go/protocol/message" "github.com/iotaledger/hive.go/protocol/tlv" @@ -16,15 +15,6 @@ var ( ErrInvalidFPCHeartbeat = errors.New("invalid FPC heartbeat") ) -var ( - // FPCHeartbeatMessageDefinition defines a heartbeat message's format. - FPCHeartbeatMessageDefinition = &message.Definition{ - ID: MessageTypeFPCHeartbeat, - MaxBytesLength: 65535, - VariableLength: true, - } -) - // FPCHeartbeat represents a heartbeat packet. type FPCHeartbeat struct { // The ID of the node who sent the heartbeat. @@ -36,6 +26,20 @@ type FPCHeartbeat struct { Finalized map[string]vote.Opinion } +// FPCHeartbeatMessageDefinition gets the fpcHeartbeatMessageDefinition. +func FPCHeartbeatMessageDefinition() *message.Definition { + // fpcHeartbeatMessageDefinition defines a heartbeat message's format. + var fpcHeartbeatMessageDefinition *message.Definition + fpcHeartBeatOnce.Do(func(){ + fpcHeartbeatMessageDefinition = &message.Definition{ + ID: MessageTypeFPCHeartbeat, + MaxBytesLength: 65535, + VariableLength: true, + } + }) + return fpcHeartbeatMessageDefinition +} + // ParseFPCHeartbeat parses a slice of bytes (serialized packet) into a FPC heartbeat. func ParseFPCHeartbeat(data []byte) (*FPCHeartbeat, error) { hb := &FPCHeartbeat{} diff --git a/plugins/analysis/packet/heartbeat.go b/plugins/analysis/packet/heartbeat.go index 41cfd39bdd3b87197a2f7b514ed327ec0a51fce0..65f75e56358168c3f94f9a88ea5cd89e4279396e 100644 --- a/plugins/analysis/packet/heartbeat.go +++ b/plugins/analysis/packet/heartbeat.go @@ -6,7 +6,6 @@ import ( "encoding/binary" "errors" "fmt" - "github.com/iotaledger/hive.go/protocol/message" "github.com/iotaledger/hive.go/protocol/tlv" ) @@ -25,9 +24,6 @@ const ( HeartbeatPacketPeerIDSize = sha256.Size // HeartbeatPacketOutboundIDCountSize is the byte size of the counter indicating the amount of outbound IDs. HeartbeatPacketOutboundIDCountSize = 1 -) - -var ( // HeartbeatPacketMinSize is the minimum byte size of a heartbeat packet. HeartbeatPacketMinSize = HeartbeatPacketPeerIDSize + HeartbeatPacketOutboundIDCountSize // HeartbeatPacketMaxSize is the maximum size a heartbeat packet can have. @@ -35,14 +31,6 @@ var ( HeartbeatMaxOutboundPeersCount*sha256.Size + HeartbeatMaxInboundPeersCount*sha256.Size ) -var ( - // HeartbeatMessageDefinition defines a heartbeat message's format. - HeartbeatMessageDefinition = &message.Definition{ - ID: MessageTypeHeartbeat, - MaxBytesLength: uint16(HeartbeatPacketMaxSize), - VariableLength: true, - } -) // Heartbeat represents a heartbeat packet. type Heartbeat struct { @@ -57,6 +45,20 @@ type Heartbeat struct { InboundIDs [][]byte } +// HeartBeatMessageDefinition gets the heartbeatMessageDefinition. +func HeartBeatMessageDefinition() *message.Definition{ + // heartbeatMessageDefinition defines a heartbeat message's format. + var heartbeatMessageDefinition *message.Definition + heartBeatOnce.Do(func(){ + heartbeatMessageDefinition = &message.Definition{ + ID: MessageTypeHeartbeat, + MaxBytesLength: uint16(HeartbeatPacketMaxSize), + VariableLength: true, + } + }) + return heartbeatMessageDefinition +} + // ParseHeartbeat parses a slice of bytes (serialized packet) into a heartbeat. func ParseHeartbeat(data []byte) (*Heartbeat, error) { // check minimum size diff --git a/plugins/analysis/packet/packet.go b/plugins/analysis/packet/packet.go index d95c72d3bd59896597b5000c2e30ee2027127a01..cf5a9740e76a85dab4c378f3f1de2609e0b9870f 100644 --- a/plugins/analysis/packet/packet.go +++ b/plugins/analysis/packet/packet.go @@ -2,6 +2,7 @@ package packet import ( "errors" + "sync" "github.com/iotaledger/hive.go/protocol/message" "github.com/iotaledger/hive.go/protocol/tlv" @@ -12,16 +13,25 @@ var ( ErrMalformedPacket = errors.New("malformed packet") ) -// AnalysisMsgRegistry holds all message definitions for analysis server related messages -var AnalysisMsgRegistry *message.Registry +var ( + // analysisMsgRegistry holds all message definitions for analysis server related messages + analysisMsgRegistry *message.Registry + fpcHeartBeatOnce sync.Once + heartBeatOnce sync.Once +) func init() { // message definitions to be registered in registry definitions := []*message.Definition{ tlv.HeaderMessageDefinition, - HeartbeatMessageDefinition, - FPCHeartbeatMessageDefinition, + HeartBeatMessageDefinition(), + FPCHeartbeatMessageDefinition(), MetricHeartbeatMessageDefinition, } - AnalysisMsgRegistry = message.NewRegistry(definitions) + analysisMsgRegistry = message.NewRegistry(definitions) +} + +// AnalysisMsgRegistry gets the analysisMsgRegistry. +func AnalysisMsgRegistry() *message.Registry { + return analysisMsgRegistry } diff --git a/plugins/analysis/server/plugin.go b/plugins/analysis/server/plugin.go index 603fd5c467d0f172f31e38d4fafe9c0a935857ad..6c7173fc3828adca685ff7541a74ec4710866191 100644 --- a/plugins/analysis/server/plugin.go +++ b/plugins/analysis/server/plugin.go @@ -5,6 +5,7 @@ import ( "net" "strconv" "strings" + "sync" "time" "github.com/iotaledger/goshimmer/packages/shutdown" @@ -36,13 +37,22 @@ func init() { } var ( - // Plugin is the plugin instance of the analysis server plugin. - Plugin = node.NewPlugin(PluginName, node.Disabled, configure, run) + // plugin is the plugin instance of the analysis server plugin. + plugin *node.Plugin + once sync.Once server *tcp.TCPServer prot *protocol.Protocol log *logger.Logger ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Disabled, configure, run) + }) + return plugin +} + func configure(_ *node.Plugin) { log = logger.NewLogger(PluginName) server = tcp.NewServer() @@ -54,7 +64,7 @@ func configure(_ *node.Plugin) { } func run(_ *node.Plugin) { - bindAddr := config.Node.GetString(CfgAnalysisServerBindAddress) + bindAddr := config.Node().GetString(CfgAnalysisServerBindAddress) addr, portStr, err := net.SplitHostPort(bindAddr) if err != nil { log.Fatal("invalid bind address in %s: %s", CfgAnalysisServerBindAddress, err) @@ -69,7 +79,7 @@ func run(_ *node.Plugin) { defer log.Infof("Stopping %s ... done", PluginName) // connect protocol events to processors - prot = protocol.New(packet.AnalysisMsgRegistry) + prot = protocol.New(packet.AnalysisMsgRegistry()) wireUp(prot) go server.Listen(addr, port) diff --git a/plugins/autopeering/autopeering.go b/plugins/autopeering/autopeering.go index 8f2b7f2604caad4981f235d4d40f452f11b4801b..7b33f4224e548f77467be7a277e2f854f05ec16c 100644 --- a/plugins/autopeering/autopeering.go +++ b/plugins/autopeering/autopeering.go @@ -33,8 +33,8 @@ var ( // ErrParsingMasterNode is returned for an invalid master node. ErrParsingMasterNode = errors.New("cannot parse master node") - // NetworkID specifies the autopeering network identifier. - NetworkID = hash32([]byte(banner.AppVersion + NetworkVersion)) + // networkID specifies the autopeering network identifier. + networkID = hash32([]byte(banner.AppVersion + NetworkVersion)) // Conn contains the network connection. Conn *NetConnMetric @@ -56,6 +56,11 @@ var ( }{c: make(chan *server.Server, 1)} ) +// NetworkID gets the networkID. +func NetworkID() uint32 { + return networkID +} + // Discovery returns the peer discovery instance. func Discovery() *discover.Protocol { peerDiscOnce.Do(createPeerDisc) @@ -71,7 +76,7 @@ func Selection() *selection.Protocol { // BindAddress returns the string form of the autopeering bind address. func BindAddress() string { peering := local.GetInstance().Services().Get(service.PeeringKey) - host := config.Node.GetString(local.CfgBind) + host := config.Node().GetString(local.CfgBind) port := strconv.Itoa(peering.Port()) return net.JoinHostPort(host, port) } @@ -97,7 +102,7 @@ func createPeerDisc() { } log.Debugf("Master peers: %v", masterPeers) - peerDisc = discover.New(local.GetInstance(), ProtocolVersion, NetworkID, + peerDisc = discover.New(local.GetInstance(), ProtocolVersion, networkID, discover.Logger(log), discover.MasterPeers(masterPeers), ) @@ -177,7 +182,7 @@ func hash32(b []byte) uint32 { } func parseEntryNodes() (result []*peer.Peer, err error) { - for _, entryNodeDefinition := range config.Node.GetStringSlice(CfgEntryNodes) { + for _, entryNodeDefinition := range config.Node().GetStringSlice(CfgEntryNodes) { if entryNodeDefinition == "" { continue } diff --git a/plugins/autopeering/local/local.go b/plugins/autopeering/local/local.go index b2a211c8a7d005f63e82cd3cc0393ab311577a07..d3fbdf923cad36b8e5ca204ab56a90f42dd24d94 100644 --- a/plugins/autopeering/local/local.go +++ b/plugins/autopeering/local/local.go @@ -26,7 +26,7 @@ func configureLocal() *peer.Local { log := logger.NewLogger("Local") var peeringIP net.IP - if str := config.Node.GetString(CfgExternal); strings.ToLower(str) == "auto" { + if str := config.Node().GetString(CfgExternal); strings.ToLower(str) == "auto" { // let the autopeering discover the IP peeringIP = net.IPv4zero } else { @@ -39,7 +39,7 @@ func configureLocal() *peer.Local { } } - peeringPort := config.Node.GetInt(CfgPort) + peeringPort := config.Node().GetInt(CfgPort) if 0 > peeringPort || peeringPort > 65535 { log.Fatalf("Invalid port number (%s): %d", CfgPort, peeringPort) } @@ -50,7 +50,7 @@ func configureLocal() *peer.Local { // set the private key from the seed provided in the config var seed [][]byte - if str := config.Node.GetString(CfgSeed); str != "" { + if str := config.Node().GetString(CfgSeed); str != "" { var bytes []byte var err error diff --git a/plugins/autopeering/plugin.go b/plugins/autopeering/plugin.go index 74aa171c2a368f5247a0224b61a548fce2daead6..c100b9768b4abae3da9ed6276a5421ee2ea804cc 100644 --- a/plugins/autopeering/plugin.go +++ b/plugins/autopeering/plugin.go @@ -1,6 +1,7 @@ package autopeering import ( + "sync" "time" "github.com/iotaledger/goshimmer/packages/shutdown" @@ -16,12 +17,21 @@ import ( const PluginName = "Autopeering" var ( - // Plugin is the plugin instance of the autopeering plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + // plugin is the plugin instance of the autopeering plugin. + plugin *node.Plugin + once sync.Once log *logger.Logger ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + }) + return plugin +} + func configure(*node.Plugin) { log = logger.NewLogger(PluginName) diff --git a/plugins/banner/plugin.go b/plugins/banner/plugin.go index 1f0936a6cd9cfa90a38a840f1cf200ef46883e33..f71fab08b3d5c946700d24ff87a47726682c0a98 100644 --- a/plugins/banner/plugin.go +++ b/plugins/banner/plugin.go @@ -2,6 +2,7 @@ package banner import ( "fmt" + "sync" "github.com/iotaledger/hive.go/node" ) @@ -9,8 +10,11 @@ import ( // PluginName is the name of the banner plugin. const PluginName = "Banner" -// Plugin is the plugin instance of the banner plugin. -var Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) +var ( + // plugin is the plugin instance of the banner plugin. + plugin *node.Plugin + once sync.Once +) const ( // AppVersion version number @@ -20,6 +24,14 @@ const ( AppName = "GoShimmer" ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Disabled, configure, run) + }) + return plugin +} + func configure(ctx *node.Plugin) { fmt.Printf(` _____ ____ _____ _ _ _____ __ __ __ __ ______ _____ diff --git a/plugins/bootstrap/plugin.go b/plugins/bootstrap/plugin.go index 1ebfd520865183b45508c6c2dca6d009618a433a..c1aab9ddcbd8aa4c8f51aa79c023e285108a5a06 100644 --- a/plugins/bootstrap/plugin.go +++ b/plugins/bootstrap/plugin.go @@ -1,6 +1,7 @@ package bootstrap import ( + goSync "sync" "time" "github.com/iotaledger/goshimmer/packages/binary/spammer" @@ -32,11 +33,20 @@ func init() { } var ( - // Plugin is the plugin instance of the bootstrap plugin. - Plugin = node.NewPlugin(PluginName, node.Disabled, configure, run) + // plugin is the plugin instance of the bootstrap plugin. + plugin *node.Plugin + once goSync.Once log *logger.Logger ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Disabled, configure, run) + }) + return plugin +} + func configure(_ *node.Plugin) { log = logger.NewLogger(PluginName) // we're auto. synced if we start in bootstrapping mode @@ -47,7 +57,7 @@ func configure(_ *node.Plugin) { func run(_ *node.Plugin) { messageSpammer := spammer.New(issuer.IssuePayload) - issuancePeriodSec := config.Node.GetInt(CfgBootstrapInitialIssuanceTimePeriodSec) + issuancePeriodSec := config.Node().GetInt(CfgBootstrapInitialIssuanceTimePeriodSec) issuancePeriod := time.Duration(issuancePeriodSec) * time.Second // issue messages on top of the genesis diff --git a/plugins/cli/plugin.go b/plugins/cli/plugin.go index 99bb6368d2e1c0f960f236fc15e187279bdf2213..8946d22b12173110418873b919446ee8870759bf 100644 --- a/plugins/cli/plugin.go +++ b/plugins/cli/plugin.go @@ -3,6 +3,7 @@ package cli import ( "fmt" "os" + "sync" "github.com/iotaledger/hive.go/events" "github.com/iotaledger/hive.go/node" @@ -15,12 +16,23 @@ import ( const PluginName = "CLI" var ( - // Plugin is the plugin instance of the CLI plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled) + // plugin is the plugin instance of the CLI plugin. + plugin *node.Plugin + once sync.Once version = flag.BoolP("version", "v", false, "Prints the GoShimmer version") ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled) + }) + return plugin +} + func init() { + plugin = Plugin() + for name, plugin := range node.GetPlugins() { onAddPlugin(name, plugin.Status) } @@ -29,7 +41,7 @@ func init() { flag.Usage = printUsage - Plugin.Events.Init.Attach(events.NewClosure(onInit)) + plugin.Events.Init.Attach(events.NewClosure(onInit)) } func onAddPlugin(name string, status int) { diff --git a/plugins/config/plugin.go b/plugins/config/plugin.go index da882233e400356dfeffae261fb0e500f37453a4..151ed747fe9d2c8677a5417d991ae754f71b2106 100644 --- a/plugins/config/plugin.go +++ b/plugins/config/plugin.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "strings" + "sync" "github.com/iotaledger/hive.go/events" "github.com/iotaledger/hive.go/node" @@ -16,8 +17,9 @@ import ( const PluginName = "Config" var ( - // Plugin is the plugin instance of the config plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled) + // plugin is the plugin instance of the config plugin. + plugin *node.Plugin + pluginOnce sync.Once // flags configName = flag.StringP("config", "c", "config", "Filename of the config file without the file extension") @@ -25,19 +27,38 @@ var ( skipConfigAvailable = flag.Bool("skip-config", false, "Skip config file availability check") // Node is viper - Node *viper.Viper + _node *viper.Viper + nodeOnce sync.Once ) // Init triggers the Init event. func Init() { - Plugin.Events.Init.Trigger(Plugin) + plugin.Events.Init.Trigger(plugin) +} + +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + pluginOnce.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled) + }) + return plugin +} + +// Node gets the node. +func Node() *viper.Viper { + nodeOnce.Do(func() { + _node = viper.New() + }) + return _node } func init() { // set the default logger config - Node = viper.New() + _node = Node() + plugin = Plugin() + - Plugin.Events.Init.Attach(events.NewClosure(func(*node.Plugin) { + plugin.Events.Init.Attach(events.NewClosure(func(*node.Plugin) { if err := fetch(false); err != nil { if !*skipConfigAvailable { // we wanted a config file but it was not present @@ -59,24 +80,25 @@ func init() { func fetch(printConfig bool, ignoreSettingsAtPrint ...[]string) error { // replace dots with underscores in env dotReplacer := strings.NewReplacer(".", "_") - Node.SetEnvKeyReplacer(dotReplacer) + _node.SetEnvKeyReplacer(dotReplacer) + // read in ENV variables // read in ENV variables - Node.AutomaticEnv() + _node.AutomaticEnv() flag.Parse() - err := parameter.LoadConfigFile(Node, *configDirPath, *configName, true, *skipConfigAvailable) + err := parameter.LoadConfigFile(_node, *configDirPath, *configName, true, *skipConfigAvailable) if err != nil { return err } if printConfig { - parameter.PrintConfig(Node, ignoreSettingsAtPrint...) + parameter.PrintConfig(_node, ignoreSettingsAtPrint...) } - for _, pluginName := range Node.GetStringSlice(node.CFG_DISABLE_PLUGINS) { + for _, pluginName := range _node.GetStringSlice(node.CFG_DISABLE_PLUGINS) { node.DisabledPlugins[node.GetPluginIdentifier(pluginName)] = true } - for _, pluginName := range Node.GetStringSlice(node.CFG_ENABLE_PLUGINS) { + for _, pluginName := range _node.GetStringSlice(node.CFG_ENABLE_PLUGINS) { node.EnabledPlugins[node.GetPluginIdentifier(pluginName)] = true } diff --git a/plugins/dashboard/explorer_routes.go b/plugins/dashboard/explorer_routes.go index 2f3463548c08d957b2ac867f3e6cebb2219cac44..5dc6bf4a82092477bdf296affcd3d9a27596c14f 100644 --- a/plugins/dashboard/explorer_routes.go +++ b/plugins/dashboard/explorer_routes.go @@ -30,7 +30,7 @@ type ExplorerMessage struct { func createExplorerMessage(msg *message.Message) (*ExplorerMessage, error) { messageID := msg.Id() - messageMetadata := messagelayer.Tangle.MessageMetadata(messageID) + messageMetadata := messagelayer.Tangle().MessageMetadata(messageID) t := &ExplorerMessage{ ID: messageID.String(), Timestamp: 0, @@ -119,7 +119,7 @@ func setupExplorerRoutes(routeGroup *echo.Group) { } func findMessage(messageID message.Id) (explorerMsg *ExplorerMessage, err error) { - if !messagelayer.Tangle.Message(messageID).Consume(func(msg *message.Message) { + if !messagelayer.Tangle().Message(messageID).Consume(func(msg *message.Message) { explorerMsg, err = createExplorerMessage(msg) }) { err = fmt.Errorf("%w: message %s", ErrNotFound, messageID.String()) diff --git a/plugins/dashboard/livefeed.go b/plugins/dashboard/livefeed.go index f0bebaa62488444d0dfb6025759fa548cf695ed6..8e491becd120cd28f612d878d8af1e54ad27b828 100644 --- a/plugins/dashboard/livefeed.go +++ b/plugins/dashboard/livefeed.go @@ -40,11 +40,11 @@ func runLiveFeed() { }) if err := daemon.BackgroundWorker("Dashboard[MsgUpdater]", func(shutdownSignal <-chan struct{}) { - messagelayer.Tangle.Events.MessageAttached.Attach(notifyNewMsg) + messagelayer.Tangle().Events.MessageAttached.Attach(notifyNewMsg) liveFeedWorkerPool.Start() <-shutdownSignal log.Info("Stopping Dashboard[MsgUpdater] ...") - messagelayer.Tangle.Events.MessageAttached.Detach(notifyNewMsg) + messagelayer.Tangle().Events.MessageAttached.Detach(notifyNewMsg) newMsgRateLimiter.Stop() liveFeedWorkerPool.Stop() log.Info("Stopping Dashboard[MsgUpdater] ... done") diff --git a/plugins/dashboard/plugin.go b/plugins/dashboard/plugin.go index f0f033aa705e2526f2521dff1fa4bb632ca472bc..b19aaf9ac79041b3507278a532c3a0b0e53290be 100644 --- a/plugins/dashboard/plugin.go +++ b/plugins/dashboard/plugin.go @@ -7,6 +7,7 @@ import ( "net/http" "runtime" "strconv" + "sync" "time" "github.com/iotaledger/goshimmer/packages/shutdown" @@ -30,8 +31,9 @@ import ( const PluginName = "Dashboard" var ( - // Plugin is the plugin instance of the dashboard plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + // plugin is the plugin instance of the dashboard plugin. + plugin *node.Plugin + once sync.Once log *logger.Logger server *echo.Echo @@ -39,6 +41,14 @@ var ( nodeStartAt = time.Now() ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + }) + return plugin +} + func configure(plugin *node.Plugin) { log = logger.NewLogger(plugin.Name) configureWebSocketWorkerPool() @@ -54,10 +64,10 @@ func configureServer() { server.HidePort = true server.Use(middleware.Recover()) - if config.Node.GetBool(CfgBasicAuthEnabled) { + 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) { + if username == config.Node().GetString(CfgBasicAuthUsername) && + password == config.Node().GetString(CfgBasicAuthPassword) { return true, nil } return false, nil @@ -75,7 +85,7 @@ func run(*node.Plugin) { // run the visualizer vertex feed runVisualizer() // run dRNG live feed if dRNG plugin is enabled - if !node.IsSkipped(drng.Plugin) { + if !node.IsSkipped(drng.Plugin()) { runDrngLiveFeed() } @@ -98,7 +108,7 @@ func worker(shutdownSignal <-chan struct{}) { defer metrics.Events.ReceivedMPSUpdated.Detach(notifyStatus) stopped := make(chan struct{}) - bindAddr := config.Node.GetString(CfgBindAddress) + bindAddr := config.Node().GetString(CfgBindAddress) go func() { log.Infof("%s started, bind-address=%s", PluginName, bindAddr) if err := server.Start(bindAddr); err != nil { diff --git a/plugins/dashboard/routes.go b/plugins/dashboard/routes.go index 63084bab4b4fa5d67dd747a27a5fa74f55f63e8f..5ae146bff14c2e27d746b23488309af7bb1de703 100644 --- a/plugins/dashboard/routes.go +++ b/plugins/dashboard/routes.go @@ -28,7 +28,7 @@ var appBox = packr.New("Dashboard_App", "./frontend/build") var assetsBox = packr.New("Dashboard_Assets", "./frontend/src/assets") func indexRoute(e echo.Context) error { - if config.Node.GetBool(CfgDev) { + if config.Node().GetBool(CfgDev) { res, err := http.Get("http://127.0.0.1:9090/") if err != nil { return err @@ -48,7 +48,7 @@ func indexRoute(e echo.Context) error { func setupRoutes(e *echo.Echo) { - if config.Node.GetBool("dashboard.dev") { + if config.Node().GetBool("dashboard.dev") { e.Static("/assets", "./plugins/dashboard/frontend/src/assets") } else { diff --git a/plugins/dashboard/visualizer.go b/plugins/dashboard/visualizer.go index 2725f40dcf2a997a3ee7f44d9f1bd206e345a1b7..fab0c7c5955ff1a1ebed3742536299a991695a1e 100644 --- a/plugins/dashboard/visualizer.go +++ b/plugins/dashboard/visualizer.go @@ -80,14 +80,14 @@ func runVisualizer() { }) if err := daemon.BackgroundWorker("Dashboard[Visualizer]", func(shutdownSignal <-chan struct{}) { - messagelayer.Tangle.Events.MessageAttached.Attach(notifyNewMsg) - defer messagelayer.Tangle.Events.MessageAttached.Detach(notifyNewMsg) - messagelayer.Tangle.Events.MessageSolid.Attach(notifyNewMsg) - defer messagelayer.Tangle.Events.MessageSolid.Detach(notifyNewMsg) - messagelayer.TipSelector.Events.TipAdded.Attach(notifyNewTip) - defer messagelayer.TipSelector.Events.TipAdded.Detach(notifyNewTip) - messagelayer.TipSelector.Events.TipRemoved.Attach(notifyDeletedTip) - defer messagelayer.TipSelector.Events.TipRemoved.Detach(notifyDeletedTip) + messagelayer.Tangle().Events.MessageAttached.Attach(notifyNewMsg) + defer messagelayer.Tangle().Events.MessageAttached.Detach(notifyNewMsg) + messagelayer.Tangle().Events.MessageSolid.Attach(notifyNewMsg) + defer messagelayer.Tangle().Events.MessageSolid.Detach(notifyNewMsg) + messagelayer.TipSelector().Events.TipAdded.Attach(notifyNewTip) + defer messagelayer.TipSelector().Events.TipAdded.Detach(notifyNewTip) + messagelayer.TipSelector().Events.TipRemoved.Attach(notifyDeletedTip) + defer messagelayer.TipSelector().Events.TipRemoved.Detach(notifyDeletedTip) visualizerWorkerPool.Start() <-shutdownSignal log.Info("Stopping Dashboard[Visualizer] ...") diff --git a/plugins/dashboard/ws.go b/plugins/dashboard/ws.go index 7092edfcb4b7ecd60069b548422219109e4c8b48..3288d77d6429b7429f19ea88efac0fdb25b77512 100644 --- a/plugins/dashboard/ws.go +++ b/plugins/dashboard/ws.go @@ -48,7 +48,7 @@ func configureWebSocketWorkerPool() { broadcastWsMessage(&wsmsg{MsgTypeMPSMetric, task.Param(0).(uint64)}) broadcastWsMessage(&wsmsg{MsgTypeNodeStatus, currentNodeStatus()}) broadcastWsMessage(&wsmsg{MsgTypeNeighborMetric, neighborMetrics()}) - broadcastWsMessage(&wsmsg{MsgTypeTipsMetric, messagelayer.TipSelector.TipCount()}) + broadcastWsMessage(&wsmsg{MsgTypeTipsMetric, messagelayer.TipSelector().TipCount()}) task.Return(nil) }, workerpool.WorkerCount(wsSendWorkerCount), workerpool.QueueSize(wsSendWorkerQueueSize)) } diff --git a/plugins/database/plugin.go b/plugins/database/plugin.go index 1886ddb2db1e35236952cf24282b55d17cbefce4..a3f4d25cd7c4e97c4869f076b5c8861cc3aa5961 100644 --- a/plugins/database/plugin.go +++ b/plugins/database/plugin.go @@ -19,15 +19,24 @@ import ( const PluginName = "Database" var ( - // Plugin is the plugin instance of the database plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure) - log *logger.Logger + // plugin is the plugin instance of the database plugin. + plugin *node.Plugin + pluginOnce sync.Once + log *logger.Logger db database.DB store kvstore.KVStore storeOnce sync.Once ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + pluginOnce.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure) + }) + return plugin +} + // Store returns the KVStore instance. func Store() kvstore.KVStore { storeOnce.Do(createStore) @@ -43,10 +52,10 @@ func createStore() { log = logger.NewLogger(PluginName) var err error - if config.Node.GetBool(CfgDatabaseInMemory) { + if config.Node().GetBool(CfgDatabaseInMemory) { db, err = database.NewMemDB() } else { - dbDir := config.Node.GetString(CfgDatabaseDir) + dbDir := config.Node().GetString(CfgDatabaseDir) db, err = database.NewDB(dbDir) } if err != nil { diff --git a/plugins/drng/drng.go b/plugins/drng/drng.go index 0d377b27a08b0f0cf2297cbae52fd5333f387758..6bfebe7c3486544bf9eeef52a1759046d7a71898 100644 --- a/plugins/drng/drng.go +++ b/plugins/drng/drng.go @@ -29,7 +29,7 @@ func configureDRNG() *drng.DRNG { // parse distributed public key of the committee var dpk []byte - if str := config.Node.GetString(CfgDRNGDistributedPubKey); str != "" { + if str := config.Node().GetString(CfgDRNGDistributedPubKey); str != "" { bytes, err := hex.DecodeString(str) if err != nil { log.Warnf("Invalid %s: %s", CfgDRNGDistributedPubKey, err) @@ -42,8 +42,8 @@ func configureDRNG() *drng.DRNG { // configure committee committeeConf := &state.Committee{ - InstanceID: config.Node.GetUint32(CfgDRNGInstanceID), - Threshold: uint8(config.Node.GetUint32(CfgDRNGThreshold)), + InstanceID: config.Node().GetUint32(CfgDRNGInstanceID), + Threshold: uint8(config.Node().GetUint32(CfgDRNGThreshold)), DistributedPK: dpk, Identities: committeeMembers, } @@ -58,7 +58,7 @@ func Instance() *drng.DRNG { } func parseCommitteeMembers() (result []ed25519.PublicKey, err error) { - for _, committeeMember := range config.Node.GetStringSlice(CfgDRNGCommitteeMembers) { + for _, committeeMember := range config.Node().GetStringSlice(CfgDRNGCommitteeMembers) { if committeeMember == "" { continue } diff --git a/plugins/drng/plugin.go b/plugins/drng/plugin.go index 294f564d4884d5654cec07b05caa91bead13072b..041c1d5d0c52ef10f60db8178e216343cd7c5161 100644 --- a/plugins/drng/plugin.go +++ b/plugins/drng/plugin.go @@ -19,13 +19,23 @@ import ( const PluginName = "DRNG" var ( - // Plugin is the plugin instance of the DRNG plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + // plugin is the plugin instance of the DRNG plugin. + plugin *node.Plugin + pluginOnce sync.Once instance *drng.DRNG once sync.Once log *logger.Logger ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + pluginOnce.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + }) + return plugin +} + + func configure(_ *node.Plugin) { configureEvents() } @@ -34,7 +44,7 @@ func run(*node.Plugin) {} func configureEvents() { instance := Instance() - messagelayer.Tangle.Events.MessageSolid.Attach(events.NewClosure(func(cachedMessage *message.CachedMessage, cachedMessageMetadata *tangle.CachedMessageMetadata) { + messagelayer.Tangle().Events.MessageSolid.Attach(events.NewClosure(func(cachedMessage *message.CachedMessage, cachedMessageMetadata *tangle.CachedMessageMetadata) { cachedMessageMetadata.Release() cachedMessage.Consume(func(msg *message.Message) { diff --git a/plugins/gossip/gossip.go b/plugins/gossip/gossip.go index 06162245c0e1f2d51740df2420e6b3b325483225..d08d8e61df133348a9e6113752f3475ac021f331 100644 --- a/plugins/gossip/gossip.go +++ b/plugins/gossip/gossip.go @@ -39,7 +39,7 @@ func createManager() { log := logger.NewLogger(PluginName) // announce the gossip service - gossipPort := config.Node.GetInt(CfgGossipPort) + gossipPort := config.Node().GetInt(CfgGossipPort) if !netutil.IsValidPort(gossipPort) { log.Fatalf("Invalid port number (%s): %d", CfgGossipPort, gossipPort) } @@ -60,7 +60,7 @@ func start(shutdownSignal <-chan struct{}) { gossipEndpoint := lPeer.Services().Get(service.GossipKey) // resolve the bind address - address := net.JoinHostPort(config.Node.GetString(local.CfgBind), strconv.Itoa(gossipEndpoint.Port())) + address := net.JoinHostPort(config.Node().GetString(local.CfgBind), strconv.Itoa(gossipEndpoint.Port())) localAddr, err := net.ResolveTCPAddr(gossipEndpoint.Network(), address) if err != nil { log.Fatalf("Error resolving %s: %v", local.CfgBind, err) @@ -92,7 +92,7 @@ func start(shutdownSignal <-chan struct{}) { // loads the given message from the message layer or an error if not found. func loadMessage(messageID message.Id) (bytes []byte, err error) { - if !messagelayer.Tangle.Message(messageID).Consume(func(message *message.Message) { + if !messagelayer.Tangle().Message(messageID).Consume(func(message *message.Message) { bytes = message.Bytes() }) { err = ErrMessageNotFound diff --git a/plugins/gossip/plugin.go b/plugins/gossip/plugin.go index dfaaa6ade431e810c11d4aa6f71d27b532491c3e..4e62dc9aa548c3acf6c2a3e35669882aaaa8f765 100644 --- a/plugins/gossip/plugin.go +++ b/plugins/gossip/plugin.go @@ -13,18 +13,29 @@ import ( "github.com/iotaledger/hive.go/events" "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/node" + "sync" ) // PluginName is the name of the gossip plugin. const PluginName = "Gossip" var ( - // Plugin is the plugin instance of the gossip plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + // plugin is the plugin instance of the gossip plugin. + plugin *node.Plugin + once sync.Once log *logger.Logger ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + }) + return plugin +} + + func configure(*node.Plugin) { log = logger.NewLogger(PluginName) @@ -104,11 +115,11 @@ func configureMessageLayer() { // configure flow of incoming messages mgr.Events().MessageReceived.Attach(events.NewClosure(func(event *gossip.MessageReceivedEvent) { - messagelayer.MessageParser.Parse(event.Data, event.Peer) + messagelayer.MessageParser().Parse(event.Data, event.Peer) })) // configure flow of outgoing messages (gossip on solidification) - messagelayer.Tangle.Events.MessageSolid.Attach(events.NewClosure(func(cachedMessage *message.CachedMessage, cachedMessageMetadata *tangle.CachedMessageMetadata) { + messagelayer.Tangle().Events.MessageSolid.Attach(events.NewClosure(func(cachedMessage *message.CachedMessage, cachedMessageMetadata *tangle.CachedMessageMetadata) { cachedMessageMetadata.Release() cachedMessage.Consume(func(msg *message.Message) { mgr.SendMessage(msg.Bytes()) @@ -116,7 +127,7 @@ func configureMessageLayer() { })) // request missing messages - messagelayer.MessageRequester.Events.SendRequest.Attach(events.NewClosure(func(messageId message.Id) { + messagelayer.MessageRequester().Events.SendRequest.Attach(events.NewClosure(func(messageId message.Id) { mgr.RequestMessage(messageId[:]) })) } diff --git a/plugins/gracefulshutdown/plugin.go b/plugins/gracefulshutdown/plugin.go index 4caf49139575307ac26f07f8b6d9244ae147a485..efa546494613457530faeeb0309693aa954d1d4b 100644 --- a/plugins/gracefulshutdown/plugin.go +++ b/plugins/gracefulshutdown/plugin.go @@ -5,6 +5,7 @@ import ( "os/signal" "sort" "strings" + "sync" "syscall" "time" @@ -20,45 +21,56 @@ const PluginName = "Graceful Shutdown" // After that the process is killed. const WaitToKillTimeInSeconds = 60 -var log *logger.Logger -var gracefulStop chan os.Signal +var ( + // plugin is the plugin instance of the graceful shutdown plugin. + plugin *node.Plugin + once sync.Once + log *logger.Logger + gracefulStop chan os.Signal +) -// Plugin is the plugin instance of the graceful shutdown plugin. -var Plugin = node.NewPlugin(PluginName, node.Enabled, func(plugin *node.Plugin) { - log = logger.NewLogger(PluginName) - gracefulStop = make(chan os.Signal) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, func(plugin *node.Plugin) { + log = logger.NewLogger(PluginName) + gracefulStop = make(chan os.Signal) - signal.Notify(gracefulStop, syscall.SIGTERM) - signal.Notify(gracefulStop, syscall.SIGINT) + signal.Notify(gracefulStop, syscall.SIGTERM) + signal.Notify(gracefulStop, syscall.SIGINT) - go func() { - <-gracefulStop + go func() { + <-gracefulStop - log.Warnf("Received shutdown request - waiting (max %d) to finish processing ...", WaitToKillTimeInSeconds) + log.Warnf("Received shutdown request - waiting (max %d) to finish processing ...", WaitToKillTimeInSeconds) - go func() { - start := time.Now() - for x := range time.Tick(1 * time.Second) { - secondsSinceStart := x.Sub(start).Seconds() + go func() { + start := time.Now() + for x := range time.Tick(1 * time.Second) { + secondsSinceStart := x.Sub(start).Seconds() - if secondsSinceStart <= WaitToKillTimeInSeconds { - processList := "" - runningBackgroundWorkers := daemon.GetRunningBackgroundWorkers() - if len(runningBackgroundWorkers) >= 1 { - sort.Strings(runningBackgroundWorkers) - processList = "(" + strings.Join(runningBackgroundWorkers, ", ") + ") " + if secondsSinceStart <= WaitToKillTimeInSeconds { + processList := "" + runningBackgroundWorkers := daemon.GetRunningBackgroundWorkers() + if len(runningBackgroundWorkers) >= 1 { + sort.Strings(runningBackgroundWorkers) + processList = "(" + strings.Join(runningBackgroundWorkers, ", ") + ") " + } + log.Warnf("Received shutdown request - waiting (max %d seconds) to finish processing %s...", WaitToKillTimeInSeconds-int(secondsSinceStart), processList) + } else { + log.Error("Background processes did not terminate in time! Forcing shutdown ...") + os.Exit(1) + } } - log.Warnf("Received shutdown request - waiting (max %d seconds) to finish processing %s...", WaitToKillTimeInSeconds-int(secondsSinceStart), processList) - } else { - log.Error("Background processes did not terminate in time! Forcing shutdown ...") - os.Exit(1) - } - } - }() + }() + + daemon.Shutdown() + }() + }) + }) + return plugin +} - daemon.Shutdown() - }() -}) // ShutdownWithError prints out an error message and shuts down the default daemon instance. func ShutdownWithError(err error) { diff --git a/plugins/issuer/plugin.go b/plugins/issuer/plugin.go index d34e6f3621499a77771f55653ff9b6f29254b6fb..8bc87008fb963db0da6737cc7ebfe52dbe12efc7 100644 --- a/plugins/issuer/plugin.go +++ b/plugins/issuer/plugin.go @@ -2,6 +2,7 @@ package issuer import ( "fmt" + goSync "sync" "github.com/iotaledger/goshimmer/packages/binary/messagelayer/message" "github.com/iotaledger/goshimmer/packages/binary/messagelayer/payload" @@ -14,10 +15,20 @@ import ( const PluginName = "Issuer" var ( - // Plugin is the plugin instance of the issuer plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure) + // plugin is the plugin instance of the issuer plugin. + plugin *node.Plugin + once goSync.Once + ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure) + }) + return plugin +} + func configure(_ *node.Plugin) {} // IssuePayload issues a payload to the message layer. @@ -26,5 +37,5 @@ func IssuePayload(payload payload.Payload) (*message.Message, error) { if !sync.Synced() { return nil, fmt.Errorf("can't issue payload: %w", sync.ErrNodeNotSynchronized) } - return messagelayer.MessageFactory.IssuePayload(payload), nil + return messagelayer.MessageFactory().IssuePayload(payload), nil } diff --git a/plugins/logger/plugin.go b/plugins/logger/plugin.go index ebe1430995db139074114058d7774b5a4d3ba577..5ab85c84f05b9e926536fc3998f88b48d7c8bbf3 100644 --- a/plugins/logger/plugin.go +++ b/plugins/logger/plugin.go @@ -5,24 +5,39 @@ import ( "github.com/iotaledger/hive.go/events" "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/node" + "sync" ) // PluginName is the name of the logger plugin. const PluginName = "Logger" -// Plugin is the plugin instance of the logger plugin. -var Plugin = node.NewPlugin(PluginName, node.Enabled) +var ( + // plugin is the plugin instance of the logger plugin. + plugin *node.Plugin + once sync.Once +) + +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled) + }) + return plugin +} + // Init triggers the Init event. func Init() { - Plugin.Events.Init.Trigger(Plugin) + plugin.Events.Init.Trigger(plugin) } func init() { + plugin = Plugin() + initFlags() - Plugin.Events.Init.Attach(events.NewClosure(func(*node.Plugin) { - if err := logger.InitGlobalLogger(config.Node); err != nil { + plugin.Events.Init.Attach(events.NewClosure(func(*node.Plugin) { + if err := logger.InitGlobalLogger(config.Node()); err != nil { panic(err) } })) diff --git a/plugins/messagelayer/plugin.go b/plugins/messagelayer/plugin.go index ca1fb0e535950b01ec4c74816aae0c30141682bb..d43792edc02368fc39c11c15732f6ba5ded2f8b0 100644 --- a/plugins/messagelayer/plugin.go +++ b/plugins/messagelayer/plugin.go @@ -1,6 +1,8 @@ package messagelayer import ( + "sync" + "github.com/iotaledger/goshimmer/packages/binary/messagelayer/message" "github.com/iotaledger/goshimmer/packages/binary/messagelayer/messagefactory" "github.com/iotaledger/goshimmer/packages/binary/messagelayer/messageparser" @@ -23,68 +25,122 @@ const ( ) var ( - // Plugin is the plugin instance of the message layer plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) - MessageParser *messageparser.MessageParser - MessageRequester *messagerequester.MessageRequester - TipSelector *tipselector.TipSelector - Tangle *tangle.Tangle - MessageFactory *messagefactory.MessageFactory + // plugin is the plugin instance of the message layer plugin. + plugin *node.Plugin + pluginOnce sync.Once + messageParser *messageparser.MessageParser + msgParserOnce sync.Once + messageRequester *messagerequester.MessageRequester + msgReqOnce sync.Once + tipSelector *tipselector.TipSelector + tipSelectorOnce sync.Once + _tangle *tangle.Tangle + tangleOnce sync.Once + messageFactory *messagefactory.MessageFactory + msgFactoryOnce sync.Once log *logger.Logger ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + pluginOnce.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + }) + return plugin +} + +// MessageParser gets the messageParser instance. +func MessageParser() *messageparser.MessageParser { + msgParserOnce.Do(func() { + messageParser = messageparser.New() + }) + return messageParser +} + +// TipSelector gets the tipSelector instance. +func TipSelector() *tipselector.TipSelector { + tipSelectorOnce.Do(func() { + tipSelector = tipselector.New() + }) + return tipSelector +} + +// Tangle gets the tangle instance. +func Tangle() *tangle.Tangle { + tangleOnce.Do(func() { + store := database.Store() + _tangle = tangle.New(store) + }) + return _tangle +} + +// MessageFactory gets the messageFactory instance. +func MessageFactory() *messagefactory.MessageFactory { + msgFactoryOnce.Do(func() { + messageFactory = messagefactory.New(database.Store(), []byte(DBSequenceNumber), local.GetInstance().LocalIdentity(), TipSelector()) + }) + return messageFactory +} + +// MessageRequester gets the messageRequester instance. +func MessageRequester() *messagerequester.MessageRequester { + msgReqOnce.Do(func() { + messageRequester = messagerequester.New() + }) + return messageRequester +} + func configure(*node.Plugin) { log = logger.NewLogger(PluginName) - store := database.Store() // create instances - MessageParser = messageparser.New() - MessageRequester = messagerequester.New() - TipSelector = tipselector.New() - Tangle = tangle.New(store) - - // Setup MessageFactory (behavior + logging)) - MessageFactory = messagefactory.New(database.Store(), []byte(DBSequenceNumber), local.GetInstance().LocalIdentity(), TipSelector) - MessageFactory.Events.MessageConstructed.Attach(events.NewClosure(Tangle.AttachMessage)) - MessageFactory.Events.Error.Attach(events.NewClosure(func(err error) { + messageParser = MessageParser() + messageRequester = MessageRequester() + tipSelector = TipSelector() + _tangle = Tangle() + + // Setup messageFactory (behavior + logging)) + messageFactory = MessageFactory() + messageFactory.Events.MessageConstructed.Attach(events.NewClosure(_tangle.AttachMessage)) + messageFactory.Events.Error.Attach(events.NewClosure(func(err error) { log.Errorf("internal error in message factory: %v", err) })) - // setup MessageParser - MessageParser.Events.MessageParsed.Attach(events.NewClosure(func(msg *message.Message, peer *peer.Peer) { + // setup messageParser + messageParser.Events.MessageParsed.Attach(events.NewClosure(func(msg *message.Message, peer *peer.Peer) { // TODO: ADD PEER - Tangle.AttachMessage(msg) + _tangle.AttachMessage(msg) })) - // setup MessageRequester - Tangle.Events.MessageMissing.Attach(events.NewClosure(MessageRequester.ScheduleRequest)) - Tangle.Events.MissingMessageReceived.Attach(events.NewClosure(func(cachedMessage *message.CachedMessage, cachedMessageMetadata *tangle.CachedMessageMetadata) { + // setup messageRequester + _tangle.Events.MessageMissing.Attach(events.NewClosure(messageRequester.ScheduleRequest)) + _tangle.Events.MissingMessageReceived.Attach(events.NewClosure(func(cachedMessage *message.CachedMessage, cachedMessageMetadata *tangle.CachedMessageMetadata) { cachedMessageMetadata.Release() cachedMessage.Consume(func(msg *message.Message) { - MessageRequester.StopRequest(msg.Id()) + messageRequester.StopRequest(msg.Id()) }) })) - // setup TipSelector - Tangle.Events.MessageSolid.Attach(events.NewClosure(func(cachedMessage *message.CachedMessage, cachedMessageMetadata *tangle.CachedMessageMetadata) { + // setup tipSelector + _tangle.Events.MessageSolid.Attach(events.NewClosure(func(cachedMessage *message.CachedMessage, cachedMessageMetadata *tangle.CachedMessageMetadata) { cachedMessageMetadata.Release() - cachedMessage.Consume(TipSelector.AddTip) + cachedMessage.Consume(tipSelector.AddTip) })) } func run(*node.Plugin) { - if err := daemon.BackgroundWorker("Tangle[MissingMessagesMonitor]", func(shutdownSignal <-chan struct{}) { - Tangle.MonitorMissingMessages(shutdownSignal) + if err := daemon.BackgroundWorker("_tangle[MissingMessagesMonitor]", func(shutdownSignal <-chan struct{}) { + _tangle.MonitorMissingMessages(shutdownSignal) }, shutdown.PriorityMissingMessagesMonitoring); err != nil { log.Panicf("Failed to start as daemon: %s", err) } - if err := daemon.BackgroundWorker("Tangle", func(shutdownSignal <-chan struct{}) { + if err := daemon.BackgroundWorker("_tangle", func(shutdownSignal <-chan struct{}) { <-shutdownSignal - MessageFactory.Shutdown() - MessageParser.Shutdown() - Tangle.Shutdown() + messageFactory.Shutdown() + messageParser.Shutdown() + _tangle.Shutdown() }, shutdown.PriorityTangle); err != nil { log.Panicf("Failed to start as daemon: %s", err) } diff --git a/plugins/metrics/message.go b/plugins/metrics/message.go index 569ba349121fc41018d2527fa7d4c68fc86796ef..927ce519c53aa8da031b1dd116d69682885fefb2 100644 --- a/plugins/metrics/message.go +++ b/plugins/metrics/message.go @@ -66,7 +66,7 @@ func increasePerPayloadCounter(p payload.Type) { } func measureMessageTips() { - metrics.Events().MessageTips.Trigger((uint64)(messagelayer.TipSelector.TipCount())) + metrics.Events().MessageTips.Trigger((uint64)(messagelayer.TipSelector().TipCount())) } // ReceivedMessagesPerSecond retrieves the current messages per second number. diff --git a/plugins/metrics/message_test.go b/plugins/metrics/message_test.go index 3d1eb537111765793333480cb3f20157c6cb5e23..bdf7925a2a2cc979ca13dc62ed831423ccf1afa4 100644 --- a/plugins/metrics/message_test.go +++ b/plugins/metrics/message_test.go @@ -7,7 +7,6 @@ import ( valuepayload "github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/payload" drngpayload "github.com/iotaledger/goshimmer/packages/binary/drng/payload" "github.com/iotaledger/goshimmer/packages/binary/messagelayer/payload" - "github.com/iotaledger/goshimmer/packages/binary/messagelayer/tipselector" "github.com/iotaledger/goshimmer/packages/metrics" "github.com/iotaledger/goshimmer/plugins/messagelayer" "github.com/iotaledger/hive.go/events" @@ -34,7 +33,7 @@ func TestMessageCountPerPayload(t *testing.T) { func TestMessageTips(t *testing.T) { var wg sync.WaitGroup // messagelayer TipSelector not configured here, so to avoid nil pointer panic, we instantiate it - messagelayer.TipSelector = tipselector.New() + messagelayer.TipSelector() metrics.Events().MessageTips.Attach(events.NewClosure(func(tips uint64) { messageTips.Store(tips) wg.Done() diff --git a/plugins/metrics/plugin.go b/plugins/metrics/plugin.go index c7c295f17667e0167c1242f2d66395acfe70ec7c..a60b7be6f95dfdd1d71a5e105eedb420687e3527 100644 --- a/plugins/metrics/plugin.go +++ b/plugins/metrics/plugin.go @@ -1,6 +1,7 @@ package metrics import ( + "sync" "time" "github.com/iotaledger/goshimmer/dapps/valuetransfers" @@ -27,30 +28,38 @@ import ( const PluginName = "Metrics" var ( - // Plugin is the plugin instance of the metrics plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) - - log *logger.Logger + // plugin is the plugin instance of the metrics plugin. + plugin *node.Plugin + once sync.Once + log *logger.Logger ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + }) + return plugin +} + func configure(_ *node.Plugin) { log = logger.NewLogger(PluginName) } func run(_ *node.Plugin) { - if config.Node.GetBool(CfgMetricsLocal) { + if config.Node().GetBool(CfgMetricsLocal) { registerLocalMetrics() } // Events from analysis server - if config.Node.GetBool(CfgMetricsGlobal) { + if config.Node().GetBool(CfgMetricsGlobal) { server.Events.MetricHeartbeat.Attach(onMetricHeartbeatReceived) } // create a background worker that update the metrics every second if err := daemon.BackgroundWorker("Metrics Updater", func(shutdownSignal <-chan struct{}) { - if config.Node.GetBool(CfgMetricsLocal) { + if config.Node().GetBool(CfgMetricsLocal) { timeutil.Ticker(func() { measureCPUUsage() measureMemUsage() @@ -65,7 +74,7 @@ func run(_ *node.Plugin) { gossipCurrentTx.Store(uint64(g.BytesWritten)) }, 1*time.Second, shutdownSignal) } - if config.Node.GetBool(CfgMetricsGlobal) { + if config.Node().GetBool(CfgMetricsGlobal) { timeutil.Ticker(calculateNetworkDiameter, 1*time.Minute, shutdownSignal) } @@ -78,7 +87,7 @@ func registerLocalMetrics() { //// Events declared in other packages which we want to listen to here //// // increase received MPS counter whenever we attached a message - messagelayer.Tangle.Events.MessageAttached.Attach(events.NewClosure(func(cachedMessage *message.CachedMessage, cachedMessageMetadata *tangle.CachedMessageMetadata) { + messagelayer.Tangle().Events.MessageAttached.Attach(events.NewClosure(func(cachedMessage *message.CachedMessage, cachedMessageMetadata *tangle.CachedMessageMetadata) { _payloadType := cachedMessage.Unwrap().Payload().Type() cachedMessage.Release() cachedMessageMetadata.Release() @@ -87,7 +96,7 @@ func registerLocalMetrics() { })) // Value payload attached - valuetransfers.Tangle.Events.PayloadAttached.Attach(events.NewClosure(func(cachedPayload *payload.CachedPayload, cachedPayloadMetadata *valuetangle.CachedPayloadMetadata) { + valuetransfers.Tangle().Events.PayloadAttached.Attach(events.NewClosure(func(cachedPayload *payload.CachedPayload, cachedPayloadMetadata *valuetangle.CachedPayloadMetadata) { cachedPayload.Release() cachedPayloadMetadata.Release() valueTransactionCounter.Inc() diff --git a/plugins/portcheck/plugin.go b/plugins/portcheck/plugin.go index 85ac7a6d034c2110d4b2b6a565a6d48b0382eddc..e1b6845b0c9f000e19a720876afe5756a24749d6 100644 --- a/plugins/portcheck/plugin.go +++ b/plugins/portcheck/plugin.go @@ -2,6 +2,7 @@ package portcheck import ( "net" + "sync" "github.com/iotaledger/goshimmer/plugins/autopeering" "github.com/iotaledger/goshimmer/plugins/autopeering/local" @@ -17,11 +18,20 @@ import ( const PluginName = "PortCheck" var ( - // Plugin is the plugin instance of the port check plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + // plugin is the plugin instance of the port check plugin. + plugin *node.Plugin + once sync.Once log *logger.Logger ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + }) + return plugin +} + func configure(*node.Plugin) { log = logger.NewLogger(PluginName) } @@ -49,7 +59,7 @@ func checkAutopeeringConnection() { defer conn.Close() // create a new discovery server for the port check - disc := discover.New(local.GetInstance(), autopeering.ProtocolVersion, autopeering.NetworkID, discover.Logger(log)) + disc := discover.New(local.GetInstance(), autopeering.ProtocolVersion, autopeering.NetworkID(), discover.Logger(log)) srv := server.Serve(local.GetInstance(), conn, log, disc) defer srv.Close() diff --git a/plugins/pow/plugin.go b/plugins/pow/plugin.go index 1660eecb7218f1fd39b9a0dbdd5e8423f7f2b058..90b76e0c2f9c12eda2620417554ce286e4c95e65 100644 --- a/plugins/pow/plugin.go +++ b/plugins/pow/plugin.go @@ -20,7 +20,7 @@ func run(*node.Plugin) { // assure that the logger is available log := logger.NewLogger(PluginName) - if node.IsSkipped(messagelayer.Plugin) { + if node.IsSkipped(messagelayer.Plugin()) { log.Infof("%s is disabled; skipping %s\n", messagelayer.PluginName, PluginName) return } @@ -28,6 +28,6 @@ func run(*node.Plugin) { // assure that the PoW worker is initialized worker := Worker() - messagelayer.MessageParser.AddBytesFilter(builtinfilters.NewPowFilter(worker, difficulty)) - messagelayer.MessageFactory.SetWorker(messagefactory.WorkerFunc(DoPOW)) + messagelayer.MessageParser().AddBytesFilter(builtinfilters.NewPowFilter(worker, difficulty)) + messagelayer.MessageFactory().SetWorker(messagefactory.WorkerFunc(DoPOW)) } diff --git a/plugins/pow/pow.go b/plugins/pow/pow.go index c547d4ae6f78f342b226b42ec794fdca543a7f3c..69207f5b6792ae48585dcaa3c81e3cd0d6ba7225 100644 --- a/plugins/pow/pow.go +++ b/plugins/pow/pow.go @@ -41,9 +41,9 @@ func Worker() *pow.Worker { workerOnce.Do(func() { log = logger.NewLogger(PluginName) // load the parameters - difficulty = config.Node.GetInt(CfgPOWDifficulty) - numWorkers = config.Node.GetInt(CfgPOWNumThreads) - timeout = config.Node.GetDuration(CfgPOWTimeout) + difficulty = config.Node().GetInt(CfgPOWDifficulty) + numWorkers = config.Node().GetInt(CfgPOWNumThreads) + timeout = config.Node().GetDuration(CfgPOWTimeout) // create the worker worker = pow.New(hash, numWorkers) }) diff --git a/plugins/profiling/plugin.go b/plugins/profiling/plugin.go index 388da6453312ed18e7a030241dafbe03eb7af109..4ab416d6e41f3bad7750d2ef7cd9ff3a6c015714 100644 --- a/plugins/profiling/plugin.go +++ b/plugins/profiling/plugin.go @@ -3,6 +3,7 @@ package profiling import ( "net/http" "runtime" + "sync" // import required to profile _ "net/http/pprof" @@ -17,14 +18,23 @@ import ( const PluginName = "Profiling" var ( - // Plugin is the profiling plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + // plugin is the profiling plugin. + plugin *node.Plugin + once sync.Once log *logger.Logger ) // CfgProfilingBindAddress defines the config flag of the profiling binding address. const CfgProfilingBindAddress = "profiling.bindAddress" +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + }) + return plugin +} + func init() { flag.String(CfgProfilingBindAddress, "127.0.0.1:6061", "bind address for the pprof server") } @@ -34,7 +44,7 @@ func configure(_ *node.Plugin) { } func run(_ *node.Plugin) { - bindAddr := config.Node.GetString(CfgProfilingBindAddress) + bindAddr := config.Node().GetString(CfgProfilingBindAddress) runtime.SetMutexProfileFraction(5) runtime.SetBlockProfileRate(5) diff --git a/plugins/prometheus/db_size.go b/plugins/prometheus/db_size.go index 99408a8e692fea1d8633da4ac7c52d66d6302bf7..df6e1372ed97805b0c1a22d3c72d37608ff3eab9 100644 --- a/plugins/prometheus/db_size.go +++ b/plugins/prometheus/db_size.go @@ -27,7 +27,7 @@ func registerDBMetrics() { } func collectDBSize() { - size, err := directorySize(config.Node.GetString(database.CfgDatabaseDir)) + size, err := directorySize(config.Node().GetString(database.CfgDatabaseDir)) if err == nil { dbSize.Set(float64(size)) } diff --git a/plugins/prometheus/plugin.go b/plugins/prometheus/plugin.go index 8aa2f765e07ed52910b7e66ce7327827ca4213e4..5f32a260f1d88e7b54efab6614f7709b0e71c207 100644 --- a/plugins/prometheus/plugin.go +++ b/plugins/prometheus/plugin.go @@ -29,14 +29,14 @@ var ( func configure(plugin *node.Plugin) { log = logger.NewLogger(plugin.Name) - if config.Node.GetBool(CfgPrometheusGoMetrics) { + if config.Node().GetBool(CfgPrometheusGoMetrics) { registry.MustRegister(prometheus.NewGoCollector()) } - if config.Node.GetBool(CfgPrometheusProcessMetrics) { + if config.Node().GetBool(CfgPrometheusProcessMetrics) { registry.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{})) } - if config.Node.GetBool(metrics.CfgMetricsLocal) { + if config.Node().GetBool(metrics.CfgMetricsLocal) { registerAutopeeringMetrics() registerDBMetrics() registerFPCMetrics() @@ -46,7 +46,7 @@ func configure(plugin *node.Plugin) { registerTangleMetrics() } - if config.Node.GetBool(metrics.CfgMetricsGlobal) { + if config.Node().GetBool(metrics.CfgMetricsGlobal) { registerClientsMetrics() } } @@ -73,13 +73,13 @@ func run(plugin *node.Plugin) { EnableOpenMetrics: true, }, ) - if config.Node.GetBool(CfgPrometheusPromhttpMetrics) { + if config.Node().GetBool(CfgPrometheusPromhttpMetrics) { handler = promhttp.InstrumentMetricHandler(registry, handler) } handler.ServeHTTP(c.Writer, c.Request) }) - bindAddr := config.Node.GetString(CfgPrometheusBindAddress) + bindAddr := config.Node().GetString(CfgPrometheusBindAddress) server = &http.Server{Addr: bindAddr, Handler: engine} go func() { diff --git a/plugins/remotelog/plugin.go b/plugins/remotelog/plugin.go index 298038d337d303007ce73879fe92d942e3006791..6d4e6f9ae0fa1b176b11d79b3f2cfd85cd7be630 100644 --- a/plugins/remotelog/plugin.go +++ b/plugins/remotelog/plugin.go @@ -36,8 +36,9 @@ const ( ) var ( - // Plugin is the plugin instance of the remote plugin instance. - Plugin = node.NewPlugin(PluginName, node.Disabled, configure, run) + // plugin is the plugin instance of the remote plugin instance. + plugin *node.Plugin + pluginOnce sync.Once log *logger.Logger myID string myGitHead string @@ -48,6 +49,14 @@ var ( remoteLoggerOnce sync.Once ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + pluginOnce.Do(func() { + plugin = node.NewPlugin(PluginName, node.Disabled, configure, run) + }) + return plugin +} + func init() { flag.String(CfgLoggerRemotelogServerAddress, "remotelog.goshimmer.iota.cafe:5213", "RemoteLog server address") } @@ -55,7 +64,7 @@ func init() { func configure(plugin *node.Plugin) { log = logger.NewLogger(PluginName) - if config.Node.GetBool(CfgDisableEvents) { + if config.Node().GetBool(CfgDisableEvents) { log.Fatalf("%s in config.json needs to be false so that events can be captured!", CfgDisableEvents) return } @@ -151,7 +160,7 @@ func getGitDir() string { // RemoteLogger represents a connection to our remote log server. func RemoteLogger() *RemoteLoggerConn { remoteLoggerOnce.Do(func() { - r, err := newRemoteLoggerConn(config.Node.GetString(CfgLoggerRemotelogServerAddress)) + r, err := newRemoteLoggerConn(config.Node().GetString(CfgLoggerRemotelogServerAddress)) if err != nil { log.Fatal(err) return diff --git a/plugins/sync/plugin.go b/plugins/sync/plugin.go index 5a08344855585bbdb2a9d140205ff91126a2f657..738285a9dea335578d4e3f2d0488cc07df42b45d 100644 --- a/plugins/sync/plugin.go +++ b/plugins/sync/plugin.go @@ -49,8 +49,9 @@ func init() { } var ( - // Plugin is the plugin instance of the sync plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + // plugin is the plugin instance of the sync plugin. + plugin *node.Plugin + once sync.Once // ErrNodeNotSynchronized is returned when an operation can't be executed because // the node is not synchronized. ErrNodeNotSynchronized = errors.New("node is not synchronized") @@ -59,6 +60,14 @@ var ( log *logger.Logger ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + }) + return plugin +} + // Synced tells whether the node is in a state we consider synchronized, meaning // it has the relevant past and present message data. func Synced() bool { @@ -133,10 +142,10 @@ func monitorForDesynchronization() { if err := daemon.BackgroundWorker("Desync-Monitor", func(shutdownSignal <-chan struct{}) { gossip.Manager().Events().NeighborRemoved.Attach(monitorPeerCountClosure) defer gossip.Manager().Events().NeighborRemoved.Detach(monitorPeerCountClosure) - messagelayer.Tangle.Events.MessageAttached.Attach(monitorMessageInflowClosure) - defer messagelayer.Tangle.Events.MessageAttached.Detach(monitorMessageInflowClosure) + messagelayer.Tangle().Events.MessageAttached.Attach(monitorMessageInflowClosure) + defer messagelayer.Tangle().Events.MessageAttached.Detach(monitorMessageInflowClosure) - desyncedIfNoMessageInSec := config.Node.GetDuration(CfgSyncDesyncedIfNoMessageAfterSec) * time.Second + desyncedIfNoMessageInSec := config.Node().GetDuration(CfgSyncDesyncedIfNoMessageAfterSec) * time.Second timer := time.NewTimer(desyncedIfNoMessageInSec) for { select { @@ -171,7 +180,7 @@ func monitorForDesynchronization() { // starts a background worker and event handlers to check whether the node is synchronized by first collecting // a set of newly received messages and then waiting for them to become solid. func monitorForSynchronization() { - wantedAnchorPointsCount := config.Node.GetInt(CfgSyncAnchorPointsCount) + wantedAnchorPointsCount := config.Node().GetInt(CfgSyncAnchorPointsCount) anchorPoints := newAnchorPoints(wantedAnchorPointsCount) log.Infof("monitoring for synchronization, awaiting %d anchor point messages to become solid", wantedAnchorPointsCount) @@ -203,13 +212,13 @@ func monitorForSynchronization() { }) if err := daemon.BackgroundWorker("Sync-Monitor", func(shutdownSignal <-chan struct{}) { - messagelayer.Tangle.Events.MessageAttached.Attach(initAnchorPointClosure) - defer messagelayer.Tangle.Events.MessageAttached.Detach(initAnchorPointClosure) - messagelayer.Tangle.Events.MessageSolid.Attach(checkAnchorPointSolidityClosure) - defer messagelayer.Tangle.Events.MessageSolid.Detach(checkAnchorPointSolidityClosure) + messagelayer.Tangle().Events.MessageAttached.Attach(initAnchorPointClosure) + defer messagelayer.Tangle().Events.MessageAttached.Detach(initAnchorPointClosure) + messagelayer.Tangle().Events.MessageSolid.Attach(checkAnchorPointSolidityClosure) + defer messagelayer.Tangle().Events.MessageSolid.Detach(checkAnchorPointSolidityClosure) - cleanupDelta := config.Node.GetDuration(CfgSyncAnchorPointsCleanupAfterSec) * time.Second - ticker := time.NewTimer(config.Node.GetDuration(CfgSyncAnchorPointsCleanupIntervalSec) * time.Second) + cleanupDelta := config.Node().GetDuration(CfgSyncAnchorPointsCleanupAfterSec) * time.Second + ticker := time.NewTimer(config.Node().GetDuration(CfgSyncAnchorPointsCleanupIntervalSec) * time.Second) defer ticker.Stop() for { select { diff --git a/plugins/webapi/autopeering/plugin.go b/plugins/webapi/autopeering/plugin.go index 0267831b63819f1495c4ae4a373cf816ac3486f2..9b046602fe5a00cafbc752b64f60ea7a1c72cbb0 100644 --- a/plugins/webapi/autopeering/plugin.go +++ b/plugins/webapi/autopeering/plugin.go @@ -4,6 +4,7 @@ import ( "net" "net/http" "strconv" + "sync" "github.com/iotaledger/goshimmer/plugins/autopeering" "github.com/iotaledger/goshimmer/plugins/webapi" @@ -16,11 +17,22 @@ import ( // PluginName is the name of the web API autopeering endpoint plugin. const PluginName = "WebAPI autopeering Endpoint" -// Plugin is the plugin instance of the web API autopeering endpoint plugin. -var Plugin = node.NewPlugin(PluginName, node.Enabled, configure) +var ( + // plugin is the plugin instance of the web API autopeering endpoint plugin. + plugin *node.Plugin + once sync.Once +) func configure(plugin *node.Plugin) { - webapi.Server.GET("autopeering/neighbors", getNeighbors) + webapi.Server().GET("autopeering/neighbors", getNeighbors) +} + +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure) + }) + return plugin } // getNeighbors returns the chosen and accepted neighbors of the node diff --git a/plugins/webapi/data/plugin.go b/plugins/webapi/data/plugin.go index 83d86d267015c60a4254b340f2796ac6812c5e0e..91f683f5299017a731db018a1cdeb0d17b072320 100644 --- a/plugins/webapi/data/plugin.go +++ b/plugins/webapi/data/plugin.go @@ -2,6 +2,7 @@ package data import ( "net/http" + "sync" "github.com/iotaledger/goshimmer/packages/binary/messagelayer/payload" "github.com/iotaledger/goshimmer/plugins/issuer" @@ -15,14 +16,23 @@ import ( const PluginName = "WebAPI data Endpoint" var ( - // Plugin is the plugin instance of the web API data endpoint plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure) + // plugin is the plugin instance of the web API data endpoint plugin. + plugin *node.Plugin + once sync.Once log *logger.Logger ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure) + }) + return plugin +} + func configure(plugin *node.Plugin) { log = logger.NewLogger(PluginName) - webapi.Server.POST("data", broadcastData) + webapi.Server().POST("data", broadcastData) } // broadcastData creates a message of the given payload and diff --git a/plugins/webapi/drng/plugin.go b/plugins/webapi/drng/plugin.go index b9e542c6c512342c79e04d16c96126fa03a65e9a..d2a89ec67c693e31dbdda4c0ad2e48d5a95d2a27 100644 --- a/plugins/webapi/drng/plugin.go +++ b/plugins/webapi/drng/plugin.go @@ -6,18 +6,28 @@ import ( "github.com/iotaledger/goshimmer/plugins/webapi/drng/info/committee" "github.com/iotaledger/goshimmer/plugins/webapi/drng/info/randomness" "github.com/iotaledger/hive.go/node" + "sync" ) // PluginName is the name of the web API DRNG endpoint plugin. const PluginName = "WebAPI DRNG Endpoint" var ( - // Plugin is the plugin instance of the web API DRNG endpoint plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure) + // plugin is the plugin instance of the web API DRNG endpoint plugin. + plugin *node.Plugin + once sync.Once ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure) + }) + return plugin +} + func configure(_ *node.Plugin) { - webapi.Server.POST("drng/collectiveBeacon", collectivebeacon.Handler) - webapi.Server.GET("drng/info/committee", committee.Handler) - webapi.Server.GET("drng/info/randomness", randomness.Handler) + webapi.Server().POST("drng/collectiveBeacon", collectivebeacon.Handler) + webapi.Server().GET("drng/info/committee", committee.Handler) + webapi.Server().GET("drng/info/randomness", randomness.Handler) } diff --git a/plugins/webapi/healthz/plugin.go b/plugins/webapi/healthz/plugin.go index 29af56fdd889537a576ec07e3b77f9d011b6bfd6..d0c859d4771ed3762821ba5ca42242894b2b85ff 100644 --- a/plugins/webapi/healthz/plugin.go +++ b/plugins/webapi/healthz/plugin.go @@ -2,6 +2,7 @@ package healthz import ( "net/http" + goSync "sync" "github.com/iotaledger/goshimmer/plugins/gossip" "github.com/iotaledger/goshimmer/plugins/sync" @@ -13,11 +14,21 @@ import ( // PluginName is the name of the web API healthz endpoint plugin. const PluginName = "WebAPI healthz Endpoint" -// Plugin is the plugin instance of the web API info endpoint plugin. -var Plugin = node.NewPlugin(PluginName, node.Enabled, configure) +var ( + // plugin is the plugin instance of the web API info endpoint plugin. + plugin *node.Plugin + once goSync.Once +) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure) + }) + return plugin +} func configure(_ *node.Plugin) { - webapi.Server.GET("healthz", getHealthz) + webapi.Server().GET("healthz", getHealthz) } func getHealthz(c echo.Context) error { diff --git a/plugins/webapi/info/plugin.go b/plugins/webapi/info/plugin.go index 6dc44a26c5fac5a606d5770a462b9ff75a874035..255343b62f108094e0ad774fc72d6c9c33dbcfea 100644 --- a/plugins/webapi/info/plugin.go +++ b/plugins/webapi/info/plugin.go @@ -3,6 +3,7 @@ package info import ( "net/http" "sort" + goSync "sync" "github.com/iotaledger/goshimmer/plugins/autopeering/local" "github.com/iotaledger/goshimmer/plugins/banner" @@ -15,11 +16,22 @@ import ( // PluginName is the name of the web API info endpoint plugin. const PluginName = "WebAPI info Endpoint" -// Plugin is the plugin instance of the web API info endpoint plugin. -var Plugin = node.NewPlugin(PluginName, node.Enabled, configure) +var ( + // plugin is the plugin instance of the web API info endpoint plugin. + plugin *node.Plugin + once goSync.Once +) + +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure) + }) + return plugin +} func configure(_ *node.Plugin) { - webapi.Server.GET("info", getInfo) + webapi.Server().GET("info", getInfo) } // getInfo returns the info of the node diff --git a/plugins/webapi/message/plugin.go b/plugins/webapi/message/plugin.go index 7e29b872a354005704691d82c221df31bc6988a9..015a69e32b231f589f3200b798c8f6501f8b1d1b 100644 --- a/plugins/webapi/message/plugin.go +++ b/plugins/webapi/message/plugin.go @@ -2,6 +2,7 @@ package message import ( "net/http" + "sync" "github.com/iotaledger/goshimmer/packages/binary/messagelayer/message" "github.com/iotaledger/goshimmer/plugins/messagelayer" @@ -15,15 +16,24 @@ import ( const PluginName = "WebAPI message Endpoint" var ( - // Plugin is the plugin instance of the web API message endpoint plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure) + // plugin is the plugin instance of the web API message endpoint plugin. + plugin *node.Plugin + once sync.Once log *logger.Logger ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure) + }) + return plugin +} + func configure(plugin *node.Plugin) { log = logger.NewLogger(PluginName) - webapi.Server.POST("message/findById", findMessageByID) - webapi.Server.POST("message/sendPayload", sendPayload) + webapi.Server().POST("message/findById", findMessageByID) + webapi.Server().POST("message/sendPayload", sendPayload) } // findMessageByID returns the array of messages for the @@ -48,8 +58,8 @@ func findMessageByID(c echo.Context) error { return c.JSON(http.StatusBadRequest, Response{Error: err.Error()}) } - msgObject := messagelayer.Tangle.Message(msgID) - msgMetadataObject := messagelayer.Tangle.MessageMetadata(msgID) + msgObject := messagelayer.Tangle().Message(msgID) + msgMetadataObject := messagelayer.Tangle().MessageMetadata(msgID) if !msgObject.Exists() || !msgMetadataObject.Exists() { result = append(result, Message{}) diff --git a/plugins/webapi/plugin.go b/plugins/webapi/plugin.go index f97f3db9b9978caa4726aaeea60ad034921cab85..73482f88a02bc766688f62c69e56a6e1c74d5030 100644 --- a/plugins/webapi/plugin.go +++ b/plugins/webapi/plugin.go @@ -4,6 +4,7 @@ import ( "context" "errors" "net/http" + "sync" "time" "github.com/iotaledger/goshimmer/packages/shutdown" @@ -18,25 +19,44 @@ import ( const PluginName = "WebAPI" var ( - // Plugin is the plugin instance of the web API plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) - // Server is the web API server. - Server = echo.New() + // plugin is the plugin instance of the web API plugin. + plugin *node.Plugin + pluginOnce sync.Once + // server is the web API server. + server *echo.Echo + serverOnce sync.Once log *logger.Logger ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + pluginOnce.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure, run) + }) + return plugin +} + +// Server gets the server instance. +func Server() *echo.Echo { + serverOnce.Do(func() { + server = echo.New() + }) + return server +} + func configure(*node.Plugin) { + server = Server() log = logger.NewLogger(PluginName) // configure the server - Server.HideBanner = true - Server.HidePort = true - Server.GET("/", IndexRequest) + server.HideBanner = true + server.HidePort = true + server.GET("/", IndexRequest) } func run(*node.Plugin) { log.Infof("Starting %s ...", PluginName) - if err := daemon.BackgroundWorker("WebAPI Server", worker, shutdown.PriorityWebAPI); err != nil { + if err := daemon.BackgroundWorker("WebAPI server", worker, shutdown.PriorityWebAPI); err != nil { log.Panicf("Failed to start as daemon: %s", err) } } @@ -45,10 +65,10 @@ func worker(shutdownSignal <-chan struct{}) { defer log.Infof("Stopping %s ... done", PluginName) stopped := make(chan struct{}) - bindAddr := config.Node.GetString(CfgBindAddress) + bindAddr := config.Node().GetString(CfgBindAddress) go func() { log.Infof("%s started, bind-address=%s", PluginName, bindAddr) - if err := Server.Start(bindAddr); err != nil { + if err := server.Start(bindAddr); err != nil { if !errors.Is(err, http.ErrServerClosed) { log.Errorf("Error serving: %s", err) } @@ -65,7 +85,7 @@ func worker(shutdownSignal <-chan struct{}) { log.Infof("Stopping %s ...", PluginName) ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() - if err := Server.Shutdown(ctx); err != nil { + if err := server.Shutdown(ctx); err != nil { log.Errorf("Error stopping: %s", err) } } diff --git a/plugins/webapi/spammer/plugin.go b/plugins/webapi/spammer/plugin.go index f4de8c78a287796a5b01eaad065b119af72e6dc9..248338f641745de3ead979261703e38d14dff8d0 100644 --- a/plugins/webapi/spammer/plugin.go +++ b/plugins/webapi/spammer/plugin.go @@ -8,6 +8,7 @@ import ( "github.com/iotaledger/hive.go/daemon" "github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/node" + "sync" ) var messageSpammer *spammer.Spammer @@ -15,15 +16,25 @@ var messageSpammer *spammer.Spammer // PluginName is the name of the spammer plugin. const PluginName = "Spammer" -// Plugin is the plugin instance of the spammer plugin. -var Plugin = node.NewPlugin(PluginName, node.Disabled, configure, run) +var ( + // plugin is the plugin instance of the spammer plugin. + plugin *node.Plugin + once sync.Once + log *logger.Logger +) -var log *logger.Logger +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Disabled, configure, run) + }) + return plugin +} func configure(plugin *node.Plugin) { log = logger.NewLogger(PluginName) messageSpammer = spammer.New(issuer.IssuePayload) - webapi.Server.GET("spammer", handleRequest) + webapi.Server().GET("spammer", handleRequest) } func run(*node.Plugin) { diff --git a/plugins/webapi/value/attachments/handler.go b/plugins/webapi/value/attachments/handler.go index 9996feec57343fe68a61b70f4f3ff22df2315830..a54d517efdb2c7ab43f82d92ff756ad15917bac9 100644 --- a/plugins/webapi/value/attachments/handler.go +++ b/plugins/webapi/value/attachments/handler.go @@ -21,7 +21,7 @@ func Handler(c echo.Context) error { var valueObjs []ValueObject // get txn by txn id - txnObj := valuetransfers.Tangle.Transaction(txnID) + txnObj := valuetransfers.Tangle().Transaction(txnID) defer txnObj.Release() if !txnObj.Exists() { return c.JSON(http.StatusNotFound, Response{Error: "Transaction not found"}) @@ -29,7 +29,7 @@ func Handler(c echo.Context) error { txn := utils.ParseTransaction(txnObj.Unwrap()) // get attachements by txn id - for _, attachmentObj := range valuetransfers.Tangle.Attachments(txnID) { + for _, attachmentObj := range valuetransfers.Tangle().Attachments(txnID) { defer attachmentObj.Release() if !attachmentObj.Exists() { continue @@ -37,7 +37,7 @@ func Handler(c echo.Context) error { attachment := attachmentObj.Unwrap() // get payload by payload id - payloadObj := valuetransfers.Tangle.Payload(attachment.PayloadID()) + payloadObj := valuetransfers.Tangle().Payload(attachment.PayloadID()) defer payloadObj.Release() if !payloadObj.Exists() { continue diff --git a/plugins/webapi/value/gettransactionbyid/handler.go b/plugins/webapi/value/gettransactionbyid/handler.go index b4bee704b621f56a4e5afdb2b34cc93dc40cc4dd..0f8ebaaab66fbe85d26e502cfb9268fcc47ca1d6 100644 --- a/plugins/webapi/value/gettransactionbyid/handler.go +++ b/plugins/webapi/value/gettransactionbyid/handler.go @@ -17,12 +17,12 @@ func Handler(c echo.Context) error { } // get txn by txn id - cachedTxnMetaObj := valuetransfers.Tangle.TransactionMetadata(txnID) + cachedTxnMetaObj := valuetransfers.Tangle().TransactionMetadata(txnID) defer cachedTxnMetaObj.Release() if !cachedTxnMetaObj.Exists() { return c.JSON(http.StatusNotFound, Response{Error: "Transaction not found"}) } - cachedTxnObj := valuetransfers.Tangle.Transaction(txnID) + cachedTxnObj := valuetransfers.Tangle().Transaction(txnID) defer cachedTxnObj.Release() if !cachedTxnObj.Exists() { return c.JSON(http.StatusNotFound, Response{Error: "Transaction not found"}) diff --git a/plugins/webapi/value/plugin.go b/plugins/webapi/value/plugin.go index 72facce9182a959913a67031ecdf92ea0d3b40ca..4fcdf40e9b06d51701fad95ca9607a9f96992c5c 100644 --- a/plugins/webapi/value/plugin.go +++ b/plugins/webapi/value/plugin.go @@ -8,20 +8,30 @@ import ( "github.com/iotaledger/goshimmer/plugins/webapi/value/testsendtxn" "github.com/iotaledger/goshimmer/plugins/webapi/value/unspentoutputs" "github.com/iotaledger/hive.go/node" + "sync" ) // PluginName is the name of the web API DRNG endpoint plugin. const PluginName = "WebAPI Value Endpoint" var ( - // Plugin is the plugin instance of the web API DRNG endpoint plugin. - Plugin = node.NewPlugin(PluginName, node.Enabled, configure) + // plugin is the plugin instance of the web API DRNG endpoint plugin. + plugin *node.Plugin + once sync.Once ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Enabled, configure) + }) + return plugin +} + func configure(_ *node.Plugin) { - webapi.Server.GET("value/attachments", attachments.Handler) - webapi.Server.POST("value/unspentOutputs", unspentoutputs.Handler) - webapi.Server.POST("value/sendTransaction", sendtransaction.Handler) - webapi.Server.POST("value/testSendTxn", testsendtxn.Handler) - webapi.Server.GET("value/transactionByID", gettransactionbyid.Handler) + webapi.Server().GET("value/attachments", attachments.Handler) + webapi.Server().POST("value/unspentOutputs", unspentoutputs.Handler) + webapi.Server().POST("value/sendTransaction", sendtransaction.Handler) + webapi.Server().POST("value/testSendTxn", testsendtxn.Handler) + webapi.Server().GET("value/transactionByID", gettransactionbyid.Handler) } diff --git a/plugins/webapi/value/unspentoutputs/handler.go b/plugins/webapi/value/unspentoutputs/handler.go index 05be4eb55ba1d901e0f3544cdec998fcef66c9a8..22dc4f0e37709055d0a0f6b77bd3d5c0480a18d6 100644 --- a/plugins/webapi/value/unspentoutputs/handler.go +++ b/plugins/webapi/value/unspentoutputs/handler.go @@ -28,11 +28,11 @@ func Handler(c echo.Context) error { outputids := make([]OutputID, 0) // get outputids by address - for id, cachedOutput := range valuetransfers.Tangle.OutputsOnAddress(address) { + for id, cachedOutput := range valuetransfers.Tangle().OutputsOnAddress(address) { // TODO: don't do this in a for defer cachedOutput.Release() output := cachedOutput.Unwrap() - cachedTxMeta := valuetransfers.Tangle.TransactionMetadata(output.TransactionID()) + cachedTxMeta := valuetransfers.Tangle().TransactionMetadata(output.TransactionID()) // TODO: don't do this in a for defer cachedTxMeta.Release() diff --git a/plugins/webauth/webauth.go b/plugins/webauth/webauth.go index 946f0c8b29bca8fab1ea379d8ab95bcef8fa21a2..a337d7ba34cc5a44ca427c4484441fe7ba60ac8c 100644 --- a/plugins/webauth/webauth.go +++ b/plugins/webauth/webauth.go @@ -3,6 +3,7 @@ package webauth import ( "net/http" "strings" + "sync" "time" "github.com/dgrijalva/jwt-go" @@ -18,20 +19,29 @@ import ( const PluginName = "WebAPI Auth" var ( - // Plugin is the plugin instance of the web API auth plugin. - Plugin = node.NewPlugin(PluginName, node.Disabled, configure) + // plugin is the plugin instance of the web API auth plugin. + plugin *node.Plugin + once sync.Once log *logger.Logger privateKey string ) +// Plugin gets the plugin instance. +func Plugin() *node.Plugin { + once.Do(func() { + plugin = node.NewPlugin(PluginName, node.Disabled, configure) + }) + return plugin +} + func configure(plugin *node.Plugin) { log = logger.NewLogger(PluginName) - privateKey = config.Node.GetString(CfgWebAPIAuthPrivateKey) + privateKey = config.Node().GetString(CfgWebAPIAuthPrivateKey) if len(privateKey) == 0 { panic("") } - webapi.Server.Use(middleware.JWTWithConfig(middleware.JWTConfig{ + webapi.Server().Use(middleware.JWTWithConfig(middleware.JWTConfig{ SigningKey: []byte(privateKey), Skipper: func(c echo.Context) bool { if strings.HasPrefix(c.Path(), "/ui") || c.Path() == "/login" { @@ -41,7 +51,7 @@ func configure(plugin *node.Plugin) { }, })) - webapi.Server.POST("/login", Handler) + webapi.Server().POST("/login", Handler) log.Info("WebAPI is now secured through JWT authentication") } @@ -66,8 +76,8 @@ func Handler(c echo.Context) error { return echo.ErrBadRequest } - if login.Username != config.Node.GetString(CfgWebAPIAuthUsername) || - login.Password != config.Node.GetString(CfgWebAPIAuthPassword) { + if login.Username != config.Node().GetString(CfgWebAPIAuthUsername) || + login.Password != config.Node().GetString(CfgWebAPIAuthPassword) { return echo.ErrUnauthorized } diff --git a/tools/relay-checker/config.go b/tools/relay-checker/config.go index eceecbcb296f11a54a22ae0734f21170f98d38b7..5e8d2ed774ba1e3e2a0cd09795c99ccdf7e77197 100644 --- a/tools/relay-checker/config.go +++ b/tools/relay-checker/config.go @@ -11,24 +11,24 @@ var ( ) func initConfig() { - if config.Node.GetString(CfgTargetNode) == "" { + if config.Node().GetString(CfgTargetNode) == "" { panic("Set the target node address\n") } - target = config.Node.GetString(CfgTargetNode) + target = config.Node().GetString(CfgTargetNode) - if len(config.Node.GetStringSlice(CfgTestNodes)) == 0 { + if len(config.Node().GetStringSlice(CfgTestNodes)) == 0 { panic("Set node addresses\n") } - nodes = append(nodes, config.Node.GetStringSlice(CfgTestNodes)...) + nodes = append(nodes, config.Node().GetStringSlice(CfgTestNodes)...) // optional settings - if config.Node.GetString(CfgData) != "" { - msgData = config.Node.GetString(CfgData) + if config.Node().GetString(CfgData) != "" { + msgData = config.Node().GetString(CfgData) } - if config.Node.GetInt(CfgCooldownTime) > 0 { - cooldownTime = config.Node.GetInt(CfgCooldownTime) + if config.Node().GetInt(CfgCooldownTime) > 0 { + cooldownTime = config.Node().GetInt(CfgCooldownTime) } - if config.Node.GetInt(CfgRepeat) > 0 { - repeat = config.Node.GetInt(CfgRepeat) + if config.Node().GetInt(CfgRepeat) > 0 { + repeat = config.Node().GetInt(CfgRepeat) } }