124 lines
2.6 KiB
Go
Raw Normal View History

2024-03-22 14:08:24 +00:00
package web
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"
2024-03-15 09:06:17 +00:00
"git.akyoto.dev/go/router"
2023-07-18 16:02:57 +00:00
)
// Context represents the interface for a request & response context.
type Context interface {
2024-03-16 14:22:47 +00:00
Copy(io.Reader) error
2023-07-18 16:02:57 +00:00
Bytes([]byte) error
2024-03-16 14:30:05 +00:00
Error(...any) error
File(string) error
Get(string) string
2024-03-13 19:18:01 +00:00
Next() error
2024-03-20 20:17:50 +00:00
Redirect(int, string) error
2024-03-16 14:22:47 +00:00
Request() Request
Response() Response
2024-03-16 14:30:05 +00:00
Status(int) Context
2023-07-19 11:01:51 +00:00
String(string) error
2023-07-18 16:02:57 +00:00
}
2024-03-12 21:31:45 +00:00
// ctx represents a request & response context.
type ctx struct {
2024-03-16 14:22:47 +00:00
request request
response response
2024-03-14 11:52:03 +00:00
server *server
2024-03-15 09:06:17 +00:00
params []router.Parameter
2024-03-14 14:11:00 +00:00
handlerCount uint8
2023-07-18 16:02:57 +00:00
}
// Bytes responds with a raw byte slice.
2024-03-16 14:22:47 +00:00
func (ctx *ctx) Bytes(body []byte) error {
_, err := ctx.response.Write(body)
return err
}
// Copy sends the contents of the io.Reader without creating an in-memory copy.
func (ctx *ctx) Copy(reader io.Reader) error {
_, err := io.Copy(ctx.response.ResponseWriter, reader)
2023-07-18 16:02:57 +00:00
return err
}
// Error is used for sending error messages to the client.
2024-03-13 15:57:36 +00:00
func (ctx *ctx) Error(messages ...any) error {
2023-07-21 21:23:49 +00:00
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))
}
}
return errors.Join(combined...)
2023-07-18 16:02:57 +00:00
}
2023-07-22 09:48:35 +00:00
// Get retrieves a parameter.
2024-03-12 21:31:45 +00:00
func (ctx *ctx) Get(param string) string {
2024-03-14 14:11:00 +00:00
for i := range len(ctx.params) {
p := ctx.params[i]
2024-03-15 09:06:17 +00:00
if p.Key == param {
2024-03-14 14:11:00 +00:00
return p.Value
2023-07-22 09:48:35 +00:00
}
}
return ""
}
2024-03-16 14:22:47 +00:00
// File serves the file at the given path.
func (ctx *ctx) File(path string) error {
http.ServeFile(ctx.response.ResponseWriter, ctx.request.Request, path)
return nil
}
2024-03-13 19:18:01 +00:00
// Next executes the next handler in the middleware chain.
func (ctx *ctx) Next() error {
ctx.handlerCount++
return ctx.server.handlers[ctx.handlerCount](ctx)
}
2024-03-16 14:22:47 +00:00
// Request returns the HTTP request.
func (ctx *ctx) Request() Request {
return &ctx.request
2024-03-13 19:18:01 +00:00
}
2024-03-16 14:22:47 +00:00
// Response returns the HTTP response.
func (ctx *ctx) Response() Response {
return &ctx.response
2024-03-14 11:52:03 +00:00
}
2024-03-20 20:17:50 +00:00
// Redirect sets the Location header and writes the headers with the given status code.
func (ctx *ctx) Redirect(code int, url string) error {
ctx.Response().SetHeader("Location", url)
ctx.Status(code)
return nil
}
2024-03-13 15:57:36 +00:00
// Status sets the HTTP status of the response.
func (ctx *ctx) Status(status int) Context {
ctx.response.WriteHeader(status)
return ctx
}
2023-07-19 11:01:51 +00:00
// String responds with the given string.
2024-03-12 21:31:45 +00:00
func (ctx *ctx) String(body string) error {
2024-03-16 14:22:47 +00:00
_, err := ctx.response.WriteString(body)
return err
2024-03-14 11:52:03 +00:00
}
2023-07-18 16:02:57 +00:00
// addParameter adds a new parameter to the context.
2024-03-15 09:06:17 +00:00
func (ctx *ctx) addParameter(key string, value string) {
ctx.params = append(ctx.params, router.Parameter{
Key: key,
Value: value,
})
2023-07-18 16:02:57 +00:00
}