1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16
17 package client
18
19 import (
20 "context"
21 "errors"
22 "fmt"
23 "net/http"
24 "net/url"
25 "strings"
26
27 "perkeep.org/internal/httputil"
28 "perkeep.org/pkg/blob"
29 "perkeep.org/pkg/blobserver/handlers"
30 )
31
32
33
34
35 func (c *Client) RemoveBlobs(ctx context.Context, blobs []blob.Ref) error {
36 if c.sto != nil {
37 return c.sto.RemoveBlobs(ctx, blobs)
38 }
39 pfx, err := c.prefix()
40 if err != nil {
41 return err
42 }
43 url_ := fmt.Sprintf("%s/camli/remove", pfx)
44 params := make(url.Values)
45 needsDelete := make(map[blob.Ref]bool)
46 for n, b := range blobs {
47 if !b.Valid() {
48 return errors.New("Cannot delete invalid blobref")
49 }
50 key := fmt.Sprintf("blob%v", n+1)
51 params.Add(key, b.String())
52 needsDelete[b] = true
53 }
54
55 req, err := http.NewRequest("POST", url_, strings.NewReader(params.Encode()))
56 if err != nil {
57 return fmt.Errorf("Error creating RemoveBlobs POST request: %v", err)
58 }
59 req = req.WithContext(ctx)
60 req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
61 c.authMode.AddAuthHeader(req)
62 resp, err := c.httpClient.Do(req)
63 if err != nil {
64 resp.Body.Close()
65 return fmt.Errorf("Got status code %d from blobserver for remove %s", resp.StatusCode, params.Encode())
66 }
67 var remResp handlers.RemoveResponse
68 decodeErr := httputil.DecodeJSON(resp, &remResp)
69 if resp.StatusCode != 200 {
70 resp.Body.Close()
71 if decodeErr == nil {
72 return fmt.Errorf("invalid http response %d in remove response: %v", resp.StatusCode, remResp.Error)
73 } else {
74 return fmt.Errorf("invalid http response %d in remove response", resp.StatusCode)
75 }
76 }
77 if decodeErr != nil {
78 return fmt.Errorf("failed to parse remove response: %v", err)
79 }
80 for _, br := range remResp.Removed {
81 delete(needsDelete, br)
82 }
83 if len(needsDelete) > 0 {
84 return fmt.Errorf("failed to remove blobs %s", strings.Join(stringKeys(needsDelete), ", "))
85 }
86 return nil
87 }
88
89
90
91 func (c *Client) RemoveBlob(ctx context.Context, b blob.Ref) error {
92 return c.RemoveBlobs(ctx, []blob.Ref{b})
93 }
94
95 func stringKeys(m map[blob.Ref]bool) (s []string) {
96 s = make([]string, 0, len(m))
97 for key := range m {
98 s = append(s, key.String())
99 }
100 return
101 }