to Config struct for configging

main
Bel LaPointe 2024-04-11 16:36:23 -06:00
parent 8b732b196d
commit 4c4d92478d
3 changed files with 125 additions and 7 deletions

68
config.go Normal file
View File

@ -0,0 +1,68 @@
package main
import (
"encoding/json"
"fmt"
"os"
"regexp"
"slices"
"strconv"
"strings"
)
type Config struct {
Port int
AB string
}
func newConfig() (Config, error) {
return newConfigFromEnv(os.Getenv)
}
func newConfigFromEnv(getEnv func(string) string) (Config, error) {
def := Config{
Port: 8080,
}
var m map[string]any
if b, err := json.Marshal(def); err != nil {
return Config{}, err
} else if err := json.Unmarshal(b, &m); err != nil {
return Config{}, err
}
re := regexp.MustCompile(`[A-Z]`)
for k, v := range m {
envK := k
idxes := re.FindAllIndex([]byte(envK), -1)
slices.Reverse(idxes)
for _, idx := range idxes {
if idx[0] > 0 {
envK = fmt.Sprintf("%s_%s", envK[:idx[0]], envK[idx[0]:])
}
}
envK = strings.ToUpper(envK)
s := getEnv(envK)
if s == "" {
continue
}
switch v.(type) {
case string:
m[k] = s
case int64, float64:
n, err := strconv.ParseFloat(s, 32)
if err != nil {
return Config{}, err
}
m[k] = n
}
}
var result Config
if b, err := json.Marshal(m); err != nil {
return Config{}, err
} else if err := json.Unmarshal(b, &result); err != nil {
return Config{}, err
}
return result, nil
}

23
config_test.go Normal file
View File

@ -0,0 +1,23 @@
package main
import "testing"
func TestNewConfig(t *testing.T) {
if got, err := newConfigFromEnv(func(k string) string {
t.Logf("getenv(%s)", k)
switch k {
case "PORT":
return "1"
case "A_B":
return "2"
default:
return ""
}
}); err != nil {
t.Fatal(err)
} else if got.Port != 1 {
t.Error(got)
} else if got.AB != "2" {
t.Error(got)
}
}

41
main.go
View File

@ -1,19 +1,46 @@
package main package main
import ( import (
"context"
"fmt" "fmt"
"net/http" "net/http"
"os" "os/signal"
"syscall"
) )
func main() { func main() {
p := os.Getenv("PORT") ctx, can := signal.NotifyContext(context.Background(), syscall.SIGINT)
if p == "" { defer can()
p = "8080"
}
addr := fmt.Sprintf(":%s", p)
if err := http.ListenAndServe(addr, http.HandlerFunc(http.NotFound)); err != nil { cfg, err := newConfig()
if err != nil {
panic(err)
}
if err := run(ctx, cfg); err != nil && ctx.Err() == nil {
panic(err) panic(err)
} }
} }
func run(ctx context.Context, cfg Config) error {
select {
case <-ctx.Done():
return ctx.Err()
case err := <-listenAndServe(ctx, cfg):
return err
}
}
func listenAndServe(ctx context.Context, cfg Config) chan error {
s := http.Server{
Addr: fmt.Sprintf(":%d", cfg.Port),
}
errc := make(chan error)
go func() {
defer close(errc)
errc <- s.ListenAndServe()
}()
return errc
}