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) }