···
···
137
-
// TODO: proper statuses here on early exit
func (rp *Repo) DownloadArtifact(w http.ResponseWriter, r *http.Request) {
139
-
tagParam := chi.URLParam(r, "tag")
140
-
filename := chi.URLParam(r, "file")
f, err := rp.repoResolver.Resolve(r)
log.Println("failed to get repo and knot", err)
142
+
http.Error(w, "failed to resolve repo", http.StatusInternalServerError)
146
+
tagParam := chi.URLParam(r, "tag")
147
+
filename := chi.URLParam(r, "file")
tag, err := rp.resolveTag(r.Context(), f, tagParam)
···
154
-
client, err := rp.oauth.AuthorizedClient(r)
156
-
log.Println("failed to get authorized client", err)
artifacts, err := db.GetArtifact(
db.FilterEq("repo_at", f.RepoAt()),
···
log.Println("failed to get artifacts", err)
164
+
http.Error(w, "failed to get artifact", http.StatusInternalServerError)
171
-
log.Printf("too many or too little artifacts found")
169
+
log.Printf("too many or too few artifacts found")
170
+
http.Error(w, "artifact not found", http.StatusNotFound)
177
-
getBlobResp, err := client.SyncGetBlob(r.Context(), artifact.BlobCid.String(), artifact.Did)
176
+
ownerPds := f.OwnerId.PDSEndpoint()
177
+
url, _ := url.Parse(fmt.Sprintf("%s/xrpc/com.atproto.sync.getBlob", ownerPds))
179
+
q.Set("cid", artifact.BlobCid.String())
180
+
q.Set("did", artifact.Did)
181
+
url.RawQuery = q.Encode()
183
+
req, err := http.NewRequest(http.MethodGet, url.String(), nil)
185
+
log.Println("failed to create request", err)
186
+
http.Error(w, "failed to create request", http.StatusInternalServerError)
189
+
req.Header.Set("Content-Type", "application/json")
191
+
resp, err := http.DefaultClient.Do(req)
179
-
log.Println("failed to get blob from pds", err)
193
+
log.Println("failed to make request", err)
194
+
http.Error(w, "failed to make request to PDS", http.StatusInternalServerError)
197
+
defer resp.Body.Close()
183
-
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", filename))
184
-
w.Write(getBlobResp)
199
+
// copy status code and relevant headers from upstream response
200
+
w.WriteHeader(resp.StatusCode)
201
+
for key, values := range resp.Header {
202
+
for _, v := range values {
203
+
w.Header().Add(key, v)
207
+
// stream the body directly to the client
208
+
if _, err := io.Copy(w, resp.Body); err != nil {
209
+
log.Println("error streaming response to client:", err)
// TODO: proper statuses here on early exit