repeater/internal/config/config.go
Pierre-Olivier Mercier 2b3a5b89f8 Add configuration system and ARP-based device discovery
Implement comprehensive configuration management with CLI flags for WiFi interface, device discovery method, and file paths. Add ARP table parsing as an alternative to DHCP leases for more reliable device detection. Improve WiFi scanning to handle concurrent scan requests gracefully.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-01 23:31:01 +07:00

87 lines
2 KiB
Go

package config
import (
"flag"
"log"
"os"
"path"
"strings"
)
type Config struct {
Bind string
WifiInterface string
UseARPDiscovery bool
DHCPLeasesPath string
ARPTablePath string
}
// ConsolidateConfig fills an Options struct by reading configuration from
// config files, environment, then command line.
//
// Should be called only one time.
func ConsolidateConfig() (opts *Config, err error) {
// Define defaults options
opts = &Config{
Bind: ":8080",
WifiInterface: "wlan0",
UseARPDiscovery: true,
DHCPLeasesPath: "/var/lib/dhcp/dhcpd.leases",
ARPTablePath: "/proc/net/arp",
}
declareFlags(opts)
// Establish a list of possible configuration file locations
configLocations := []string{
"repeater.conf",
}
if home, err := os.UserConfigDir(); err == nil {
configLocations = append(configLocations, path.Join(home, "repeater", "repeater.conf"))
}
configLocations = append(configLocations, path.Join("etc", "repeater.conf"))
// If config file exists, read configuration from it
for _, filename := range configLocations {
if _, e := os.Stat(filename); !os.IsNotExist(e) {
log.Printf("Loading configuration from %s\n", filename)
err = parseFile(opts, filename)
if err != nil {
return
}
break
}
}
// Then, overwrite that by what is present in the environment
err = parseEnvironmentVariables(opts)
if err != nil {
return
}
// Finaly, command line takes precedence
err = parseCLI(opts)
if err != nil {
return
}
return
}
// parseLine treats a config line and place the read value in the variable
// declared to the corresponding flag.
func parseLine(o *Config, line string) (err error) {
fields := strings.SplitN(line, "=", 2)
orig_key := strings.TrimSpace(fields[0])
value := strings.TrimSpace(fields[1])
key := strings.TrimPrefix(orig_key, "REPEATER_")
key = strings.Replace(key, "_", "-", -1)
key = strings.ToLower(key)
err = flag.Set(key, value)
return
}