1
0
Fork 0
eighty/status_resp.go

264 lines
9.4 KiB
Go

package eighty
import (
"amuz.es/src/go/misc"
"github.com/valyala/fasthttp"
"log"
)
type (
// HandledError is a http status handler type
HandledError int
// PageRenderer is a function interface type for the http status page renderer.
PageRenderer = func(r *fasthttp.RequestCtx, name string, context map[string]any) error
)
var (
// Is the interface compatible with the actual dto
_ error = (*HandledError)(nil)
)
// Collection of predefined HandledError.
const (
// HandledErrorBadRequest : 400, BadRequest http status
HandledErrorBadRequest HandledError = 400
// HandledErrorUnauthorized : 401, Unauthorized http status
HandledErrorUnauthorized HandledError = 401
// HandledErrorForbidden : 403, Forbidden http status
HandledErrorForbidden HandledError = 403
// HandledErrorNotFound : 404, NotFound http status
HandledErrorNotFound HandledError = 404
// HandledErrorMethodNotAllowed : 405, MethodNotAllowed http status
HandledErrorMethodNotAllowed HandledError = 405
// HandledErrorNotAcceptable : 406, NotAcceptable http status
HandledErrorNotAcceptable HandledError = 406
// HandledErrorRequestTimeout : 408, RequestTimeout http status
HandledErrorRequestTimeout HandledError = 408
// HandledErrorGone : 410, Gone http status
HandledErrorGone HandledError = 410
// HandledErrorTooManyRequests : 429, TooManyRequests http status
HandledErrorTooManyRequests HandledError = 429
// HandledErrorInternalServerError : 500, InternalServerError http status
HandledErrorInternalServerError HandledError = 500
// HandledErrorNotImplemented : 501, NotImplemented http status
HandledErrorNotImplemented HandledError = 501
// HandledErrorBadGateway : 502, BadGateway http status
HandledErrorBadGateway HandledError = 502
// HandledErrorServiceUnavailable : 503, ServiceUnavailable http status
HandledErrorServiceUnavailable HandledError = 503
// HandledErrorGatewayTimeout : 504, GatewayTimeout http status
HandledErrorGatewayTimeout HandledError = 504
)
// HandledErrorCodeOf is the conversion function with the http status code to HandledError.
func HandledErrorCodeOf(value int) (HandledError, bool) {
switch value {
case int(HandledErrorBadRequest):
return HandledErrorBadRequest, true
case int(HandledErrorUnauthorized):
return HandledErrorUnauthorized, true
case int(HandledErrorForbidden):
return HandledErrorForbidden, true
case int(HandledErrorNotFound):
return HandledErrorNotFound, true
case int(HandledErrorMethodNotAllowed):
return HandledErrorMethodNotAllowed, true
case int(HandledErrorNotAcceptable):
return HandledErrorNotAcceptable, true
case int(HandledErrorGone):
return HandledErrorGone, true
case int(HandledErrorNotImplemented):
return HandledErrorNotImplemented, true
case int(HandledErrorBadGateway):
return HandledErrorBadGateway, true
case int(HandledErrorServiceUnavailable):
return HandledErrorServiceUnavailable, true
case int(HandledErrorGatewayTimeout):
return HandledErrorGatewayTimeout, true
case int(HandledErrorInternalServerError):
return HandledErrorInternalServerError, true
default:
return HandledErrorInternalServerError, false
}
}
// HandledErrorOf is the conversion function with the generic error object to HandledError.
func HandledErrorOf(value any) (HandledError, bool) {
switch value {
case HandledErrorBadRequest:
return HandledErrorBadRequest, true
case HandledErrorUnauthorized:
return HandledErrorUnauthorized, true
case HandledErrorForbidden:
return HandledErrorForbidden, true
case HandledErrorNotFound:
return HandledErrorNotFound, true
case HandledErrorMethodNotAllowed:
return HandledErrorMethodNotAllowed, true
case HandledErrorNotAcceptable:
return HandledErrorNotAcceptable, true
case HandledErrorRequestTimeout:
return HandledErrorRequestTimeout, true
case HandledErrorGone:
return HandledErrorGone, true
case HandledErrorTooManyRequests:
return HandledErrorTooManyRequests, true
case HandledErrorNotImplemented:
return HandledErrorNotImplemented, true
case HandledErrorBadGateway:
return HandledErrorBadGateway, true
case HandledErrorServiceUnavailable:
return HandledErrorServiceUnavailable, true
case HandledErrorGatewayTimeout:
return HandledErrorGatewayTimeout, true
case HandledErrorInternalServerError:
return HandledErrorInternalServerError, true
default:
return HandledErrorInternalServerError, false
}
}
// StatusCode returns the http status code.
func (handler HandledError) StatusCode() int {
return int(handler)
}
// StatusMessage returns the http status message.
func (handler HandledError) StatusMessage() (msg string) {
switch handler {
case HandledErrorBadRequest:
msg = "Bad Request"
case HandledErrorUnauthorized:
msg = "Unauthorized"
case HandledErrorForbidden:
msg = "Forbidden"
case HandledErrorNotFound:
msg = "Not Found"
case HandledErrorMethodNotAllowed:
msg = "Method Not Allowed"
case HandledErrorNotAcceptable:
msg = "Not Acceptable"
case HandledErrorRequestTimeout:
msg = "Request Timeout"
case HandledErrorGone:
msg = "Gone"
case HandledErrorTooManyRequests:
msg = "Too Many Requests"
case HandledErrorNotImplemented:
msg = "Not Implemented"
case HandledErrorBadGateway:
msg = "Bad Gateway"
case HandledErrorServiceUnavailable:
msg = "Service Unavailable"
case HandledErrorGatewayTimeout:
msg = "Gateway Timeout"
case HandledErrorInternalServerError:
fallthrough
default:
msg = "Internal Server Error"
}
return
}
// StatusDescription returns the http status description.
func (handler HandledError) StatusDescription() (msg string) {
switch handler {
case HandledErrorBadRequest:
msg = "The request could not be understood by the server due to malformed syntax."
case HandledErrorUnauthorized:
msg = "The request requires user authentication."
case HandledErrorForbidden:
msg = "The server understood the request, but is refusing to fulfill it."
case HandledErrorNotFound:
msg = "The server has not found anything matching the Request-URI."
case HandledErrorMethodNotAllowed:
msg = "The method specified in the Request-Line is not allowed for the resource identified by the Request-URI."
case HandledErrorNotAcceptable:
msg = "The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request."
case HandledErrorRequestTimeout:
msg = "The client did not produce a request within the time that the server was prepared to wait."
case HandledErrorGone:
msg = "The requested resource is no longer available at the server and no forwarding address is known."
case HandledErrorTooManyRequests:
msg = "The client has sent too many requests in a given amount of time."
case HandledErrorNotImplemented:
msg = "The server does not support the functionality required to fulfill the request."
case HandledErrorBadGateway:
msg = "The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request."
case HandledErrorServiceUnavailable:
msg = "The server is currently unable to handle the request due to a temporary overloading or maintenance of the server."
case HandledErrorGatewayTimeout:
msg = "The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI."
case HandledErrorInternalServerError:
fallthrough
default:
msg = "The server encountered an unexpected condition which prevented it from fulfilling the request."
}
return
}
// RenderPage is a html page renderer function, that follows the http status code with context.
func (handler HandledError) RenderPage(ctx *fasthttp.RequestCtx, templateRenderer PageRenderer, err error) {
defer func() {
if len(ctx.Response.Header.ContentType()) == 0 {
ctx.SetContentType(HtmlContentUTF8Type[0])
}
ctx.SetStatusCode(handler.StatusCode())
}()
tmplCtx := map[string]any{
"title": handler.StatusMessage(),
"description": handler.StatusDescription(),
"nofollow": true,
}
if err != nil {
tmplCtx["message"] = err.Error()
}
if err := templateRenderer(ctx, "error", tmplCtx); err != nil {
log.Print("cannot render error page: ", err)
}
return
}
// RenderAPI is a json renderer function, that follows the http status code with context.
func (handler HandledError) RenderAPI(ctx *fasthttp.RequestCtx, _ error) {
defer func() {
if len(ctx.Response.Header.ContentType()) == 0 {
ctx.SetContentType(JsonContentType[0])
}
ctx.SetStatusCode(handler.StatusCode())
}()
stream := misc.JSONCodec.BorrowStream(ctx)
defer misc.JSONCodec.ReturnStream(stream)
stream.WriteObjectStart()
stream.WriteObjectField("code")
stream.WriteInt(handler.StatusCode())
stream.WriteMore()
stream.WriteObjectField("message")
stream.WriteString(handler.StatusMessage())
stream.WriteObjectEnd()
_ = stream.Flush()
return
}
// Error implements the built-in interface type error.
func (handler HandledError) Error() string {
return handler.StatusMessage()
}
// WrapHandledError is the panic handler function with a thrown panic object.
func WrapHandledError(panicObj any) (handler HandledError, err error) {
var panicObjIsErr bool
if err, panicObjIsErr = panicObj.(error); panicObjIsErr {
var errIsDefined bool
if handler, errIsDefined = HandledErrorOf(err); errIsDefined {
err = nil
}
} else {
log.Printf("panic object(%v) isn't error interface", panicObj)
handler = HandledErrorInternalServerError
}
return
}