package nodeconfig import ( "fmt" "os" "strconv" "time" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config" "github.com/nspcc-dev/neofs-node/pkg/network" utilConfig "github.com/nspcc-dev/neofs-node/pkg/util/config" ) // PersistentSessionsConfig is a wrapper over "persistent_sessions" config section // which provides access to persistent session tokens storage configuration of node. type PersistentSessionsConfig struct { cfg *config.Config } // PersistentStateConfig is a wrapper over "persistent_state" config section // which provides access to persistent state storage configuration of node. type PersistentStateConfig struct { cfg *config.Config } // NotificationConfig is a wrapper over "notification" config section // which provides access to object notification configuration of node. type NotificationConfig struct { cfg *config.Config } const ( subsection = "node" persistentSessionsSubsection = "persistent_sessions" persistentStateSubsection = "persistent_state" notificationSubsection = "notification" attributePrefix = "attribute" // PersistentStatePathDefault is a default path for persistent state file. PersistentStatePathDefault = ".neofs-storage-state" // NotificationTimeoutDefault is a default timeout for object notification operation. NotificationTimeoutDefault = 5 * time.Second ) // Key returns the value of "key" config parameter // from "node" section. // // If the value is not set, fallbacks to Wallet section. // // Panics if the value is incorrect filename of binary encoded private key. func Key(c *config.Config) *keys.PrivateKey { v := config.StringSafe(c.Sub(subsection), "key") if v == "" { return Wallet(c) } var ( key *keys.PrivateKey err error data []byte ) if data, err = os.ReadFile(v); err == nil { key, err = keys.NewPrivateKeyFromBytes(data) } if err != nil { panic(fmt.Errorf("invalid private key in node section: %w", err)) } return key } // Wallet returns the value of a node private key from "node" section. // // Panics if section contains invalid values. func Wallet(c *config.Config) *keys.PrivateKey { v := c.Sub(subsection).Sub("wallet") acc, err := utilConfig.LoadAccount( config.String(v, "path"), config.String(v, "address"), config.String(v, "password")) if err != nil { panic(fmt.Errorf("invalid wallet config: %w", err)) } return acc.PrivateKey() } type stringAddressGroup []string func (x stringAddressGroup) IterateAddresses(f func(string) bool) { for i := range x { if f(x[i]) { break } } } func (x stringAddressGroup) NumberOfAddresses() int { return len(x) } // BootstrapAddresses returns the value of "addresses" config parameter // from "node" section as network.AddressGroup. // // Panics if the value is not a string list of valid NeoFS network addresses. func BootstrapAddresses(c *config.Config) (addr network.AddressGroup) { v := config.StringSlice(c.Sub(subsection), "addresses") err := addr.FromIterator(stringAddressGroup(v)) if err != nil { panic(fmt.Errorf("could not parse bootstrap addresses: %w", err)) } return addr } // Attributes returns list of config parameters // from "node" section that are set in "attribute_i" format, // where i in range [0,100). func Attributes(c *config.Config) (attrs []string) { const maxAttributes = 100 for i := 0; i < maxAttributes; i++ { attr := config.StringSafe(c.Sub(subsection), attributePrefix+"_"+strconv.Itoa(i)) if attr == "" { return } attrs = append(attrs, attr) } return } // Relay returns the value of "relay" config parameter // from "node" section. // // Returns false if the value is not set. func Relay(c *config.Config) bool { return config.BoolSafe(c.Sub(subsection), "relay") } // PersistentSessions returns structure that provides access to "persistent_sessions" // subsection of "node" section. func PersistentSessions(c *config.Config) PersistentSessionsConfig { return PersistentSessionsConfig{ c.Sub(subsection).Sub(persistentSessionsSubsection), } } // Path returns the value of "path" config parameter. func (p PersistentSessionsConfig) Path() string { return config.String(p.cfg, "path") } // PersistentState returns structure that provides access to "persistent_state" // subsection of "node" section. func PersistentState(c *config.Config) PersistentStateConfig { return PersistentStateConfig{ c.Sub(subsection).Sub(persistentStateSubsection), } } // Path returns the value of "path" config parameter. // // Returns PersistentStatePathDefault if the value is not a non-empty string. func (p PersistentStateConfig) Path() string { v := config.String(p.cfg, "path") if v != "" { return v } return PersistentStatePathDefault } // SubnetConfig represents node configuration related to subnets. type SubnetConfig config.Config // Init initializes SubnetConfig from "subnet" sub-section of "node" section // of the root config. func (x *SubnetConfig) Init(root config.Config) { *x = SubnetConfig(*root.Sub(subsection).Sub("subnet")) } // ExitZero returns the value of "exit_zero" config parameter as bool. // Returns false if the value can not be cast. func (x SubnetConfig) ExitZero() bool { return config.BoolSafe((*config.Config)(&x), "exit_zero") } // IterateSubnets casts the value of "entries" config parameter to string slice, // iterates over all of its elements and passes them to f. // // Does nothing if the value can not be cast to string slice. func (x SubnetConfig) IterateSubnets(f func(string)) { ids := config.StringSliceSafe((*config.Config)(&x), "entries") for i := range ids { f(ids[i]) } } // Notification returns structure that provides access to "notification" // subsection of "node" section. func Notification(c *config.Config) NotificationConfig { return NotificationConfig{ c.Sub(subsection).Sub(notificationSubsection), } } // Enabled returns the value of "enabled" config parameter from "notification" // subsection of "node" section. // // Returns false if the value is not presented. func (n NotificationConfig) Enabled() bool { return config.BoolSafe(n.cfg, "enabled") } // DefaultTopic returns the value of "default_topic" config parameter from // "notification" subsection of "node" section. // // Returns empty string if the value is not presented. func (n NotificationConfig) DefaultTopic() string { return config.StringSafe(n.cfg, "default_topic") } // Endpoint returns the value of "endpoint" config parameter from "notification" // subsection of "node" section. // // Returns empty string if the value is not presented. func (n NotificationConfig) Endpoint() string { return config.StringSafe(n.cfg, "endpoint") } // Timeout returns the value of "timeout" config parameter from "notification" // subsection of "node" section. // // Returns NotificationTimeoutDefault if the value is not positive. func (n NotificationConfig) Timeout() time.Duration { v := config.DurationSafe(n.cfg, "timeout") if v > 0 { return v } return NotificationTimeoutDefault } // CertPath returns the value of "certificate_path" config parameter from "notification" // subsection of "node" section. // // Returns empty string if the value is not presented. func (n NotificationConfig) CertPath() string { return config.StringSafe(n.cfg, "certificate") } // KeyPath returns the value of "key_path" config parameter from // "notification" subsection of "node" section. // // Returns empty string if the value is not presented. func (n NotificationConfig) KeyPath() string { return config.StringSafe(n.cfg, "key") } // CAPath returns the value of "ca_path" config parameter from // "notification" subsection of "node" section. // // Returns empty string if the value is not presented. func (n NotificationConfig) CAPath() string { return config.StringSafe(n.cfg, "ca") }