github.com/packtpublishing/learning-functional-programming-in-go@v0.0.0-20230130084745-8b849f6d58c4/Chapter07/func-param/src/utils/options.go (about)

     1  package utils
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"github.com/BurntSushi/toml"
     7  	"reflect"
     8  	"strconv"
     9  	"github.com/pkg/errors"
    10  )
    11  
    12  type Conf struct {
    13  	Port	string   `toml:"port"`
    14  	LogDebugInfo         bool     `toml:"log_debug_info"`
    15  	MaxConcurrentConnections	int   `toml:"max_concurrent_connections"`
    16  	MaxNumber	int   `toml:"max_number"`
    17  	UseNumberHandler	bool   `toml:"use_number_handler"`
    18  }
    19  
    20  var Config Conf
    21  
    22  func GetOptions() bool {
    23  	var configFile string
    24  
    25  	flag.StringVar(&configFile, "config", "", "Configuration file")
    26  	flag.StringVar(&Config.Port, "port", "8080", "Port that the API listens on")
    27  	flag.BoolVar(&Config.LogDebugInfo, "log-debug-info", false, "Whether to log debug output to the log (set to true for debug purposes)")
    28  	flag.IntVar(&Config.MaxConcurrentConnections, "max-concurrent-connections", 6, "Maximum number of concurrent connections (not currently used)")
    29  	flag.IntVar(&Config.MaxNumber, "max_number", 10, "Maximum number that user is allowed to enter")
    30  	flag.BoolVar(&Config.UseNumberHandler, "use-number-handler", true, "Use number handler (to display number, optionally with FormatNumber applied) else display files in project root")
    31  
    32  	flag.Parse()
    33  
    34  	if configFile != "" {
    35  		if _, err := toml.DecodeFile(configFile, &Config); err != nil {
    36  			HandlePanic(errors.Wrap(err, "unable to read config file"))
    37  		}
    38  	}
    39  	return true
    40  }
    41  
    42  type Datastore interface {}
    43  
    44  // UpdateConfigVal returns string representation of old config value
    45  func UpdateConfigVal(d Datastore, key, val string) (oldValue string) {
    46  	Debug.Printf("key (%s), val (%v)\n", key, val)
    47  	value := reflect.ValueOf(d)
    48  	if value.Kind() != reflect.Ptr {
    49  		panic("not a pointer")
    50  	}
    51  	valElem := value.Elem()
    52  	//this loops through the fields
    53  	for i := 0; i < valElem.NumField(); i++ { // iterates through every struct type field
    54  		tag := valElem.Type().Field(i).Tag // returns the tag string
    55  		field := valElem.Field(i)          // returns the content of the struct type field
    56  		switch tag.Get("toml") {
    57  		case key:
    58  			if fmt.Sprintf("%v", field.Kind()) == "int" {
    59  				oldValue = strconv.FormatInt(field.Int(), 10)
    60  				intVal, err := strconv.Atoi(val)
    61  				if err != nil {
    62  					fmt.Printf("could not parse int, key(%s) val(%s)", key, val)
    63  				} else {
    64  					field.SetInt(int64(intVal))
    65  				}
    66  			} else if fmt.Sprintf("%v", field.Kind()) == "bool" {
    67  				oldValue = strconv.FormatBool(field.Bool())
    68  				b, err := strconv.ParseBool(val)
    69  				if err != nil {
    70  					fmt.Printf("could not parse bool, key(%s) val(%s)", key, val)
    71  				} else {
    72  					field.SetBool(b)
    73  				}
    74  			} else {
    75  				// Currently only supports bool, int and string
    76  				oldValue = field.String()
    77  				field.SetString(val)
    78  			}
    79  		}
    80  	}
    81  	return
    82  }
    83