Files
upscayl-server/utils/error.go
2026-05-21 12:51:16 +08:00

121 lines
2.4 KiB
Go

package utils
import (
"fmt"
"net/http"
"runtime/debug"
"github.com/go-chi/chi/v5/middleware"
)
type recoverErr struct {
Error string `json:"error"`
Msg string `json:"msg"`
Code int `json:"code"`
}
func (e recoverErr) Json() string {
return fmt.Sprintf(`{"error":"%s","msg":"%s","code":%d}`, e.Msg, e.Error, e.Code)
}
// Close will panic anyway.
// Recoverer will catch the panic and return the error.
func Close(msg string, err any, status int) {
switch v := err.(type) {
case string:
panic(recoverErr{
Error: v,
Msg: msg,
Code: status,
})
case error:
panic(recoverErr{
Error: v.Error(),
Msg: msg,
Code: status,
})
default:
panic(recoverErr{
Error: fmt.Sprint(err),
Msg: msg,
Code: status,
})
}
}
// CloseIf will panic if hasErr is true.
// Recoverer will catch the panic and return the error.
func CloseIf(hasErr bool, msg string, err any, status int) {
if hasErr {
switch v := err.(type) {
case string:
panic(recoverErr{
Error: v,
Msg: msg,
Code: status,
})
case error:
panic(recoverErr{
Error: v.Error(),
Msg: msg,
Code: status,
})
default:
panic(recoverErr{
Error: fmt.Sprint(err),
Msg: msg,
Code: status,
})
}
}
}
// CloseIfErr will panic if err is not nil.
// Recoverer will catch the panic and return the error.
func CloseIfErr(err error, msg string, status int) {
if err != nil {
panic(recoverErr{
Error: err.Error(),
Msg: msg,
Code: status,
})
}
}
// Recoverer edited from https://github.com/go-chi/chi/blob/master/middleware/recoverer.go
func Recoverer(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rvr := recover(); rvr != nil {
if rvr == http.ErrAbortHandler {
// we don't recover http.ErrAbortHandler so the response
// to the client is aborted, this should not be logged
panic(rvr)
}
if errs, ok := rvr.(recoverErr); ok {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(errs.Code)
Json(w, errs)
return
}
logEntry := middleware.GetLogEntry(r)
if logEntry != nil {
logEntry.Panic(rvr, debug.Stack())
} else {
middleware.PrintPrettyStack(rvr)
}
if r.Header.Get("Connection") != "Upgrade" {
w.WriteHeader(http.StatusInternalServerError)
}
}
}()
next.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}