From ed6caf9e58c8c9060e56766035c5a84f78ad4851 Mon Sep 17 00:00:00 2001 From: huy Date: Fri, 10 Jan 2025 10:23:08 -0800 Subject: [PATCH] Get config instance --- adapter/{command => config}/claim-rewards.go | 2 +- adapter/{command => config}/commands.go | 2 +- adapter/{command => config}/exit.go | 2 +- .../generate-deposit-data.go | 2 +- adapter/{command => config}/generate-keys.go | 2 +- .../{command => config}/get-node-status.go | 2 +- adapter/config/he-config.go | 336 ++++++++++++++++++ adapter/config/ids/ids.go | 16 + adapter/{command => config}/initialize.go | 2 +- .../upload-deposit-data.go | 2 +- adapter/hd-module/get-config-instance.go | 45 +++ adapter/utils/auth.go | 99 ++++++ adapter/utils/flags.go | 6 + adapter/utils/gas.go | 2 +- adapter/utils/prompt.go | 2 +- go.mod | 2 +- go.sum | 2 + shared/config/ids/config.go | 106 ++++++ 18 files changed, 621 insertions(+), 11 deletions(-) rename adapter/{command => config}/claim-rewards.go (99%) rename adapter/{command => config}/commands.go (99%) rename adapter/{command => config}/exit.go (99%) rename adapter/{command => config}/generate-deposit-data.go (99%) rename adapter/{command => config}/generate-keys.go (99%) rename adapter/{command => config}/get-node-status.go (99%) create mode 100644 adapter/config/he-config.go create mode 100644 adapter/config/ids/ids.go rename adapter/{command => config}/initialize.go (98%) rename adapter/{command => config}/upload-deposit-data.go (97%) create mode 100644 adapter/hd-module/get-config-instance.go create mode 100644 adapter/utils/auth.go create mode 100644 shared/config/ids/config.go diff --git a/adapter/command/claim-rewards.go b/adapter/config/claim-rewards.go similarity index 99% rename from adapter/command/claim-rewards.go rename to adapter/config/claim-rewards.go index e76a9f9..a28367c 100644 --- a/adapter/command/claim-rewards.go +++ b/adapter/config/claim-rewards.go @@ -1,4 +1,4 @@ -package command +package config import ( "fmt" diff --git a/adapter/command/commands.go b/adapter/config/commands.go similarity index 99% rename from adapter/command/commands.go rename to adapter/config/commands.go index acff32b..62c14f9 100644 --- a/adapter/command/commands.go +++ b/adapter/config/commands.go @@ -1,4 +1,4 @@ -package command +package config import ( "fmt" diff --git a/adapter/command/exit.go b/adapter/config/exit.go similarity index 99% rename from adapter/command/exit.go rename to adapter/config/exit.go index a067b3c..2006897 100644 --- a/adapter/command/exit.go +++ b/adapter/config/exit.go @@ -1,4 +1,4 @@ -package command +package config import ( "fmt" diff --git a/adapter/command/generate-deposit-data.go b/adapter/config/generate-deposit-data.go similarity index 99% rename from adapter/command/generate-deposit-data.go rename to adapter/config/generate-deposit-data.go index 045b410..78fdded 100644 --- a/adapter/command/generate-deposit-data.go +++ b/adapter/config/generate-deposit-data.go @@ -1,4 +1,4 @@ -package command +package config import ( "encoding/json" diff --git a/adapter/command/generate-keys.go b/adapter/config/generate-keys.go similarity index 99% rename from adapter/command/generate-keys.go rename to adapter/config/generate-keys.go index 9aa1265..3aaa956 100644 --- a/adapter/command/generate-keys.go +++ b/adapter/config/generate-keys.go @@ -1,4 +1,4 @@ -package command +package config import ( "fmt" diff --git a/adapter/command/get-node-status.go b/adapter/config/get-node-status.go similarity index 99% rename from adapter/command/get-node-status.go rename to adapter/config/get-node-status.go index d9ffea7..aaf8bd6 100644 --- a/adapter/command/get-node-status.go +++ b/adapter/config/get-node-status.go @@ -1,4 +1,4 @@ -package command +package config import ( "fmt" diff --git a/adapter/config/he-config.go b/adapter/config/he-config.go new file mode 100644 index 0000000..98037fe --- /dev/null +++ b/adapter/config/he-config.go @@ -0,0 +1,336 @@ +package config + +import ( + "fmt" + "os" + + "github.com/nodeset-org/hyperdrive-stakewise/adapter/config/ids" + nativecfg "github.com/nodeset-org/hyperdrive-stakewise/shared/config/ids" + hdconfig "github.com/nodeset-org/hyperdrive/modules/config" + "github.com/urfave/cli/v2" + "gopkg.in/yaml.v3" +) + +const ( + FloatThreshold float64 = 75.0 +) + +type PortMode string + +const ( + PortMode_Closed PortMode = "closed" + PortMode_Localhost PortMode = "localhost" + PortMode_External PortMode = "external" +) + +type ExampleConfig struct { + // ExampleBool hdconfig.BoolParameterMetadata + + // ExampleInt hdconfig.IntParameterMetadata + + // ExampleUint hdconfig.UintParameterMetadata + + // ExampleFloat hdconfig.FloatParameterMetadata + + // ExampleString hdconfig.StringParameterMetadata + + // ExampleChoice hdconfig.ChoiceParameterMetadata[nativecfg.ExampleOption] + + SubConfig *SubConfig + + ServerConfig *ServerConfig +} + +func NewExampleConfig() *ExampleConfig { + cfg := &ExampleConfig{} + + // // ExampleBool + // cfg.ExampleBool.ID = hdconfig.Identifier(ids.ExampleBoolID) + // cfg.ExampleBool.Name = "Example Boolean" + // cfg.ExampleBool.Description.Default = "This is an example of a boolean parameter. It doesn't directly affect the service, but it does control the behavior of some other config parameters." + // cfg.ExampleBool.AffectedContainers = []string{shared.ServiceContainerName} + // cfg.ExampleBool.Value = cfg.ExampleBool.Default + + // // ExampleInt + // cfg.ExampleInt.ID = hdconfig.Identifier(ids.ExampleIntID) + // cfg.ExampleInt.Name = "Example Integer" + // cfg.ExampleInt.Description.Default = "This is an example of an integer parameter." + // cfg.ExampleInt.AffectedContainers = []string{shared.ServiceContainerName} + // cfg.ExampleInt.Value = cfg.ExampleInt.Default + + // // ExampleUint + // cfg.ExampleUint.ID = hdconfig.Identifier(ids.ExampleUintID) + // cfg.ExampleUint.Name = "Example Unsigned Integer" + // cfg.ExampleUint.Description.Default = "This is an example of an unsigned integer parameter." + // cfg.ExampleUint.AffectedContainers = []string{shared.ServiceContainerName} + // cfg.ExampleUint.Value = cfg.ExampleUint.Default + + // // ExampleFloat + // cfg.ExampleFloat.ID = hdconfig.Identifier(ids.ExampleFloatID) + // cfg.ExampleFloat.Name = "Example Float" + // cfg.ExampleFloat.Description.Default = "This is an example of a float parameter with a minimum and maximum set." + // cfg.ExampleFloat.Default = 50 + // cfg.ExampleFloat.MinValue = 0.0 + // cfg.ExampleFloat.MaxValue = 100.0 + // cfg.ExampleFloat.Value = cfg.ExampleFloat.Default + // cfg.ExampleFloat.AffectedContainers = []string{shared.ServiceContainerName} + + // // ExampleString + // cfg.ExampleString.ID = hdconfig.Identifier(ids.ExampleStringID) + // cfg.ExampleString.Name = "Example String" + // cfg.ExampleString.Description.Default = "This is an example of a string parameter. It has a max length and regex pattern set." + // cfg.ExampleString.MaxLength = 10 + // cfg.ExampleString.Regex = "^[a-zA-Z]*$" + // cfg.ExampleString.Value = cfg.ExampleString.Default + // cfg.ExampleString.AffectedContainers = []string{shared.ServiceContainerName} + + // // Options for ExampleChoice + // options := make([]hdconfig.ParameterMetadataOption[nativecfg.ExampleOption], 3) + // options[0].Name = "One" + // options[0].Description.Default = "This is the first option." + // options[0].Value = nativecfg.ExampleOption_One + + // thresholdString := strconv.FormatFloat(FloatThreshold, 'f', -1, 64) + // options[1].Name = "Two" + // options[1].Description.Default = "This is the second option. It is hidden when ExampleFloat is less than " + thresholdString + "." + // options[1].Description.Template = fmt.Sprintf("{{if lt .GetValue %s %s}}This option is hidden because the float is less than %s.{{else}}This option is visible because the float is greater than or equal to %s.{{end}}", ids.ExampleFloatID, thresholdString, thresholdString, thresholdString) + // options[1].Value = nativecfg.ExampleOption_Two + // options[1].Disabled.Default = true + // options[1].Disabled.Template = "{{if eq .GetValue " + ids.ExampleBoolID + " true}}false{{else}}{{.UseDefault}}{{end}}" + + // options[2].Name = "Three" + // options[2].Description.Default = "This is the third option." + // options[2].Value = nativecfg.ExampleOption_Three + + // // ExampleChoice + // cfg.ExampleChoice.ID = hdconfig.Identifier(ids.ExampleChoiceID) + // cfg.ExampleChoice.Name = "Example Choice" + // cfg.ExampleChoice.Description.Default = "This is an example of a choice parameter between multiple options." + // cfg.ExampleChoice.Options = options + // cfg.ExampleChoice.Default = options[0].Value + // cfg.ExampleChoice.Value = cfg.ExampleChoice.Default + // cfg.ExampleChoice.AffectedContainers = []string{} + + // Subconfigs + cfg.SubConfig = NewSubConfig() + cfg.ServerConfig = NewServerConfig() + + return cfg +} + +type SubConfig struct { + hdconfig.SectionMetadataHeader + + SubExampleBool hdconfig.BoolParameterMetadata + + SubExampleChoice hdconfig.ChoiceParameterMetadata[nativecfg.ExampleOption] +} + +func NewSubConfig() *SubConfig { + cfg := &SubConfig{} + // cfg.ID = hdconfig.Identifier(ids.SubConfigID) + // cfg.Name = "Sub Config" + // cfg.Description.Default = "This is a sub-section of the main configuration." + // cfg.Hidden.Default = true + // cfg.Hidden.Template = "{{if eq .GetValue " + ids.ExampleBoolID + " true}}false{{else}}true{{end}}" + + // // SubExampleBool + // cfg.SubExampleBool.ID = hdconfig.Identifier(ids.SubExampleBoolID) + // cfg.SubExampleBool.Name = "Sub Example Boolean" + // cfg.SubExampleBool.Description.Default = "This is an example of a boolean parameter in a sub-section." + // cfg.SubExampleBool.Value = cfg.SubExampleBool.Default + + // // Options for SubExampleChoice + // options := make([]hdconfig.ParameterMetadataOption[nativecfg.ExampleOption], 2) + // options[0].Name = "One" + // options[0].Description.Default = "This is the first option." + // options[0].Value = nativecfg.ExampleOption_One + + // options[1].Name = "Two" + // options[1].Description.Default = "This is the second option." + // options[1].Value = nativecfg.ExampleOption_Two + + // // SubExampleChoice + // cfg.SubExampleChoice.ID = hdconfig.Identifier(ids.SubExampleChoiceID) + // cfg.SubExampleChoice.Name = "Sub Example Choice" + // cfg.SubExampleChoice.Description.Default = "This is an example of a choice parameter between multiple options in a sub-section." + // cfg.SubExampleChoice.Options = options + // cfg.SubExampleChoice.Default = options[1].Value + // cfg.SubExampleChoice.Value = cfg.SubExampleChoice.Default + + return cfg +} + +type ServerConfig struct { + hdconfig.SectionMetadataHeader + + Port hdconfig.UintParameterMetadata + + PortMode hdconfig.ChoiceParameterMetadata[PortMode] +} + +func NewServerConfig() *ServerConfig { + cfg := &ServerConfig{} + // cfg.ID = hdconfig.Identifier(ids.ServerConfigID) + // cfg.Name = "Service Config" + // cfg.Description.Default = "This is the configuration for the module's service. This isn't used by the service directly, but it is used by Hyperdrive itself in the service's Docker Compose file template to configure the service during its starting process." + + // // Port + // cfg.Port.ID = hdconfig.Identifier(ids.PortID) + // cfg.Port.Name = "API Port" + // cfg.Port.Description.Default = "This is the API port the server should run on." + // cfg.Port.Default = uint64(shared.DefaultServerApiPort) + // cfg.Port.MinValue = 0 + // cfg.Port.MaxValue = 65535 + // cfg.Port.Value = cfg.Port.Default + // cfg.Port.AffectedContainers = []string{shared.ServiceContainerName} + + // // Options for PortMode + // options := make([]hdconfig.ParameterMetadataOption[PortMode], 3) + // options[0].Name = "Closed" + // options[0].Description.Default = "The API is only accessible to internal Docker container traffic." + // options[0].Value = PortMode_Closed + + // options[1].Name = "Localhost Only" + // options[1].Description.Default = "The API is accessible from internal Docker containers and your own local machine, but no other external machines." + // options[1].Value = PortMode_Localhost + + // options[2].Name = "All External Traffic" + // options[2].Description.Default = "The port is accessible to everything, including external machines.\n\n[orange]Use with caution!" + // options[2].Value = PortMode_External + + // // PortMode + // cfg.PortMode.ID = hdconfig.Identifier(ids.PortModeID) + // cfg.PortMode.Name = "Expose API Port" + // cfg.PortMode.Description.Default = "Determine how the server's HTTP API restricts its access from various sources." + // cfg.PortMode.Options = options + // cfg.PortMode.Default = options[0].Value + // cfg.PortMode.Value = cfg.PortMode.Default + // cfg.PortMode.AffectedContainers = []string{shared.ServiceContainerName} + + return cfg +} + +func ConvertToMetadata(native *nativecfg.NativeExampleConfig) *ExampleConfig { + cfg := NewExampleConfig() + + // cfg.ExampleBool.Value = native.ExampleBool + // cfg.ExampleInt.Value = native.ExampleInt + // cfg.ExampleUint.Value = native.ExampleUint + // cfg.ExampleFloat.Value = native.ExampleFloat + // cfg.ExampleString.Value = native.ExampleString + // cfg.ExampleChoice.Value = native.ExampleChoice + + cfg.SubConfig.SubExampleBool.Value = native.SubConfig.SubExampleBool + cfg.SubConfig.SubExampleChoice.Value = native.SubConfig.SubExampleChoice + + return cfg +} + +func (cfg *ExampleConfig) ConvertToNative() *nativecfg.NativeExampleConfig { + // native := &nativecfg.NativeExampleConfig{} + + // native.ExampleBool = cfg.ExampleBool.Value + // native.ExampleInt = cfg.ExampleInt.Value + // native.ExampleUint = cfg.ExampleUint.Value + // native.ExampleFloat = cfg.ExampleFloat.Value + // native.ExampleString = cfg.ExampleString.Value + // native.ExampleChoice = cfg.ExampleChoice.Value + // native.SubConfig.SubExampleBool = cfg.SubConfig.SubExampleBool.Value + // native.SubConfig.SubExampleChoice = cfg.SubConfig.SubExampleChoice.Value + // return native + return nil +} + +// Configuration manager +type AdapterConfigManager struct { + // The adapter configuration + AdapterConfig *ExampleConfig + + // The native configuration manager + // nativeConfigManager *nativecfg.ConfigManager + + // The path to the adapter configuration file + adapterConfigPath string +} + +// Create a new configuration manager for the adapter +func NewAdapterConfigManager(c *cli.Context) (*AdapterConfigManager, error) { + // configDir := c.String(utils.ConfigDirFlag.Name) + // if configDir == "" { + // return nil, fmt.Errorf("config directory is required") + // } + // return &AdapterConfigManager{ + // // nativeConfigManager: nativecfg.NewConfigManager(filepath.Join(configDir, utils.ServiceConfigFile)), + // adapterConfigPath: filepath.Join(configDir, utils.AdapterConfigFile), + // }, nil + return nil, nil +} + +// Load the configuration from disk +func (m *AdapterConfigManager) LoadConfigFromDisk() (*ExampleConfig, error) { + // Load the native config + // nativeCfg, err := m.nativeConfigManager.LoadConfigFromFile() + // if err != nil { + // return nil, fmt.Errorf("error loading service config: %w", err) + // } + + // // Check if the adapter config exists + // _, err = os.Stat(m.adapterConfigPath) + // if errors.Is(err, fs.ErrNotExist) { + // return nil, nil + // } + + // Load it + bytes, err := os.ReadFile(m.adapterConfigPath) + if err != nil { + return nil, fmt.Errorf("error reading config file [%s]: %w", m.adapterConfigPath, err) + } + + // Deserialize it + cfgInstance := map[string]any{} + err = yaml.Unmarshal(bytes, &cfgInstance) + if err != nil { + return nil, fmt.Errorf("error deserializing adapter config file [%s]: %w", m.adapterConfigPath, err) + } + serverCfg := NewServerConfig() + portInt := cfgInstance[ids.PortID].(int) + serverCfg.Port.Value = uint64(portInt) + serverCfg.PortMode.Value = PortMode(cfgInstance[ids.PortModeID].(string)) + + // Merge the configs + // modCfg := ConvertToMetadata(nativeCfg) + // modCfg.ServerConfig = serverCfg + // m.AdapterConfig = modCfg + // return modCfg, nil + return nil, nil +} + +// Save the configuration to a file. If the config hasn't been loaded yet, this doesn't do anything. +func (m *AdapterConfigManager) SaveConfigToDisk() error { + if m.AdapterConfig == nil { + return nil + } + + // // Save the native config + // nativeCfg := m.AdapterConfig.ConvertToNative() + // m.nativeConfigManager.Config = nativeCfg + // err := m.nativeConfigManager.SaveConfigToFile() + // if err != nil { + // return fmt.Errorf("error saving service config: %w", err) + // } + + // Serialize the adapter config + // modCfg := hdconfig.CreateInstanceFromMetadata(m.AdapterConfig.ServerConfig) + // bytes, err := yaml.Marshal(modCfg) + // if err != nil { + // return fmt.Errorf("error serializing adapter config: %w", err) + // } + + // Write it + // err = os.WriteFile(m.adapterConfigPath, bytes, nativecfg.ConfigFileMode) + // if err != nil { + // return fmt.Errorf("error writing adapter config file [%s]: %w", m.adapterConfigPath, err) + // } + return nil +} diff --git a/adapter/config/ids/ids.go b/adapter/config/ids/ids.go new file mode 100644 index 0000000..90fd979 --- /dev/null +++ b/adapter/config/ids/ids.go @@ -0,0 +1,16 @@ +package ids + +const ( + ExampleBoolID string = "exampleBool" + ExampleIntID string = "exampleInt" + ExampleUintID string = "exampleUint" + ExampleFloatID string = "exampleFloat" + ExampleStringID string = "exampleString" + ExampleChoiceID string = "exampleChoice" + SubConfigID string = "subConfig" + SubExampleBoolID string = "subConfigBool" + SubExampleChoiceID string = "subConfigChoice" + ServerConfigID string = "server" + PortModeID string = "portMode" + PortID string = "port" +) diff --git a/adapter/command/initialize.go b/adapter/config/initialize.go similarity index 98% rename from adapter/command/initialize.go rename to adapter/config/initialize.go index 8500f6f..52d32f5 100644 --- a/adapter/command/initialize.go +++ b/adapter/config/initialize.go @@ -1,4 +1,4 @@ -package command +package config import ( "fmt" diff --git a/adapter/command/upload-deposit-data.go b/adapter/config/upload-deposit-data.go similarity index 97% rename from adapter/command/upload-deposit-data.go rename to adapter/config/upload-deposit-data.go index 848475d..3baf692 100644 --- a/adapter/command/upload-deposit-data.go +++ b/adapter/config/upload-deposit-data.go @@ -1,4 +1,4 @@ -package command +package config import ( "fmt" diff --git a/adapter/hd-module/get-config-instance.go b/adapter/hd-module/get-config-instance.go new file mode 100644 index 0000000..5f36636 --- /dev/null +++ b/adapter/hd-module/get-config-instance.go @@ -0,0 +1,45 @@ +package hdmodule + +import ( + "fmt" + + "github.com/goccy/go-json" + "github.com/nodeset-org/hyperdrive-stakewise/adapter/config" + "github.com/nodeset-org/hyperdrive-stakewise/adapter/utils" + hdconfig "github.com/nodeset-org/hyperdrive/modules/config" + "github.com/urfave/cli/v2" +) + +func getConfigInstance(c *cli.Context) error { + // Get the request + _, err := utils.HandleKeyedRequest[*utils.KeyedRequest](c) + if err != nil { + return err + } + + // Get the config + cfgMgr, err := config.NewAdapterConfigManager(c) + if err != nil { + return fmt.Errorf("error creating config manager: %w", err) + } + cfg, err := cfgMgr.LoadConfigFromDisk() + if err != nil { + return fmt.Errorf("error loading config: %w", err) + } + + // Handle no saved config + if cfg == nil { + return fmt.Errorf("config has not been initialized yet") + } + + // Create the response + instance := hdconfig.CreateInstanceFromMetadata(cfg) + bytes, err := json.Marshal(instance) + if err != nil { + return fmt.Errorf("error marshalling config: %w", err) + } + + // Print it + fmt.Println(string(bytes)) + return nil +} diff --git a/adapter/utils/auth.go b/adapter/utils/auth.go new file mode 100644 index 0000000..672ac38 --- /dev/null +++ b/adapter/utils/auth.go @@ -0,0 +1,99 @@ +package utils + +import ( + "bufio" + "fmt" + "io/fs" + "os" + + "errors" + + "github.com/goccy/go-json" + "github.com/urfave/cli/v2" +) + +const ( + AuthenticatorMetadataKey string = "authenticator" +) + +// KeyedRequest is a request that contains a key used for authentication +type KeyedRequest struct { + Key string `json:"key"` +} + +// Returns the key for the request +func (r *KeyedRequest) GetKey() string { + return r.Key +} + +// Interface for requests that contain a key +type IKeyedRequest interface { + GetKey() string +} + +// Simple authenticator used for processing incoming requests +type Authenticator struct { + key string +} + +// Creates a new Authenticator instance +func NewAuthenticator(c *cli.Context) (*Authenticator, error) { + keyFile := c.String(KeyFileFlag.Name) + if keyFile == "" { + return nil, fmt.Errorf("secret key file is required") + } + + // Make sure the file exists + _, err := os.Stat(keyFile) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + return nil, fmt.Errorf("key file [%s] does not exist", keyFile) + } + return nil, fmt.Errorf("error checking key file [%s]: %w", keyFile, err) + } + + // Read the key file + key, err := os.ReadFile(keyFile) + if err != nil { + return nil, fmt.Errorf("error reading key file [%s]: %w", keyFile, err) + } + + return &Authenticator{ + key: string(key), + }, nil +} + +// Authenticate checks if the provided key matches the stored key +func (a *Authenticator) Authenticate(key string) error { + if key != a.key { + return errors.New("invalid key") + } + return nil +} + +// Handles an incoming keyed request by reading the input, parsing it, and authenticating it +func HandleKeyedRequest[RequestType IKeyedRequest](c *cli.Context) (RequestType, error) { + var data RequestType + + // Read the input + reader := bufio.NewReader(os.Stdin) + input, err := reader.ReadString('\n') + if err != nil { + return data, fmt.Errorf("error reading input: %w", err) + } + + // Parse the input + err = json.Unmarshal([]byte(input), &data) + if err != nil { + return data, fmt.Errorf("error parsing input: %w", err) + } + + // Authenticate the request + authenticator := c.App.Metadata[AuthenticatorMetadataKey].(*Authenticator) + err = authenticator.Authenticate(data.GetKey()) + if err != nil { + return data, fmt.Errorf("error authenticating request: %w", err) + } + + return data, nil +} diff --git a/adapter/utils/flags.go b/adapter/utils/flags.go index a804479..de93d2e 100644 --- a/adapter/utils/flags.go +++ b/adapter/utils/flags.go @@ -73,6 +73,12 @@ var ( Aliases: []string{"st"}, Usage: "Sign any TXs and print the results, but don't submit it to the network. Useful if you want to save a TX for later or bundle it up with a service like Flashbots.", } + KeyFileFlag *cli.StringFlag = &cli.StringFlag{ + Name: "secret", + Aliases: []string{"s"}, + Usage: "The path to the secret key file for authentication", + Value: "/hd/secret", + } ) func InstantiateFlag[FlagType cli.Flag](prototype FlagType, description string) cli.Flag { diff --git a/adapter/utils/gas.go b/adapter/utils/gas.go index 87c5218..c60529d 100644 --- a/adapter/utils/gas.go +++ b/adapter/utils/gas.go @@ -6,8 +6,8 @@ import ( "math/big" "strconv" + "github.com/nodeset-org/hyperdrive-stakewise/adapter/utils/terminal" swclient "github.com/nodeset-org/hyperdrive-stakewise/client" - "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/terminal" "github.com/rocket-pool/node-manager-core/eth" "github.com/rocket-pool/node-manager-core/gas" "github.com/urfave/cli/v2" diff --git a/adapter/utils/prompt.go b/adapter/utils/prompt.go index 4eaf58a..1951733 100644 --- a/adapter/utils/prompt.go +++ b/adapter/utils/prompt.go @@ -9,7 +9,7 @@ import ( "strings" "syscall" - "github.com/nodeset-org/hyperdrive/hyperdrive-cli/utils/terminal" + "github.com/nodeset-org/hyperdrive-stakewise/adapter/utils/terminal" "golang.org/x/term" ) diff --git a/go.mod b/go.mod index a6ae126..e9f72cd 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 github.com/mitchellh/go-homedir v1.1.0 - github.com/nodeset-org/hyperdrive v1.1.1 + github.com/nodeset-org/hyperdrive v1.1.2-0.20250106215109-78519b2bef69 github.com/nodeset-org/hyperdrive-daemon v1.1.1 github.com/nodeset-org/nodeset-client-go v1.2.2 github.com/nodeset-org/osha v0.3.1 diff --git a/go.sum b/go.sum index a797e22..b6af530 100644 --- a/go.sum +++ b/go.sum @@ -379,6 +379,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nodeset-org/hyperdrive v1.1.1 h1:PImbcczTqGpx0UPJugQIZkxzlWMJn9O5+138mOrbeKA= github.com/nodeset-org/hyperdrive v1.1.1/go.mod h1:BId3aaponZ2gPeNReLIdB+AAK0sDOKUxV3xAQQrs4fg= +github.com/nodeset-org/hyperdrive v1.1.2-0.20250106215109-78519b2bef69 h1:FJojeBJ3vr7hsIaKzZJDKYPAvxT+kYPUX3ratal9Kmc= +github.com/nodeset-org/hyperdrive v1.1.2-0.20250106215109-78519b2bef69/go.mod h1:nBfN+6oGRe91ZmMrfoQcGCiSGj1ryKfwN5Ap6UfeqwA= github.com/nodeset-org/hyperdrive-daemon v1.1.1 h1:aUQzEKmyuYhVTzn3AQEIdUm335xBYmsCTJfPdGNA5r0= github.com/nodeset-org/hyperdrive-daemon v1.1.1/go.mod h1:tzqdqfRR4Xcy4GtdSiEnfjOFj3+g4TvuZJpYljCQEBM= github.com/nodeset-org/nodeset-client-go v1.2.2 h1:mjJnH5uw/CF5TWdRxdU5+Cw/ERRLz4hl9VsRFVO0Wdo= diff --git a/shared/config/ids/config.go b/shared/config/ids/config.go new file mode 100644 index 0000000..bb4a7d7 --- /dev/null +++ b/shared/config/ids/config.go @@ -0,0 +1,106 @@ +package ids + +import ( + "errors" + "fmt" + "io/fs" + "os" + + "gopkg.in/yaml.v3" +) + +const ( + ConfigFileMode os.FileMode = 0644 +) + +// Example of a choice option, like an enum +type ExampleOption string + +const ( + ExampleOption_One ExampleOption = "one" + ExampleOption_Two ExampleOption = "two" + ExampleOption_Three ExampleOption = "three" +) + +// Example of a configuration for a service +type NativeExampleConfig struct { + ExampleBool bool `json:"exampleBool" yaml:"exampleBool"` + + ExampleInt int64 `json:"exampleInt" yaml:"exampleInt"` + + ExampleUint uint64 `json:"exampleUint" yaml:"exampleUint"` + + ExampleFloat float64 `json:"exampleFloat" yaml:"exampleFloat"` + + ExampleString string `json:"exampleString" yaml:"exampleString"` + + ExampleChoice ExampleOption `json:"exampleChoice" yaml:"exampleChoice"` + + SubConfig NativeSubConfig `json:"subConfig" yaml:"subConfig"` +} + +// Example of a section under the service's top-level configuration +type NativeSubConfig struct { + SubExampleBool bool `json:"subExampleBool" yaml:"subExampleBool"` + + SubExampleChoice ExampleOption `json:"subExampleChoice" yaml:"subExampleChoice"` +} + +// Configuration manager +type ConfigManager struct { + // The configuration + Config *NativeExampleConfig + + // The path to the configuration file + ConfigPath string +} + +// Create a new configuration manager +func NewConfigManager(path string) *ConfigManager { + return &ConfigManager{ + ConfigPath: path, + } +} + +// Load the configuration from a file +func (m *ConfigManager) LoadConfigFromFile() (*NativeExampleConfig, error) { + // Check if the file exists + _, err := os.Stat(m.ConfigPath) + if errors.Is(err, fs.ErrNotExist) { + return nil, nil + } + + // Load it + bytes, err := os.ReadFile(m.ConfigPath) + if err != nil { + return nil, fmt.Errorf("error reading config file [%s]: %w", m.ConfigPath, err) + } + + // Deserialize it + cfg := NativeExampleConfig{} + err = yaml.Unmarshal(bytes, &cfg) + if err != nil { + return nil, fmt.Errorf("error deserializing config file [%s]: %w", m.ConfigPath, err) + } + return &cfg, nil +} + +// Save the configuration to a file. If the config hasn't been loaded yet, this doesn't do anything. +func (m *ConfigManager) SaveConfigToFile() error { + if m.Config == nil { + return nil + } + + // Serialize it + bytes, err := yaml.Marshal(m.Config) + if err != nil { + return fmt.Errorf("error serializing config: %w", err) + } + + // Write it + err = os.WriteFile(m.ConfigPath, bytes, ConfigFileMode) + if err != nil { + return fmt.Errorf("error writing config file [%s]: %w", m.ConfigPath, err) + } + return nil +}