package main import ( "encoding/json" "flag" "io/ioutil" "os" "reflect" "strings" ) const ( mbpsToBps = 125000 DefaultMaxReceiveStreamFlowControlWindow = 33554432 DefaultMaxReceiveConnectionFlowControlWindow = 67108864 DefaultMaxIncomingStreams = 200 ) func loadConfig(cfg interface{}, args []string) error { cfgVal := reflect.ValueOf(cfg).Elem() fs := flag.NewFlagSet("", flag.ContinueOnError) fsValMap := make(map[reflect.Value]interface{}, cfgVal.NumField()) for i := 0; i < cfgVal.NumField(); i++ { structField := cfgVal.Type().Field(i) tag := structField.Tag switch structField.Type.Kind() { case reflect.String: fsValMap[cfgVal.Field(i)] = fs.String(jsonTagToFlagName(tag.Get("json")), "", tag.Get("desc")) case reflect.Int: fsValMap[cfgVal.Field(i)] = fs.Int(jsonTagToFlagName(tag.Get("json")), 0, tag.Get("desc")) case reflect.Uint64: fsValMap[cfgVal.Field(i)] = fs.Uint64(jsonTagToFlagName(tag.Get("json")), 0, tag.Get("desc")) case reflect.Bool: var bf optionalBoolFlag fs.Var(&bf, jsonTagToFlagName(tag.Get("json")), tag.Get("desc")) fsValMap[cfgVal.Field(i)] = &bf } } configFile := fs.String("config", "", "Configuration file") // Parse if err := fs.Parse(args); err != nil { os.Exit(1) } // Put together the config if len(*configFile) > 0 { cb, err := ioutil.ReadFile(*configFile) if err != nil { return err } if err := json.Unmarshal(cb, cfg); err != nil { return err } } // Flags override config from file for field, val := range fsValMap { switch v := val.(type) { case *string: if len(*v) > 0 { field.SetString(*v) } case *int: if *v != 0 { field.SetInt(int64(*v)) } case *uint64: if *v != 0 { field.SetUint(*v) } case *optionalBoolFlag: if v.Exists { field.SetBool(v.Value) } } } return nil } func jsonTagToFlagName(tag string) string { return strings.ReplaceAll(tag, "_", "-") }