1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package pouchdb
16
17 import (
18 "context"
19 "io"
20 "strings"
21 "sync"
22
23 "github.com/gopherjs/gopherjs/js"
24 "github.com/gopherjs/jsbuiltin"
25
26 "github.com/go-kivik/kivik/v4/driver"
27 "github.com/go-kivik/kivik/v4/pouchdb/bindings"
28 )
29
30 func (d *db) PutAttachment(ctx context.Context, docID string, att *driver.Attachment, options driver.Options) (newRev string, err error) {
31 opts := map[string]interface{}{}
32 options.Apply(opts)
33 rev, _ := opts["rev"].(string)
34 result, err := d.db.PutAttachment(ctx, docID, att.Filename, rev, att.Content, att.ContentType)
35 if err != nil {
36 return "", err
37 }
38 return result.Get("rev").String(), nil
39 }
40
41 func (d *db) GetAttachment(ctx context.Context, docID, filename string, options driver.Options) (*driver.Attachment, error) {
42 opts := map[string]interface{}{}
43 options.Apply(opts)
44 result, err := d.db.GetAttachment(ctx, docID, filename, opts)
45 if err != nil {
46 return nil, err
47 }
48 return parseAttachment(result)
49 }
50
51 func parseAttachment(obj *js.Object) (att *driver.Attachment, err error) {
52 defer bindings.RecoverError(&err)
53 if jsbuiltin.TypeOf(obj.Get("write")) == jsbuiltin.TypeFunction {
54
55 body := obj.Call("toString", "binary").String()
56
57
58
59 return &driver.Attachment{
60 Content: io.NopCloser(strings.NewReader(body)),
61 }, nil
62 }
63
64 return &driver.Attachment{
65 ContentType: obj.Get("type").String(),
66 Content: &blobReader{Object: obj},
67 }, nil
68 }
69
70 type blobReader struct {
71 *js.Object
72 offset int
73 Size int `js:"size"`
74 }
75
76 var _ io.ReadCloser = &blobReader{}
77
78 func (b *blobReader) Read(p []byte) (n int, err error) {
79 defer bindings.RecoverError(&err)
80 if b.offset >= b.Size {
81 return 0, io.EOF
82 }
83 end := b.offset + len(p) + 1
84 if end > b.Size {
85 end = b.Size
86 }
87 slice := b.Call("slice", b.offset, end)
88 fileReader := js.Global.Get("FileReader").New()
89 var wg sync.WaitGroup
90 wg.Add(1)
91 fileReader.Set("onload", js.MakeFunc(func(this *js.Object, _ []*js.Object) interface{} {
92 defer wg.Done()
93 n = copy(p, js.Global.Get("Uint8Array").New(this.Get("result")).Interface().([]uint8))
94 return nil
95 }))
96 fileReader.Call("readAsArrayBuffer", slice)
97 wg.Wait()
98 b.offset += n
99 return
100 }
101
102 func (b *blobReader) Close() (err error) {
103 defer bindings.RecoverError(&err)
104 b.Call("close")
105 return nil
106 }
107
108 func (d *db) DeleteAttachment(ctx context.Context, docID, filename string, options driver.Options) (newRev string, err error) {
109 opts := map[string]interface{}{}
110 options.Apply(opts)
111 rev, _ := opts["rev"].(string)
112 result, err := d.db.RemoveAttachment(ctx, docID, filename, rev)
113 if err != nil {
114 return "", err
115 }
116 return result.Get("rev").String(), nil
117 }
118
View as plain text