ollama/x/oweb/oweb.go
Blake Mizerany adc23d5f96 Add 'x/' from commit 'a10a11b9d371f36b7c3510da32a1d70b74e27bd1'
git-subtree-dir: x
git-subtree-mainline: 7d05a6ee8f44b314fa697a427439e5fa4d78c3d7
git-subtree-split: a10a11b9d371f36b7c3510da32a1d70b74e27bd1
2024-04-03 10:40:23 -07:00

87 lines
1.8 KiB
Go

package oweb
import (
"cmp"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"
"bllamo.com/client/ollama"
)
func Missing(field string) error {
return &ollama.Error{
Status: 400,
Code: "missing",
Field: field,
Message: fmt.Sprintf("%s is required", field),
}
}
func Mistake(code, field, message string) error {
return &ollama.Error{
Status: 400,
Code: code,
Field: field,
Message: fmt.Sprintf("%s: %s", field, message),
}
}
// Convenience errors
var (
ErrNotFound = &ollama.Error{Status: 404, Code: "not_found"}
ErrInternal = &ollama.Error{Status: 500, Code: "internal_error"}
ErrMethodNotAllowed = &ollama.Error{Status: 405, Code: "method_not_allowed"}
)
type HandlerFunc func(w http.ResponseWriter, r *http.Request) error
func Serve(h HandlerFunc, w http.ResponseWriter, r *http.Request) {
if err := h(w, r); err != nil {
// TODO: take a slog.Logger
log.Printf("error: %v", err)
var oe *ollama.Error
if !errors.As(err, &oe) {
oe = ErrInternal
}
oe.Status = cmp.Or(oe.Status, 400)
w.WriteHeader(oe.Status)
if err := EncodeJSON(w, oe); err != nil {
log.Printf("error encoding error: %v", err)
}
}
}
func DecodeUserJSON[T any](field string, r io.Reader) (*T, error) {
v, err := DecodeJSON[T](r)
if err == nil {
return v, nil
}
var msg string
var e *json.SyntaxError
if errors.As(err, &e) {
msg = e.Error()
}
var se *json.UnmarshalTypeError
if errors.As(err, &se) {
msg = fmt.Sprintf("%s (%q) is not a %s", se.Field, se.Value, se.Type)
}
return nil, Mistake("invalid_json", field, msg)
}
func DecodeJSON[T any](r io.Reader) (*T, error) {
var v *T
if err := json.NewDecoder(r).Decode(&v); err != nil {
var zero T
return &zero, err
}
return v, nil
}
func EncodeJSON(w io.Writer, v any) error {
return json.NewEncoder(w).Encode(v)
}