1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16
17 package server
18
19 import (
20 "io"
21 "log"
22 "net/http"
23
24 "go4.org/types"
25 "perkeep.org/internal/httputil"
26 "perkeep.org/pkg/blob"
27 "perkeep.org/pkg/schema"
28 )
29
30
31 type uploadHelperResponse struct {
32 Got []*uploadHelperGotItem `json:"got"`
33 }
34
35 type uploadHelperGotItem struct {
36 FileName string `json:"filename"`
37 ModTime types.Time3339 `json:"modtime"`
38 FormName string `json:"formname"`
39 FileRef blob.Ref `json:"fileref"`
40 }
41
42 func (ui *UIHandler) serveUploadHelper(rw http.ResponseWriter, req *http.Request) {
43 ctx := req.Context()
44 if ui.root.Storage == nil {
45 httputil.ServeJSONError(rw, httputil.ServerError("No BlobRoot configured"))
46 return
47 }
48
49 mr, err := req.MultipartReader()
50 if err != nil {
51 httputil.ServeJSONError(rw, httputil.ServerError("reading body: "+err.Error()))
52 return
53 }
54
55 var got []*uploadHelperGotItem
56 var modTime types.Time3339
57 for {
58 part, err := mr.NextPart()
59 if err == io.EOF {
60 break
61 }
62 if err != nil {
63 httputil.ServeJSONError(rw, httputil.ServerError("reading body: "+err.Error()))
64 break
65 }
66 if part.FormName() == "modtime" {
67 payload, err := io.ReadAll(part)
68 if err != nil {
69 log.Printf("ui uploadhelper: unable to read part for modtime: %v", err)
70 continue
71 }
72 modTime = types.ParseTime3339OrZero(string(payload))
73 continue
74 }
75 fileName := part.FileName()
76 if fileName == "" {
77 continue
78 }
79 br, err := schema.WriteFileFromReaderWithModTime(ctx, ui.root.Storage, fileName, modTime.Time(), part)
80 if err != nil {
81 httputil.ServeJSONError(rw, httputil.ServerError("writing to blobserver: "+err.Error()))
82 return
83 }
84 got = append(got, &uploadHelperGotItem{
85 FileName: part.FileName(),
86 ModTime: modTime,
87 FormName: part.FormName(),
88 FileRef: br,
89 })
90 }
91
92 httputil.ReturnJSON(rw, &uploadHelperResponse{Got: got})
93 }