diff --git a/cmd/sequencer/config/config.go b/cmd/sequencer/config/config.go new file mode 100644 index 0000000..30e309e --- /dev/null +++ b/cmd/sequencer/config/config.go @@ -0,0 +1,70 @@ +package config + +import ( + "log/slog" + "os" + + "github.com/machinefi/sprout-pebble-sequencer/util/env" +) + +type Config struct { + LogLevel slog.Level `env:"LOG_LEVEL,optional"` + BootNodeMultiAddr string `env:"BOOTNODE_MULTIADDR"` + IoTeXChainID int `env:"IOTEX_CHAINID"` + DatasourceDSN string `env:"DATASOURCE_DSN"` + ChainEndpoint string `env:"CHAIN_ENDPOINT,optional"` + OperatorPrvKey string `env:"OPERATOR_PRIVATE_KEY,optional"` + LocalDBDir string `env:"LOCAL_DB_DIRECTORY,optional"` + BeginningBlockNumber uint64 `env:"BEGINNING_BLOCK_NUMBER,optional"` + ProverContractAddr string `env:"PROVER_CONTRACT_ADDRESS,optional"` + MinterContractAddr string `env:"MINTER_CONTRACT_ADDRESS,optional"` + TaskManagerContractAddr string `env:"TASK_MANAGER_CONTRACT_ADDRESS,optional"` + env string `env:"-"` +} + +var ( + defaultTestnetConfig = &Config{ + LogLevel: slog.LevelInfo, + BootNodeMultiAddr: "/dns4/bootnode-0.testnet.iotex.one/tcp/4689/ipfs/12D3KooWFnaTYuLo8Mkbm3wzaWHtUuaxBRe24Uiopu15Wr5EhD3o", + DatasourceDSN: "postgres://postgres:mysecretpassword@postgres:5432/w3bstream?sslmode=disable", + IoTeXChainID: 2, + ChainEndpoint: "https://babel-api.testnet.iotex.io", + OperatorPrvKey: "33e6ba3e033131026903f34dfa208feb88c284880530cf76280b68d38041c67b", + ProverContractAddr: "0xab6836908d15E42D30bdEf14cbFA4ad45dCAF3a3", + MinterContractAddr: "0x49C096AE869A3054Db06ffF221b917b41f94CEf3", + TaskManagerContractAddr: "0xF0714400a4C0C72007A9F910C5E3007614958636", + LocalDBDir: "./local_db", + BeginningBlockNumber: 28685000, + env: "TESTNET", + } +) + +func (c *Config) init() error { + if err := env.ParseEnv(c); err != nil { + return err + } + h := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.Level(c.LogLevel)}) + slog.SetDefault(slog.New(h)) + return nil +} + +func Get() (*Config, error) { + var conf *Config + env := os.Getenv("ENV") + switch env { + case "TESTNET": + conf = defaultTestnetConfig + default: + env = "TESTNET" + conf = defaultTestnetConfig + } + conf.env = env + if err := conf.init(); err != nil { + return nil, err + } + return conf, nil +} + +func (c *Config) Print() { + env.Print(c) +} diff --git a/util/env/env.go b/util/env/env.go new file mode 100644 index 0000000..9c25d67 --- /dev/null +++ b/util/env/env.go @@ -0,0 +1,80 @@ +package env + +import ( + "fmt" + "log/slog" + "reflect" + "strings" + + "github.com/fatih/color" + "github.com/spf13/viper" +) + +func parseEnvTag(tag string) (key string, require bool) { + if tag == "" || tag == "-" { + return "", false + } + tagKeys := strings.Split(tag, ",") + key = tagKeys[0] + if len(tagKeys) > 1 && tagKeys[1] == "optional" { + return key, false + } + return key, true +} + +func ParseEnv(c any) error { + rv := reflect.ValueOf(c).Elem() + rt := reflect.TypeOf(c).Elem() + + for i := 0; i < rt.NumField(); i++ { + fi := rt.Field(i) + fv := rv.Field(i) + key, require := parseEnvTag(fi.Tag.Get("env")) + if key == "" { + continue + } + viper.MustBindEnv(key) + + v := viper.Get(key) + if require && v == nil && fv.IsZero() { + panic(fmt.Sprintf("env `%s` is require but got empty", key)) + } + if v == nil { + continue + } + + switch fv.Kind() { + case reflect.String: + fv.Set(reflect.ValueOf(viper.GetString(key))) + case reflect.Int: + if fi.Type == reflect.TypeOf(slog.Level(0)) { + level := slog.Level(viper.GetInt(key)) + fv.Set(reflect.ValueOf(level)) + } else { + fv.Set(reflect.ValueOf(viper.GetInt(key))) + } + case reflect.Uint64: + fv.Set(reflect.ValueOf(viper.GetUint64(key))) + } + } + return nil +} + +func Print(c any) { + rt := reflect.TypeOf(c).Elem() + rv := reflect.ValueOf(c).Elem() + + if env, ok := c.(interface{ Env() string }); ok { + fmt.Println(color.CyanString("ENV: %s", env.Env())) + } + + for i := 0; i < rt.NumField(); i++ { + fi := rt.Field(i) + fv := rv.Field(i) + key, _ := parseEnvTag(fi.Tag.Get("env")) + if key == "" { + continue + } + fmt.Printf("%s: %v\n", color.GreenString(key), fv.Interface()) + } +}