Skip to content

Commit

Permalink
feat(preferences): ✨ add support for setting MQTT preferences via the…
Browse files Browse the repository at this point in the history
… command-line
  • Loading branch information
joshuar committed Sep 2, 2024
1 parent a0c6b8d commit b49d0db
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 5 deletions.
57 changes: 57 additions & 0 deletions internal/cli/configCmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) 2024 Joshua Rich <joshua.rich@gmail.com>
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT

package cli

import (
"errors"
"fmt"
"path/filepath"

"github.com/adrg/xdg"

"github.com/joshuar/go-hass-agent/internal/preferences"
)

var ErrMQTTServerRequired = errors.New("mqtt-server not specified")

type ConfigCmd struct {
Path string `kong:"hidden"`
MQTTConfig `kong:"help='Set MQTT options.'"`
}

type MQTTConfig preferences.MQTT

func (r *ConfigCmd) Run(ctx *Context) error {
r.Path = filepath.Join(xdg.ConfigHome, ctx.AppID)

prefs, err := preferences.Load(r.Path)
if err != nil {
return fmt.Errorf("config: load preferences: %w", err)
}

r.MQTTEnabled = true
prefs.MQTT = (*preferences.MQTT)(&r.MQTTConfig)

err = prefs.Save()
if err != nil {
return fmt.Errorf("config: save preferences: %w", err)
}

return nil
}

func (r *MQTTConfig) Validate() error {
err := validate.Struct(r)
if err != nil {
return fmt.Errorf("%w: %s", ErrValidationFailed, parseValidationErrors(err))
}

if r.MQTTServer == "" {
return ErrMQTTServerRequired
}

return nil
}
45 changes: 45 additions & 0 deletions internal/cli/validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2024 Joshua Rich <joshua.rich@gmail.com>
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT

package cli

import (
"errors"
"strings"

"github.com/go-playground/validator/v10"
)

var validate *validator.Validate

var ErrValidationFailed = errors.New("validation failed")

func init() {
validate = validator.New(validator.WithRequiredStructEnabled())
}

//nolint:errorlint
//revive:disable:unhandled-error
func parseValidationErrors(validation error) string {
validationErrs, ok := validation.(validator.ValidationErrors)
if !ok {
return "internal validation error"
}

var message strings.Builder

for _, err := range validationErrs {
switch err.Tag() {
case "required":
message.WriteString(err.Field() + " is required")
default:
message.WriteString(err.Field() + " should match " + err.Tag())
}

message.WriteRune(' ')
}

return message.String()
}
10 changes: 5 additions & 5 deletions internal/preferences/prefs.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ type Preferences struct {
}

type MQTT struct {
MQTTServer string `toml:"server,omitempty" validate:"omitempty,uri"`
MQTTUser string `toml:"user,omitempty" validate:"omitempty"`
MQTTPassword string `toml:"password,omitempty" validate:"omitempty"`
MQTTTopicPrefix string `toml:"topic_prefix,omitempty" validate:"omitempty,ascii"`
MQTTEnabled bool `toml:"enabled" validate:"boolean"`
MQTTServer string `toml:"server,omitempty" validate:"omitempty,uri" kong:"required,help='MQTT server URI. Required.',placeholder='scheme://some.host:port'"` //nolint:lll
MQTTUser string `toml:"user,omitempty" validate:"omitempty" kong:"optional,help='MQTT username.'"`
MQTTPassword string `toml:"password,omitempty" validate:"omitempty" kong:"optional,help='MQTT password.'"`
MQTTTopicPrefix string `toml:"topic_prefix,omitempty" validate:"omitempty,ascii" kong:"optional,help='MQTT topic prefix.'"`
MQTTEnabled bool `toml:"enabled" validate:"boolean" kong:"-"`
}

func (p *Preferences) Validate() error {
Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var CLI struct {
Profile cli.ProfileFlags `help:"Enable profiling."`
AppID string `name:"appid" default:"${defaultAppID}" help:"Specify a custom app id (for debugging)."`
LogLevel string `name:"log-level" enum:"info,debug,trace" default:"info" help:"Set logging level."`
Config cli.ConfigCmd `cmd:"" help:"Configure Go Hass Agent."`
Register cli.RegisterCmd `cmd:"" help:"Register with Home Assistant."`
NoLogFile bool `help:"Don't write to a log file."`
Headless bool `name:"terminal" help:"Run without a GUI."`
Expand Down

0 comments on commit b49d0db

Please sign in to comment.