110 lines
2.5 KiB
Go
Raw Normal View History

2023-07-18 19:48:38 +00:00
package server
2023-07-18 16:02:57 +00:00
import (
2023-07-21 21:23:49 +00:00
"errors"
2023-07-19 11:01:51 +00:00
"io"
2023-07-18 16:02:57 +00:00
"net/http"
2023-07-19 11:01:51 +00:00
"unsafe"
2023-07-18 16:02:57 +00:00
)
// maxParams defines the maximum number of parameters per route.
const maxParams = 16
// Context represents the interface for a request & response context.
type Context interface {
Bytes([]byte) error
2023-07-21 21:23:49 +00:00
Error(status int, messages ...any) error
2023-07-22 09:48:35 +00:00
Get(param string) string
2023-07-19 11:01:51 +00:00
Reader(io.Reader) error
2023-07-22 10:32:52 +00:00
Request() Request
Response() Response
2023-07-21 21:23:49 +00:00
SetStatus(status int)
2023-07-19 11:01:51 +00:00
String(string) error
2023-07-18 16:02:57 +00:00
}
// context represents a request & response context.
type context struct {
2023-07-22 10:32:52 +00:00
request request
response response
2023-07-18 16:02:57 +00:00
paramNames [maxParams]string
paramValues [maxParams]string
paramCount int
}
// newContext returns a new context from the pool.
2023-07-22 10:32:52 +00:00
func newContext(req *http.Request, res http.ResponseWriter) *context {
2023-07-18 16:02:57 +00:00
ctx := contextPool.Get().(*context)
2023-07-22 10:32:52 +00:00
ctx.request.Request = req
ctx.response.ResponseWriter = res
2023-07-18 16:02:57 +00:00
ctx.paramCount = 0
return ctx
}
// Bytes responds with a raw byte slice.
func (ctx *context) Bytes(body []byte) error {
_, err := ctx.response.Write(body)
return err
}
// Error is used for sending error messages to the client.
2023-07-21 21:23:49 +00:00
func (ctx *context) Error(status int, messages ...any) error {
var combined []error
for _, msg := range messages {
switch err := msg.(type) {
case error:
combined = append(combined, err)
case string:
combined = append(combined, errors.New(err))
}
}
ctx.SetStatus(status)
return errors.Join(combined...)
2023-07-18 16:02:57 +00:00
}
2023-07-22 09:48:35 +00:00
// Get retrieves a parameter.
func (ctx *context) Get(param string) string {
for i := 0; i < ctx.paramCount; i++ {
if ctx.paramNames[i] == param {
return ctx.paramValues[i]
}
}
return ""
}
2023-07-19 11:01:51 +00:00
// Reader sends the contents of the io.Reader without creating an in-memory copy.
func (ctx *context) Reader(reader io.Reader) error {
_, err := io.Copy(ctx.response, reader)
return err
}
2023-07-22 10:32:52 +00:00
// Request returns the HTTP request.
func (ctx *context) Request() Request {
return &ctx.request
}
// Response returns the HTTP response.
func (ctx *context) Response() Response {
return &ctx.response
}
2023-07-21 21:23:49 +00:00
// SetStatus writes the header with the given HTTP status code.
func (ctx *context) SetStatus(status int) {
ctx.response.WriteHeader(status)
}
2023-07-19 11:01:51 +00:00
// String responds with the given string.
func (ctx *context) String(body string) error {
slice := unsafe.Slice(unsafe.StringData(body), len(body))
return ctx.Bytes(slice)
}
2023-07-18 16:02:57 +00:00
// addParameter adds a new parameter to the context.
func (ctx *context) addParameter(name string, value string) {
ctx.paramNames[ctx.paramCount] = name
ctx.paramValues[ctx.paramCount] = value
ctx.paramCount++
}