go-paste/v2/app.paste.go

132 lines
2.8 KiB
Go
Raw Normal View History

2023-10-19 17:05:41 -06:00
package main
import (
"context"
"crypto/rand"
"errors"
"fmt"
"log"
"net/http"
"strconv"
"strings"
"go.sour.is/pkg/env"
"go.sour.is/pkg/lg"
"go.sour.is/pkg/service"
"go.sour.is/paste/assets"
"go.sour.is/paste/v2/paste"
)
var _ = apps.Register(50, func(ctx context.Context, svc *service.Harness) error {
_, span := lg.Span(ctx)
defer span.End()
store := env.Default("PASTE_STORE", "data/")
randBytes, err := strconv.ParseInt(env.Default("PASTE_RANDOM", "4096"), 10, 32)
if err != nil {
return err
}
p, err := paste.New(store)
if err != nil {
return err
}
svc.Add(&pasteSRV{
ui: http.FileServer(http.FS(assets.GetUI())),
paste: p,
randBytes: int(randBytes),
})
return nil
})
type pasteSRV struct {
ui http.Handler
paste *paste.Paste
randBytes int
}
func (a *pasteSRV) RegisterHTTP(mux *http.ServeMux) {
mux.Handle("/ui/", lg.Htrace(http.StripPrefix("/ui/", a.ui), "paste-assets"))
mux.Handle("/api", http.StripPrefix("/api", a))
mux.Handle("/api/", http.StripPrefix("/api/", a))
mux.Handle("/paste", http.StripPrefix("/paste", a))
mux.Handle("/paste/", http.StripPrefix("/paste/", a))
}
func (p *pasteSRV) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
switch {
case strings.HasPrefix(r.URL.Path, "rng"):
p.getRandom(w)
case strings.HasPrefix(r.URL.Path, "get"), r.URL.Path != "":
p.getPaste(w, strings.TrimPrefix(r.URL.Path, "get/"))
default:
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
case http.MethodPost:
switch {
case r.URL.Path == "":
p.postPaste(w, r)
default:
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}
default:
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
}
}
func (p *pasteSRV) getRandom(w http.ResponseWriter) {
log.Println("get random")
s := make([]byte, p.randBytes)
_, _ = rand.Read(s)
w.Header().Set("content-type", "application/octet-stream")
w.WriteHeader(http.StatusOK)
_, _ = w.Write(s)
}
func (p *pasteSRV) getPaste(w http.ResponseWriter, id string) {
log.Println("get paste", id)
w.Header().Set("content-type", "application/octet-stream")
err := p.paste.Get(w, id)
if err != nil {
switch {
case errors.Is(err, paste.ErrGone):
w.WriteHeader(http.StatusGone)
case errors.Is(err, paste.ErrNotFound):
w.WriteHeader(http.StatusNotFound)
case errors.Is(err, paste.ErrReadingContent):
w.WriteHeader(http.StatusInternalServerError)
}
fmt.Fprintf(w, "ERR %s", err)
return
}
}
func (p *pasteSRV) postPaste(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "application/octet-stream")
id, err := p.paste.Set(r.Body)
if err != nil {
fmt.Fprintf(w, "ERR %s", err)
return
}
log.Println("post paste", id)
fmt.Fprint(w, "OK ", id)
}