-
Notifications
You must be signed in to change notification settings - Fork 207
/
utils.go
173 lines (140 loc) · 3.65 KB
/
utils.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// Package utils [general utility functions for the db1000n app]
package utils
import (
"context"
"fmt"
"log"
"os"
"os/exec"
"runtime"
"strconv"
"strings"
"time"
"github.com/mitchellh/mapstructure"
"go.uber.org/zap"
"gopkg.in/yaml.v3"
)
// PanicHandler just stub it in the beginning of every major module invocation to prevent single module failure from crashing the whole app
func PanicHandler(logger *zap.Logger) {
if err := recover(); err != nil {
logger.Error("caught panic, recovering", zap.Any("err", err))
}
}
// GetEnvStringDefault returns environment variable or default value if no env varible is present
func GetEnvStringDefault(key, defaultValue string) string {
value, ok := os.LookupEnv(key)
if !ok {
return defaultValue
}
return value
}
// GetEnvIntDefault returns environment variable or default value if no env varible is present
func GetEnvIntDefault(key string, defaultValue int) int {
value, ok := os.LookupEnv(key)
if !ok {
return defaultValue
}
v, err := strconv.Atoi(value)
if err != nil {
log.Printf("GetEnvIntDefault[%s]: %v", key, err)
return defaultValue
}
return v
}
// GetEnvBoolDefault returns environment variable or default value if no env varible is present
func GetEnvBoolDefault(key string, defaultValue bool) bool {
value, ok := os.LookupEnv(key)
if !ok {
return defaultValue
}
v, err := strconv.ParseBool(value)
if err != nil {
log.Printf("GetEnvBoolDefault[%s]: %v", key, err)
return defaultValue
}
return v
}
// GetEnvDurationDefault returns environment variable or default value if no env varible is present
func GetEnvDurationDefault(key string, defaultValue time.Duration) time.Duration {
value, ok := os.LookupEnv(key)
if !ok {
return defaultValue
}
v, err := time.ParseDuration(value)
if err != nil {
log.Printf("GetEnvBoolDefault[%s]: %v", key, err)
return defaultValue
}
return v
}
func NonNilOrDefault[T any](v *T, dflt T) T {
if v != nil {
return *v
}
return dflt
}
// Decode is an alias to a mapstructure.NewDecoder({Squash: true}).Decode()
// with WeaklyTypedInput set to true and MatchFunc that only compares aplhanumeric sequence in field names
func Decode(input any, output any) error {
filter := func(r rune) rune {
if ('a' <= r && r <= 'z') ||
('A' <= r && r <= 'Z') ||
('0' <= r && r <= '9') {
return r
}
return -1
}
matchName := func(lhs, rhs string) bool {
return strings.EqualFold(strings.Map(filter, lhs), strings.Map(filter, rhs))
}
decoderConfig := &mapstructure.DecoderConfig{
Squash: true,
WeaklyTypedInput: true,
MatchName: matchName,
DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
Result: output,
}
decoder, err := mapstructure.NewDecoder(decoderConfig)
if err != nil {
return err
}
return decoder.Decode(input)
}
// It could've been more effective if go had yield but this should be close enough
func InfiniteRange[T any](ctx context.Context, input []T) chan T {
result := make(chan T)
loop := func() {
defer close(result)
for {
for _, el := range input {
select {
case <-ctx.Done():
return
case result <- el:
}
}
}
}
go loop()
return result
}
func Unmarshal(input []byte, output any, format string) error {
switch format {
case "", "json", "yaml":
if err := yaml.Unmarshal(input, output); err != nil {
return err
}
default:
return fmt.Errorf("unknown config format: %v", format)
}
return nil
}
func openBrowser(url string) {
switch runtime.GOOS {
case "windows":
_ = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
case "darwin":
_ = exec.Command("open", url).Start()
}
log.Printf("Please open %s", url)
}