fix(go.sum): update ResolveSpec dependency to v1.0.87
This commit is contained in:
+377
@@ -0,0 +1,377 @@
|
||||
package bunrouter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type routeCtxKey struct{}
|
||||
|
||||
// ParamsFromContext retrieves route parameters from the given context.
|
||||
// It returns an empty Params if no parameters are found.
|
||||
func ParamsFromContext(ctx context.Context) Params {
|
||||
if ctx == nil {
|
||||
return Params{}
|
||||
}
|
||||
route, _ := ctx.Value(routeCtxKey{}).(Params)
|
||||
return route
|
||||
}
|
||||
|
||||
// contextWithParams stores route parameters in the context.
|
||||
func contextWithParams(ctx context.Context, params Params) context.Context {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
return context.WithValue(ctx, routeCtxKey{}, params)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// HTTPHandler converts http.Handler to bunrouter.HandlerFunc.
|
||||
func HTTPHandler(handler http.Handler) HandlerFunc {
|
||||
if handler == nil {
|
||||
panic("bunrouter: nil handler")
|
||||
}
|
||||
return HTTPHandlerFunc(handler.ServeHTTP)
|
||||
}
|
||||
|
||||
// HTTPHandlerFunc converts http.HandlerFunc to bunrouter.HandlerFunc.
|
||||
func HTTPHandlerFunc(handler http.HandlerFunc) HandlerFunc {
|
||||
if handler == nil {
|
||||
panic("bunrouter: nil handler")
|
||||
}
|
||||
|
||||
return func(w http.ResponseWriter, req Request) (err error) {
|
||||
if w == nil {
|
||||
return fmt.Errorf("bunrouter: nil response writer")
|
||||
}
|
||||
|
||||
ctx := contextWithParams(req.Context(), req.params)
|
||||
|
||||
defer func() {
|
||||
if v := recover(); v != nil {
|
||||
var ok bool
|
||||
err, ok = v.(error)
|
||||
if !ok {
|
||||
err = fmt.Errorf("bunrouter: panic recovered: %v", v)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
handler.ServeHTTP(w, req.Request.WithContext(ctx))
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// HandlerFunc is a function that handles HTTP requests in bunrouter.
|
||||
// It returns an error that will be handled by the router.
|
||||
type HandlerFunc func(w http.ResponseWriter, req Request) error
|
||||
|
||||
var _ http.Handler = (*HandlerFunc)(nil)
|
||||
|
||||
func (h HandlerFunc) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
if h == nil {
|
||||
http.Error(w, "Handler not found", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if req == nil {
|
||||
http.Error(w, "Invalid request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h(w, NewRequest(req)); err != nil {
|
||||
code := http.StatusInternalServerError
|
||||
if httpErr, ok := err.(HTTPError); ok {
|
||||
code = httpErr.StatusCode()
|
||||
}
|
||||
http.Error(w, err.Error(), code)
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPError represents an HTTP error with a status code
|
||||
type HTTPError interface {
|
||||
error
|
||||
StatusCode() int
|
||||
}
|
||||
|
||||
// MiddlewareFunc is a function that wraps a HandlerFunc to provide middleware functionality.
|
||||
type MiddlewareFunc func(next HandlerFunc) HandlerFunc
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Request extends http.Request with route parameters.
|
||||
type Request struct {
|
||||
*http.Request
|
||||
params Params
|
||||
}
|
||||
|
||||
// NewRequest creates a new Request instance from an http.Request.
|
||||
func NewRequest(req *http.Request) Request {
|
||||
if req == nil {
|
||||
req = &http.Request{}
|
||||
}
|
||||
return Request{
|
||||
Request: req,
|
||||
params: ParamsFromContext(req.Context()),
|
||||
}
|
||||
}
|
||||
|
||||
func newRequestParams(req *http.Request, params Params) Request {
|
||||
if req == nil {
|
||||
req = &http.Request{}
|
||||
}
|
||||
return Request{
|
||||
Request: req,
|
||||
params: params,
|
||||
}
|
||||
}
|
||||
|
||||
// WithContext returns a new Request with the provided context.
|
||||
func (req Request) WithContext(ctx context.Context) Request {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
return Request{
|
||||
Request: req.Request.WithContext(ctx),
|
||||
params: req.params,
|
||||
}
|
||||
}
|
||||
|
||||
// Params returns the route parameters associated with the request.
|
||||
func (req Request) Params() Params {
|
||||
return req.params
|
||||
}
|
||||
|
||||
// Param returns the value of the named parameter or empty string if not found.
|
||||
func (req Request) Param(key string) string {
|
||||
return req.Params().ByName(key)
|
||||
}
|
||||
|
||||
// Route returns the matched route pattern.
|
||||
func (req Request) Route() string {
|
||||
return req.Params().Route()
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Params holds route parameters and route information.
|
||||
type Params struct {
|
||||
path string
|
||||
node *node
|
||||
handler *routeHandler
|
||||
wildcardLen uint16
|
||||
}
|
||||
|
||||
// IsZero returns true if Params has no associated route node.
|
||||
func (ps Params) IsZero() bool {
|
||||
return ps.node == nil
|
||||
}
|
||||
|
||||
// Route returns the route pattern that matched the request.
|
||||
func (ps Params) Route() string {
|
||||
if ps.node != nil {
|
||||
return ps.node.route
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Get returns the value of the named parameter and whether it was found.
|
||||
func (ps Params) Get(name string) (string, bool) {
|
||||
if ps.node == nil || ps.handler == nil {
|
||||
return "", false
|
||||
}
|
||||
if i, ok := ps.handler.params[name]; ok {
|
||||
return ps.findParam(i)
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (ps *Params) findParam(paramIndex int) (string, bool) {
|
||||
if ps.node == nil || ps.handler == nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
path := ps.path
|
||||
pathLen := len(path)
|
||||
if pathLen == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
currNode := ps.node
|
||||
currParamIndex := len(ps.handler.params) - 1
|
||||
|
||||
if paramIndex < 0 || paramIndex > currParamIndex {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Wildcard can be only in the final node.
|
||||
if ps.node.isWC {
|
||||
if currParamIndex == paramIndex {
|
||||
if int(ps.wildcardLen) > pathLen {
|
||||
return "", false
|
||||
}
|
||||
pathLen -= int(ps.wildcardLen)
|
||||
return path[pathLen:], true
|
||||
}
|
||||
|
||||
currParamIndex--
|
||||
if int(ps.wildcardLen) > pathLen {
|
||||
return "", false
|
||||
}
|
||||
pathLen -= int(ps.wildcardLen)
|
||||
path = path[:pathLen]
|
||||
}
|
||||
|
||||
for currNode != nil {
|
||||
if currNode.part[0] != ':' { // static node
|
||||
partLen := len(currNode.part)
|
||||
if partLen > pathLen {
|
||||
return "", false
|
||||
}
|
||||
pathLen -= partLen
|
||||
path = path[:pathLen]
|
||||
currNode = currNode.parent
|
||||
continue
|
||||
}
|
||||
|
||||
i := strings.LastIndexByte(path, '/')
|
||||
if i == -1 {
|
||||
return "", false
|
||||
}
|
||||
pathLen = i + 1
|
||||
|
||||
if currParamIndex == paramIndex {
|
||||
return path[pathLen:], true
|
||||
}
|
||||
|
||||
currParamIndex--
|
||||
path = path[:pathLen]
|
||||
currNode = currNode.parent
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
// ByName returns the value of the named parameter or empty string if not found.
|
||||
func (ps Params) ByName(name string) string {
|
||||
s, _ := ps.Get(name)
|
||||
return s
|
||||
}
|
||||
|
||||
// Int parses the named parameter as an integer.
|
||||
func (ps Params) Int(name string) (int, error) {
|
||||
value := ps.ByName(name)
|
||||
if value == "" {
|
||||
return 0, fmt.Errorf("bunrouter: param '%s' not found", name)
|
||||
}
|
||||
return strconv.Atoi(value)
|
||||
}
|
||||
|
||||
// Uint32 parses the named parameter as an unsigned 32-bit integer.
|
||||
func (ps Params) Uint32(name string) (uint32, error) {
|
||||
value := ps.ByName(name)
|
||||
if value == "" {
|
||||
return 0, fmt.Errorf("bunrouter: param '%s' not found", name)
|
||||
}
|
||||
n, err := strconv.ParseUint(value, 10, 32)
|
||||
return uint32(n), err
|
||||
}
|
||||
|
||||
// Uint64 parses the named parameter as an unsigned 64-bit integer.
|
||||
func (ps Params) Uint64(name string) (uint64, error) {
|
||||
value := ps.ByName(name)
|
||||
if value == "" {
|
||||
return 0, fmt.Errorf("bunrouter: param '%s' not found", name)
|
||||
}
|
||||
return strconv.ParseUint(value, 10, 64)
|
||||
}
|
||||
|
||||
// Int32 parses the named parameter as a signed 32-bit integer.
|
||||
func (ps Params) Int32(name string) (int32, error) {
|
||||
value := ps.ByName(name)
|
||||
if value == "" {
|
||||
return 0, fmt.Errorf("bunrouter: param '%s' not found", name)
|
||||
}
|
||||
n, err := strconv.ParseInt(value, 10, 32)
|
||||
return int32(n), err
|
||||
}
|
||||
|
||||
// Int64 parses the named parameter as a signed 64-bit integer.
|
||||
func (ps Params) Int64(name string) (int64, error) {
|
||||
value := ps.ByName(name)
|
||||
if value == "" {
|
||||
return 0, fmt.Errorf("bunrouter: param '%s' not found", name)
|
||||
}
|
||||
return strconv.ParseInt(value, 10, 64)
|
||||
}
|
||||
|
||||
// Map returns route parameters as a map[string]string.
|
||||
func (ps Params) Map() map[string]string {
|
||||
if ps.handler == nil || len(ps.handler.params) == 0 {
|
||||
return make(map[string]string)
|
||||
}
|
||||
m := make(map[string]string, len(ps.handler.params))
|
||||
for param, index := range ps.handler.params {
|
||||
if value, ok := ps.findParam(index); ok {
|
||||
m[param] = value
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Param represents a key-value pair of route parameters.
|
||||
type Param struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// Slice returns route parameters as a slice of Param.
|
||||
func (ps Params) Slice() []Param {
|
||||
if ps.handler == nil || len(ps.handler.params) == 0 {
|
||||
return []Param{}
|
||||
}
|
||||
slice := make([]Param, len(ps.handler.params))
|
||||
for param, index := range ps.handler.params {
|
||||
if value, ok := ps.findParam(index); ok {
|
||||
slice[index] = Param{Key: param, Value: value}
|
||||
}
|
||||
}
|
||||
return slice
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// H is a shorthand for map[string]interface{}.
|
||||
type H map[string]interface{}
|
||||
|
||||
// JSON marshals the value as JSON and writes it to the response writer.
|
||||
// It sets the Content-Type header to application/json.
|
||||
//
|
||||
// Don't hesitate to copy-paste this function to your project and customize it as necessary.
|
||||
func JSON(w http.ResponseWriter, value interface{}) error {
|
||||
if w == nil {
|
||||
return fmt.Errorf("bunrouter: nil response writer")
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if value == nil {
|
||||
if _, err := w.Write([]byte("null")); err != nil {
|
||||
return fmt.Errorf("bunrouter: failed to write null response: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(w)
|
||||
if err := enc.Encode(value); err != nil {
|
||||
return fmt.Errorf("bunrouter: JSON encoding error: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user