mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-11 06:58:20 -05:00
Co-authored-by: colinlyguo <colinlyguo@scroll.io> Co-authored-by: colinlyguo <colinlyguo@users.noreply.github.com> Co-authored-by: Péter Garamvölgyi <peter@scroll.io> Co-authored-by: colin <102356659+colinlyguo@users.noreply.github.com>
171 lines
3.7 KiB
Go
171 lines
3.7 KiB
Go
package utils
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/modern-go/reflect2"
|
|
"github.com/scroll-tech/go-ethereum/core"
|
|
"github.com/scroll-tech/go-ethereum/log"
|
|
)
|
|
|
|
// TryTimes try run several times until the function return true.
|
|
func TryTimes(times int, run func() bool) bool {
|
|
for i := 0; i < times; i++ {
|
|
if run() {
|
|
return true
|
|
}
|
|
time.Sleep(time.Millisecond * 500)
|
|
}
|
|
return false
|
|
}
|
|
|
|
// LoopWithContext Run the f func with context periodically.
|
|
func LoopWithContext(ctx context.Context, period time.Duration, f func(ctx context.Context)) {
|
|
tick := time.NewTicker(period)
|
|
defer tick.Stop()
|
|
for ; ; <-tick.C {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
default:
|
|
f(ctx)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Loop Run the f func periodically.
|
|
func Loop(ctx context.Context, period time.Duration, f func()) {
|
|
tick := time.NewTicker(period)
|
|
defer tick.Stop()
|
|
for ; ; <-tick.C {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
default:
|
|
f()
|
|
}
|
|
}
|
|
}
|
|
|
|
// IsNil Check if the interface is empty.
|
|
func IsNil(i interface{}) bool {
|
|
return i == nil || reflect2.IsNil(i)
|
|
}
|
|
|
|
// RandomURL return a random port endpoint.
|
|
func RandomURL() string {
|
|
id, _ := rand.Int(rand.Reader, big.NewInt(5000-1))
|
|
return fmt.Sprintf("localhost:%d", 10000+2000+id.Int64())
|
|
}
|
|
|
|
// ReadGenesis parses and returns the genesis file at the given path
|
|
func ReadGenesis(genesisPath string) (*core.Genesis, error) {
|
|
file, err := os.Open(filepath.Clean(genesisPath))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
genesis := new(core.Genesis)
|
|
if err := json.NewDecoder(file).Decode(genesis); err != nil {
|
|
return nil, errors.Join(err, file.Close())
|
|
}
|
|
return genesis, file.Close()
|
|
}
|
|
|
|
// OverrideConfigWithEnv recursively overrides config values with environment variables
|
|
func OverrideConfigWithEnv(cfg interface{}, prefix string) error {
|
|
v := reflect.ValueOf(cfg)
|
|
if v.Kind() != reflect.Ptr || v.IsNil() {
|
|
return nil
|
|
}
|
|
v = v.Elem()
|
|
|
|
t := v.Type()
|
|
for i := 0; i < t.NumField(); i++ {
|
|
field := t.Field(i)
|
|
fieldValue := v.Field(i)
|
|
|
|
if !fieldValue.CanSet() {
|
|
continue
|
|
}
|
|
|
|
tag := field.Tag.Get("json")
|
|
if tag == "" {
|
|
tag = strings.ToLower(field.Name)
|
|
}
|
|
|
|
envKey := prefix + "_" + strings.ToUpper(tag)
|
|
|
|
switch fieldValue.Kind() {
|
|
case reflect.Ptr:
|
|
if !fieldValue.IsNil() {
|
|
err := OverrideConfigWithEnv(fieldValue.Interface(), envKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
case reflect.Struct:
|
|
err := OverrideConfigWithEnv(fieldValue.Addr().Interface(), envKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
default:
|
|
if envValue, exists := os.LookupEnv(envKey); exists {
|
|
log.Info("Overriding config with env var", "key", envKey)
|
|
err := setField(fieldValue, envValue)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// setField sets the value of a field based on the environment variable value
|
|
func setField(field reflect.Value, value string) error {
|
|
switch field.Kind() {
|
|
case reflect.String:
|
|
field.SetString(value)
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
intValue, err := strconv.ParseInt(value, 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
field.SetInt(intValue)
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
uintValue, err := strconv.ParseUint(value, 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
field.SetUint(uintValue)
|
|
case reflect.Float32, reflect.Float64:
|
|
floatValue, err := strconv.ParseFloat(value, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
field.SetFloat(floatValue)
|
|
case reflect.Bool:
|
|
boolValue, err := strconv.ParseBool(value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
field.SetBool(boolValue)
|
|
default:
|
|
return fmt.Errorf("unsupported type: %v", field.Kind())
|
|
}
|
|
return nil
|
|
}
|