package main import ( _ "embed" "encoding/json" "image" "log/slog" "net/http" "sync" "time" "spoolweight/claude" ) //go:embed index.html var indexHTML []byte // serve runs the mobile putaway web server. Requests are serialized because the // shared spooldb browser session is single-threaded. func serve(addr string, auth claude.Auth, sp *spoolSync, dryRun bool) error { var mu sync.Mutex mux := http.NewServeMux() mux.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.NotFound(w, r) return } w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Write(indexHTML) }) mux.HandleFunc("POST /process", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") if err := r.ParseMultipartForm(64 << 20); err != nil { writeJSON(w, result{Error: "upload too large or malformed"}) return } file, hdr, err := r.FormFile("photo") if err != nil { writeJSON(w, result{Error: "no photo in request"}) return } defer file.Close() img, _, err := image.Decode(file) if err != nil { writeJSON(w, result{Image: hdr.Filename, Error: "could not read image (try choosing from your library)"}) return } start := time.Now() mu.Lock() res := processImg(img, hdr.Filename, auth, sp, dryRun) mu.Unlock() slog.Info("processed upload", "file", hdr.Filename, "spool", res.SpoolID, "dur", time.Since(start)) writeJSON(w, res) }) slog.Info("putaway server listening", "addr", addr, "dry_run", dryRun) return http.ListenAndServe(addr, mux) } func writeJSON(w http.ResponseWriter, v any) { json.NewEncoder(w).Encode(v) }