package config import ( "bufio" "fmt" "os" "strconv" "strings" ) type Config struct { GRPCListenAddr string GRPCAdvertiseAddr string DiscoveryPort int UARTDevice string UARTBaud int } func Default() Config { return Config{ GRPCListenAddr: ":50051", GRPCAdvertiseAddr: "127.0.0.1:50051", DiscoveryPort: 50052, UARTDevice: "/dev/ttyS3", UARTBaud: 115200, } } func Load(path string) (Config, error) { cfg := Default() if path == "" { return cfg, nil } f, err := os.Open(path) if err != nil { if os.IsNotExist(err) { return cfg, nil } return Config{}, err } defer f.Close() scanner := bufio.NewScanner(f) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, "#") { continue } key, value, ok := strings.Cut(line, ":") if !ok { return Config{}, fmt.Errorf("invalid config line: %q", line) } key = strings.ToLower(strings.TrimSpace(key)) value = strings.TrimSpace(value) value = strings.Trim(value, `"'`) switch key { case "grpc_addr": cfg.GRPCListenAddr = value cfg.GRPCAdvertiseAddr = value case "grpc_listen_addr": cfg.GRPCListenAddr = value case "grpc_advertise_addr": cfg.GRPCAdvertiseAddr = value case "discovery_port": n, err := strconv.Atoi(value) if err != nil { return Config{}, fmt.Errorf("invalid discovery_port: %w", err) } cfg.DiscoveryPort = n case "uart_device": cfg.UARTDevice = value case "uart_baud": n, err := strconv.Atoi(value) if err != nil { return Config{}, fmt.Errorf("invalid uart_baud: %w", err) } cfg.UARTBaud = n } } if err := scanner.Err(); err != nil { return Config{}, err } if cfg.GRPCAdvertiseAddr == "" { cfg.GRPCAdvertiseAddr = cfg.GRPCListenAddr } return cfg, nil }