From 1b374bccc61481f1e0e4407faef540403e8e2c4d Mon Sep 17 00:00:00 2001 From: Anna Rose Wiggins Date: Mon, 11 Aug 2025 12:38:07 -0400 Subject: [PATCH] Begin to overhaul config to couple initialization logic closer to the structs themselves. --- cmd/evinfo/main.go | 4 +- cmd/joyful/device_init.go | 47 +++++++++++++++ cmd/joyful/main.go | 24 ++------ internal/{config => configparser}/codes.go | 2 +- .../{config => configparser}/codes_test.go | 2 +- .../{config => configparser}/configparser.go | 58 ++++++++++++++++++- internal/{config => configparser}/devices.go | 2 +- .../{config => configparser}/devices_test.go | 2 +- .../{config => configparser}/interfaces.go | 2 +- .../make_rule_targets.go | 2 +- .../make_rule_targets_test.go | 2 +- .../{config => configparser}/make_rules.go | 2 +- internal/{config => configparser}/modes.go | 2 +- internal/{config => configparser}/schema.go | 2 +- .../{config => configparser}/variables.go | 2 +- 15 files changed, 122 insertions(+), 33 deletions(-) create mode 100644 cmd/joyful/device_init.go rename internal/{config => configparser}/codes.go (98%) rename internal/{config => configparser}/codes_test.go (99%) rename internal/{config => configparser}/configparser.go (59%) rename internal/{config => configparser}/devices.go (99%) rename internal/{config => configparser}/devices_test.go (99%) rename internal/{config => configparser}/interfaces.go (84%) rename internal/{config => configparser}/make_rule_targets.go (99%) rename internal/{config => configparser}/make_rule_targets_test.go (99%) rename internal/{config => configparser}/make_rules.go (99%) rename internal/{config => configparser}/modes.go (94%) rename internal/{config => configparser}/schema.go (99%) rename internal/{config => configparser}/variables.go (99%) diff --git a/cmd/evinfo/main.go b/cmd/evinfo/main.go index c2cc8f0..dd551d3 100644 --- a/cmd/evinfo/main.go +++ b/cmd/evinfo/main.go @@ -5,7 +5,7 @@ import ( "slices" // TODO: using config here feels like bad coupling... ButtonFromIndex might need a refactor / move - "git.annabunches.net/annabunches/joyful/internal/config" + "git.annabunches.net/annabunches/joyful/internal/configparser" "git.annabunches.net/annabunches/joyful/internal/logger" "github.com/holoplot/go-evdev" flag "github.com/spf13/pflag" @@ -20,7 +20,7 @@ func isJoystickLike(device *evdev.InputDevice) bool { if slices.Contains(types, evdev.EV_KEY) { buttons := device.CapableEvents(evdev.EV_KEY) - for _, code := range config.ButtonFromIndex { + for _, code := range configparser.ButtonFromIndex { if slices.Contains(buttons, code) { return true } diff --git a/cmd/joyful/device_init.go b/cmd/joyful/device_init.go new file mode 100644 index 0000000..fad6842 --- /dev/null +++ b/cmd/joyful/device_init.go @@ -0,0 +1,47 @@ +package main + +import ( + "git.annabunches.net/annabunches/joyful/internal/configparser" + "git.annabunches.net/annabunches/joyful/internal/logger" + "github.com/holoplot/go-evdev" +) + +func initPhysicalDevices(conf *configparser.Config) map[string]*evdev.InputDevice { + pDeviceMap := make(map[string]*evdev.InputDevice) + + for _, devConfig := range conf.Devices { + if devConfig.Type != configparser.DeviceTypePhysical { + continue + } + + name, device, err := initPhysicalDevice(devConfig.Config.(configparser.DeviceConfigPhysical)) + if err != nil { + logger.LogError(err, "Failed to initialize device") + } + pDeviceMap[name] = device + } + + if len(pDeviceMap) == 0 { + logger.Log("Warning: no physical devices found in configuration. No rules will work.") + } + return pDeviceMap +} + +func initPhysicalDevice(config configparser.DeviceConfigPhysical) (string, *evdev.InputDevice, error) { + name := config.Name + var device *evdev.InputDevice + var err error + + if config.DevicePath != "" { + device, err = evdev.Open(config.DevicePath) + } else { + device, err = evdev.OpenByName(config.DeviceName) + } + + if config.Lock && err == nil { + grabErr := device.Grab() + logger.LogIfError(grabErr, "Failed to lock device for exclusive access") + } + + return name, device, err +} diff --git a/cmd/joyful/main.go b/cmd/joyful/main.go index f6cf6de..8a0ab15 100644 --- a/cmd/joyful/main.go +++ b/cmd/joyful/main.go @@ -10,7 +10,7 @@ import ( "github.com/holoplot/go-evdev" flag "github.com/spf13/pflag" - "git.annabunches.net/annabunches/joyful/internal/config" + "git.annabunches.net/annabunches/joyful/internal/configparser" "git.annabunches.net/annabunches/joyful/internal/logger" "git.annabunches.net/annabunches/joyful/internal/mappingrules" "git.annabunches.net/annabunches/joyful/internal/virtualdevice" @@ -21,14 +21,7 @@ func getConfigDir(dir string) string { return os.ExpandEnv(configDir) } -func readConfig(configDir string) *config.ConfigParser { - parser := &config.ConfigParser{} - err := parser.Parse(configDir) - logger.FatalIfError(err, "Failed to parse config") - return parser -} - -func initVirtualBuffers(config *config.ConfigParser) (map[string]*evdev.InputDevice, +func initVirtualBuffers(config *configparser.ConfigParser) (map[string]*evdev.InputDevice, map[string]*virtualdevice.EventBuffer, map[*evdev.InputDevice]*virtualdevice.EventBuffer) { @@ -46,14 +39,6 @@ func initVirtualBuffers(config *config.ConfigParser) (map[string]*evdev.InputDev return vDevices, vBuffersByName, vBuffersByDevice } -func initPhysicalDevices(config *config.ConfigParser) map[string]*evdev.InputDevice { - pDeviceMap := config.InitPhysicalDevices() - if len(pDeviceMap) == 0 { - logger.Log("Warning: no physical devices found in configuration. No rules will work.") - } - return pDeviceMap -} - func main() { // parse command-line var configFlag string @@ -64,7 +49,8 @@ func main() { // parse configs configDir := getConfigDir(configFlag) - config := readConfig(configDir) + config, err := configparser.ParseConfig(configDir) + logger.FatalIfError(err, "Failed to parse configuration") // initialize TTS tts, err := newTTS(ttsOps) @@ -144,7 +130,7 @@ func main() { } func loadRules( - config *config.ConfigParser, + config *configparser.ConfigParser, pDevices map[string]*evdev.InputDevice, vDevices map[string]*evdev.InputDevice) ([]mappingrules.MappingRule, <-chan ChannelEvent, func(), *sync.WaitGroup) { diff --git a/internal/config/codes.go b/internal/configparser/codes.go similarity index 98% rename from internal/config/codes.go rename to internal/configparser/codes.go index c879feb..994b2b7 100644 --- a/internal/config/codes.go +++ b/internal/configparser/codes.go @@ -1,4 +1,4 @@ -package config +package configparser import ( "fmt" diff --git a/internal/config/codes_test.go b/internal/configparser/codes_test.go similarity index 99% rename from internal/config/codes_test.go rename to internal/configparser/codes_test.go index 6e80291..107ec24 100644 --- a/internal/config/codes_test.go +++ b/internal/configparser/codes_test.go @@ -1,4 +1,4 @@ -package config +package configparser import ( "fmt" diff --git a/internal/config/configparser.go b/internal/configparser/configparser.go similarity index 59% rename from internal/config/configparser.go rename to internal/configparser/configparser.go index 564c00d..864551e 100644 --- a/internal/config/configparser.go +++ b/internal/configparser/configparser.go @@ -10,7 +10,7 @@ // // nb: there are methods defined on ConfigParser in other files in this package! -package config +package configparser import ( "errors" @@ -75,3 +75,59 @@ func (parser *ConfigParser) GetModes() []string { } return parser.config.Modes } + +func ParseConfig(directory string) (*Config, error) { + config := new(Config) + + configFiles, err := getConfigFilePaths(directory) + if err != nil { + return nil, err + } + + // Open each yaml file and add its contents to the global config + for _, filePath := range configFiles { + data, err := os.ReadFile(filePath) + if err != nil { + logger.LogError(err, "Error while opening config file") + continue + } + + newConfig := Config{} + err = yaml.Unmarshal(data, &newConfig) + logger.LogIfError(err, "Error parsing YAML") + config.Rules = append(config.Rules, newConfig.Rules...) + config.Devices = append(config.Devices, newConfig.Devices...) + config.Modes = append(config.Modes, newConfig.Modes...) + } + + if len(config.Devices) == 0 { + return nil, errors.New("Found no devices in configuration. Please add configuration at " + directory) + } + + return config, nil +} + +func getConfigFilePaths(directory string) ([]string, error) { + paths := make([]string, 0) + + dirEntries, err := os.ReadDir(directory) + if err != nil { + err = os.Mkdir(directory, 0755) + if err != nil { + return nil, errors.New("failed to create config directory at " + directory) + } else { + return nil, errors.New("no config files found at " + directory) + } + } + + for _, file := range dirEntries { + name := strings.ToLower(file.Name()) + if file.IsDir() || !(strings.HasSuffix(name, ".yaml") || strings.HasSuffix(name, ".yml")) { + continue + } + + paths = append(paths, filepath.Join(directory, file.Name())) + } + + return paths, nil +} diff --git a/internal/config/devices.go b/internal/configparser/devices.go similarity index 99% rename from internal/config/devices.go rename to internal/configparser/devices.go index d933ed7..bb60532 100644 --- a/internal/config/devices.go +++ b/internal/configparser/devices.go @@ -1,4 +1,4 @@ -package config +package configparser import ( "fmt" diff --git a/internal/config/devices_test.go b/internal/configparser/devices_test.go similarity index 99% rename from internal/config/devices_test.go rename to internal/configparser/devices_test.go index ad3b624..509a606 100644 --- a/internal/config/devices_test.go +++ b/internal/configparser/devices_test.go @@ -1,4 +1,4 @@ -package config +package configparser import ( "testing" diff --git a/internal/config/interfaces.go b/internal/configparser/interfaces.go similarity index 84% rename from internal/config/interfaces.go rename to internal/configparser/interfaces.go index 0b9fa42..9ebe1b1 100644 --- a/internal/config/interfaces.go +++ b/internal/configparser/interfaces.go @@ -1,4 +1,4 @@ -package config +package configparser import "github.com/holoplot/go-evdev" diff --git a/internal/config/make_rule_targets.go b/internal/configparser/make_rule_targets.go similarity index 99% rename from internal/config/make_rule_targets.go rename to internal/configparser/make_rule_targets.go index 203a015..4ae2fc6 100644 --- a/internal/config/make_rule_targets.go +++ b/internal/configparser/make_rule_targets.go @@ -1,4 +1,4 @@ -package config +package configparser import ( "errors" diff --git a/internal/config/make_rule_targets_test.go b/internal/configparser/make_rule_targets_test.go similarity index 99% rename from internal/config/make_rule_targets_test.go rename to internal/configparser/make_rule_targets_test.go index 7ee8fb8..30fa4ae 100644 --- a/internal/config/make_rule_targets_test.go +++ b/internal/configparser/make_rule_targets_test.go @@ -1,4 +1,4 @@ -package config +package configparser import ( "fmt" diff --git a/internal/config/make_rules.go b/internal/configparser/make_rules.go similarity index 99% rename from internal/config/make_rules.go rename to internal/configparser/make_rules.go index 9baf9d7..9434de2 100644 --- a/internal/config/make_rules.go +++ b/internal/configparser/make_rules.go @@ -1,4 +1,4 @@ -package config +package configparser import ( "fmt" diff --git a/internal/config/modes.go b/internal/configparser/modes.go similarity index 94% rename from internal/config/modes.go rename to internal/configparser/modes.go index ad3dee2..4888be0 100644 --- a/internal/config/modes.go +++ b/internal/configparser/modes.go @@ -1,4 +1,4 @@ -package config +package configparser import "slices" diff --git a/internal/config/schema.go b/internal/configparser/schema.go similarity index 99% rename from internal/config/schema.go rename to internal/configparser/schema.go index ad91f28..8b70521 100644 --- a/internal/config/schema.go +++ b/internal/configparser/schema.go @@ -1,7 +1,7 @@ // These types comprise the YAML schema for configuring Joyful. // The config files will be combined and then unmarshalled into this -package config +package configparser import ( "fmt" diff --git a/internal/config/variables.go b/internal/configparser/variables.go similarity index 99% rename from internal/config/variables.go rename to internal/configparser/variables.go index 6e62977..2bcc9d0 100644 --- a/internal/config/variables.go +++ b/internal/configparser/variables.go @@ -1,4 +1,4 @@ -package config +package configparser import ( "github.com/holoplot/go-evdev"