Unify error handling and HTTP statuses

Signed-off-by: Sean Du <do4suki@gmail.com>
This commit is contained in:
2026-07-11 16:18:17 +08:00
parent 61b33ae0e3
commit cb8f587e30
113 changed files with 408 additions and 166 deletions
+89 -1
View File
@@ -1,6 +1,15 @@
package honokautils
import "errors"
import (
"errors"
"fmt"
"net/http"
"reflect"
"strconv"
"strings"
"github.com/gin-gonic/gin"
)
type UnimplementedError struct {
Kind string
@@ -35,3 +44,82 @@ func IsUnimplementedError(err error) bool {
var target *UnimplementedError
return err != nil && errors.As(err, &target)
}
const maintenanceHeader = "Maintenance"
type ErrorContent struct {
Detail string `json:"detail,omitempty"`
Exception string `json:"exception,omitempty"`
Message string `json:"message,omitempty"`
Traceback []string `json:"traceback,omitempty"`
}
func IsMainPHPRequest(path string) bool {
return path == "/main.php" || strings.HasPrefix(path, "/main.php/")
}
func WriteMaintenanceJSON(setHeader func(string, string), writeJSON func(int, any), status int, content any) {
setHeader("Content-Type", "application/json; charset=utf-8")
setHeader("status_code", strconv.Itoa(status))
setHeader(maintenanceHeader, "1")
writeJSON(status, content)
}
func AbortMaintenanceJSON(ctx *gin.Context, status int, content any) {
WriteMaintenanceJSON(ctx.Header, ctx.JSON, status, content)
ctx.Abort()
}
func NewDetailContent(detail string) ErrorContent {
return ErrorContent{
Detail: detail,
}
}
func NewNotFoundContent(path string) ErrorContent {
return NewDetailContent(fmt.Sprintf("Endpoint not found: %s", path))
}
func NewInternalErrorContent(err error) ErrorContent {
return ErrorContent{
Exception: exceptionName(err),
Message: err.Error(),
}
}
func NewErrorContent(exception, message string) ErrorContent {
return ErrorContent{
Exception: exception,
Message: message,
}
}
func NewPanicContent(recovered any, stack []byte) ErrorContent {
return ErrorContent{
Exception: "panic",
Message: fmt.Sprint(recovered),
Traceback: splitLines(stack),
}
}
func exceptionName(err error) string {
if err == nil {
return http.StatusText(http.StatusInternalServerError)
}
typ := reflect.TypeOf(err)
if typ.Kind() == reflect.Pointer {
typ = typ.Elem()
}
if name := typ.Name(); name != "" {
return name
}
return typ.String()
}
func splitLines(stack []byte) []string {
if len(stack) == 0 {
return nil
}
return strings.Split(strings.TrimSpace(string(stack)), "\n")
}