From 81bf9e86ece23c0082a8ce7075e31a8aad8ae553 Mon Sep 17 00:00:00 2001 From: Joshua Rich Date: Wed, 30 Oct 2024 15:50:23 +1000 Subject: [PATCH] perf: :zap: share a validator instance across packages --- internal/agent/ui/fyneUI/fyneUI.go | 19 +++----- internal/hass/event/event.go | 10 +++-- internal/hass/sensor/entities.go | 13 +++--- internal/hass/sensor/validation.go | 40 ----------------- internal/preferences/prefs.go | 6 ++- internal/preferences/registration.go | 6 ++- internal/preferences/validation.go | 45 ------------------- .../{hass/event => validation}/validation.go | 8 ++-- 8 files changed, 31 insertions(+), 116 deletions(-) delete mode 100644 internal/hass/sensor/validation.go delete mode 100644 internal/preferences/validation.go rename internal/{hass/event => validation}/validation.go (79%) diff --git a/internal/agent/ui/fyneUI/fyneUI.go b/internal/agent/ui/fyneUI/fyneUI.go index 8c44270d..118be606 100644 --- a/internal/agent/ui/fyneUI/fyneUI.go +++ b/internal/agent/ui/fyneUI/fyneUI.go @@ -27,7 +27,8 @@ import ( "fyne.io/fyne/v2/driver/desktop" "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/widget" - "github.com/go-playground/validator/v10" + + agentvalidator "github.com/joshuar/go-hass-agent/internal/validation" "github.com/joshuar/go-hass-agent/internal/agent/ui" "github.com/joshuar/go-hass-agent/internal/hass" @@ -35,8 +36,6 @@ import ( "github.com/joshuar/go-hass-agent/internal/preferences" ) -var validate *validator.Validate - var ( //nolint:stylecheck //lint:ignore ST1005 these are not standard error messages @@ -59,10 +58,6 @@ type FyneUI struct { logger *slog.Logger } -func init() { - validate = validator.New(validator.WithRequiredStructEnabled()) -} - // New FyneUI sets up the UI for the agent. func NewFyneUI(ctx context.Context) *FyneUI { appUI := &FyneUI{ @@ -546,10 +541,8 @@ func longestString(stringList []string) string { // httpValidator is a custom fyne validator that will validate a string is a // valid http/https URL. func httpValidator() fyne.StringValidator { - v := validator.New() - return func(text string) error { - if v.Var(text, "http_url") != nil { + if agentvalidator.Validate.Var(text, "http_url") != nil { return ErrInvalidURL } @@ -565,7 +558,7 @@ func httpValidator() fyne.StringValidator { // valid http/https URL. func uriValidator() fyne.StringValidator { return func(text string) error { - if validate.Var(text, "uri") != nil { + if agentvalidator.Validate.Var(text, "uri") != nil { return ErrInvalidURI } @@ -590,10 +583,8 @@ func hostPortValidator(msg string) fyne.StringValidator { errMsg = ErrInvalidHostPort } - v := validator.New() - return func(text string) error { - if v.Var(text, "hostname_port") != nil { + if agentvalidator.Validate.Var(text, "hostname_port") != nil { return errMsg } // if _, err := url.Parse(text); err != nil { diff --git a/internal/hass/event/event.go b/internal/hass/event/event.go index 7742267f..ac07471d 100644 --- a/internal/hass/event/event.go +++ b/internal/hass/event/event.go @@ -4,7 +4,11 @@ //revive:disable:unused-receiver package event -import "fmt" +import ( + "fmt" + + "github.com/joshuar/go-hass-agent/internal/validation" +) const ( requestTypeEvent = "fire_event" @@ -16,9 +20,9 @@ type Event struct { } func (e *Event) Validate() error { - err := validate.Struct(e) + err := validation.Validate.Struct(e) if err != nil { - return fmt.Errorf("event is invalid: %s", parseValidationErrors(err)) + return fmt.Errorf("event is invalid: %s", validation.ParseValidationErrors(err)) } return nil diff --git a/internal/hass/sensor/entities.go b/internal/hass/sensor/entities.go index f1aa6164..e0768268 100644 --- a/internal/hass/sensor/entities.go +++ b/internal/hass/sensor/entities.go @@ -9,6 +9,7 @@ import ( "fmt" "github.com/joshuar/go-hass-agent/internal/hass/sensor/types" + "github.com/joshuar/go-hass-agent/internal/validation" ) const ( @@ -33,9 +34,9 @@ type State struct { } func (s *State) Validate() error { - err := validate.Struct(s) + err := validation.Validate.Struct(s) if err != nil { - return fmt.Errorf("sensor state is invalid: %s", parseValidationErrors(err)) + return fmt.Errorf("sensor state is invalid: %s", validation.ParseValidationErrors(err)) } return nil @@ -75,9 +76,9 @@ type Entity struct { } func (e *Entity) Validate() error { - err := validate.Struct(e) + err := validation.Validate.Struct(e) if err != nil { - return fmt.Errorf("sensor is invalid: %s", parseValidationErrors(err)) + return fmt.Errorf("sensor is invalid: %s", validation.ParseValidationErrors(err)) } return nil @@ -132,9 +133,9 @@ type Location struct { } func (l *Location) Validate() error { - err := validate.Struct(l) + err := validation.Validate.Struct(l) if err != nil { - return fmt.Errorf("location is invalid: %s", parseValidationErrors(err)) + return fmt.Errorf("location is invalid: %s", validation.ParseValidationErrors(err)) } return nil diff --git a/internal/hass/sensor/validation.go b/internal/hass/sensor/validation.go deleted file mode 100644 index 7c08bdac..00000000 --- a/internal/hass/sensor/validation.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2024 Joshua Rich . -// SPDX-License-Identifier: MIT - -package sensor - -import ( - "strings" - - "github.com/go-playground/validator/v10" -) - -var validate *validator.Validate - -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("field " + err.Field() + " is required") - default: - message.WriteString("field " + err.Field() + " should match " + err.Tag()) - } - - message.WriteRune(' ') - } - - return message.String() -} diff --git a/internal/preferences/prefs.go b/internal/preferences/prefs.go index 41df0be8..e9dd2c64 100644 --- a/internal/preferences/prefs.go +++ b/internal/preferences/prefs.go @@ -14,6 +14,8 @@ import ( "github.com/adrg/xdg" "github.com/pelletier/go-toml/v2" + + "github.com/joshuar/go-hass-agent/internal/validation" ) const ( @@ -122,9 +124,9 @@ func DefaultPreferences(file string) *Preferences { } func (p *Preferences) Validate() error { - err := validate.Struct(p) + err := validation.Validate.Struct(p) if err != nil { - return fmt.Errorf("%w: %s", ErrValidationFailed, parseValidationErrors(err)) + return fmt.Errorf("validation failed: %s", validation.ParseValidationErrors(err)) } return nil diff --git a/internal/preferences/registration.go b/internal/preferences/registration.go index 2a797421..b3716ca0 100644 --- a/internal/preferences/registration.go +++ b/internal/preferences/registration.go @@ -7,6 +7,8 @@ package preferences import ( "fmt" + + "github.com/joshuar/go-hass-agent/internal/validation" ) type Registration struct { @@ -23,9 +25,9 @@ func DefaultRegistrationPreferences() *Registration { } func (p *Registration) Validate() error { - err := validate.Struct(p) + err := validation.Validate.Struct(p) if err != nil { - return fmt.Errorf("%w: %s", ErrValidationFailed, parseValidationErrors(err)) + return fmt.Errorf("validation failed: %s", validation.ParseValidationErrors(err)) } return nil diff --git a/internal/preferences/validation.go b/internal/preferences/validation.go deleted file mode 100644 index 90c0697a..00000000 --- a/internal/preferences/validation.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2024 Joshua Rich -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -package preferences - -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() -} diff --git a/internal/hass/event/validation.go b/internal/validation/validation.go similarity index 79% rename from internal/hass/event/validation.go rename to internal/validation/validation.go index 0ac72430..42281037 100644 --- a/internal/hass/event/validation.go +++ b/internal/validation/validation.go @@ -1,7 +1,7 @@ // Copyright 2024 Joshua Rich . // SPDX-License-Identifier: MIT -package event +package validation import ( "strings" @@ -9,15 +9,15 @@ import ( "github.com/go-playground/validator/v10" ) -var validate *validator.Validate +var Validate *validator.Validate func init() { - validate = validator.New(validator.WithRequiredStructEnabled()) + Validate = validator.New(validator.WithRequiredStructEnabled()) } //nolint:errorlint //revive:disable:unhandled-error -func parseValidationErrors(validation error) string { +func ParseValidationErrors(validation error) string { validationErrs, ok := validation.(validator.ValidationErrors) if !ok { return "internal validation error"