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) }