forked from ethereum-optimism/optimism
-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.go
107 lines (95 loc) · 2.91 KB
/
util.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package op_service
import (
"context"
"errors"
"fmt"
"os"
"os/signal"
"reflect"
"strings"
"syscall"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"
)
// PrefixEnvVar adds a prefix to the environment variable,
// and returns the env-var wrapped in a slice for usage with urfave CLI v2.
func PrefixEnvVar(prefix, suffix string) []string {
return []string{prefix + "_" + suffix}
}
// ValidateEnvVars logs all env vars that are found where the env var is
// prefixed with the supplied prefix (like OP_BATCHER) but there is no
// actual env var with that name.
// It helps validate that the supplied env vars are in fact valid.
func ValidateEnvVars(prefix string, flags []cli.Flag, log log.Logger) {
for _, envVar := range validateEnvVars(prefix, os.Environ(), cliFlagsToEnvVars(flags)) {
log.Warn("Unknown env var", "prefix", prefix, "env_var", envVar)
}
}
func cliFlagsToEnvVars(flags []cli.Flag) map[string]struct{} {
definedEnvVars := make(map[string]struct{})
for _, flag := range flags {
envVars := reflect.ValueOf(flag).Elem().FieldByName("EnvVars")
for i := 0; i < envVars.Len(); i++ {
envVarField := envVars.Index(i)
definedEnvVars[envVarField.String()] = struct{}{}
}
}
return definedEnvVars
}
// validateEnvVars returns a list of the unknown environment variables that match the prefix.
func validateEnvVars(prefix string, providedEnvVars []string, definedEnvVars map[string]struct{}) []string {
var out []string
for _, envVar := range providedEnvVars {
parts := strings.Split(envVar, "=")
if len(parts) == 0 {
continue
}
key := parts[0]
if strings.HasPrefix(key, prefix) {
if _, ok := definedEnvVars[key]; !ok {
out = append(out, envVar)
}
}
}
return out
}
// ParseAddress parses an ETH address from a hex string. This method will fail if
// the address is not a valid hexadecimal address.
func ParseAddress(address string) (common.Address, error) {
if common.IsHexAddress(address) {
return common.HexToAddress(address), nil
}
return common.Address{}, fmt.Errorf("invalid address: %v", address)
}
// CloseAction runs the function in the background, until it finishes or until it is closed by the user with an interrupt.
func CloseAction(fn func(ctx context.Context, shutdown <-chan struct{}) error) error {
stopped := make(chan error, 1)
shutdown := make(chan struct{}, 1)
ctx, cancel := context.WithCancel(context.Background())
go func() {
stopped <- fn(ctx, shutdown)
}()
doneCh := make(chan os.Signal, 1)
signal.Notify(doneCh, []os.Signal{
os.Interrupt,
os.Kill,
syscall.SIGTERM,
syscall.SIGQUIT,
}...)
select {
case <-doneCh:
cancel()
shutdown <- struct{}{}
select {
case err := <-stopped:
return err
case <-time.After(time.Second * 10):
return errors.New("command action is unresponsive for more than 10 seconds... shutting down")
}
case err := <-stopped:
cancel()
return err
}
}