Always make fatal errors json-serializable (#14396)

This commit is contained in:
andig 2024-06-16 16:58:31 +02:00 • committed by GitHub
parent a8f95ef6d0
commit 4d6109d3ab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 39 additions and 16 deletions

View file

@ -28,6 +28,27 @@ const (
ClassSponsorship
)
// FatalError is an error that can be marshaled
type FatalError struct {
err error
}
func (e *FatalError) Error() string {
return e.err.Error()
}
func (e FatalError) MarshalJSON() ([]byte, error) {
if je, ok := e.err.(json.Marshaler); ok {
return je.MarshalJSON()
}
return json.Marshal(struct {
Error string `json:"error"`
}{
Error: e.err.Error(),
})
}
// DeviceError indicates the specific device that failed
type DeviceError struct {
Name string

View file

@ -75,23 +75,25 @@ func shutdownDoneC() <-chan struct{} {
return doneC
}
func wrapError(err error) error {
if err != nil {
var opErr *net.OpError
var pathErr *os.PathError
func wrapFatalError(err error) error {
if err == nil {
return nil
}
switch {
case errors.As(err, &opErr):
if opErr.Op == "listen" && strings.Contains(opErr.Error(), "address already in use") {
err = fmt.Errorf("could not open port- check that evcc is not already running (%w)", err)
}
var opErr *net.OpError
var pathErr *os.PathError
case errors.As(err, &pathErr):
if pathErr.Op == "remove" && strings.Contains(pathErr.Error(), "operation not permitted") {
err = fmt.Errorf("could not remove file- check that evcc is not already running (%w)", err)
}
switch {
case errors.As(err, &opErr):
if opErr.Op == "listen" && strings.Contains(opErr.Error(), "address already in use") {
err = fmt.Errorf("could not open port- check that evcc is not already running (%w)", err)
}
case errors.As(err, &pathErr):
if pathErr.Op == "remove" && strings.Contains(pathErr.Error(), "operation not permitted") {
err = fmt.Errorf("could not remove file- check that evcc is not already running (%w)", err)
}
}
return err
return &FatalError{err}
}

View file

@ -291,7 +291,7 @@ func runRoot(cmd *cobra.Command, args []string) {
if err != nil {
// improve error message
err = wrapError(err)
err = wrapFatalError(err)
valueChan <- util.Param{Key: keys.Fatal, Val: err}
// TODO stop reboot loop if user updates config (or show countdown in UI)
@ -307,5 +307,5 @@ func runRoot(cmd *cobra.Command, args []string) {
// uds health check listener
go server.HealthListener(site)
log.FATAL.Println(wrapError(httpd.ListenAndServe()))
log.FATAL.Println(wrapFatalError(httpd.ListenAndServe()))
}