implement put and delete of R2

This commit is contained in:
syumai 2022-05-29 11:14:27 +09:00
parent f0149a86de
commit 47a5378664
4 changed files with 91 additions and 23 deletions

View File

@ -41,8 +41,8 @@ func handler(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Cache-Control", "public, max-age=14400")
w.Header().Set("ETag", fmt.Sprintf("W/%s", imgObj.HTTPETag))
contentType := "application/octet-stream"
if imgObj.HTTPMetadata.ContentType != nil {
contentType = *imgObj.HTTPMetadata.ContentType
if imgObj.HTTPMetadata.ContentType != "" {
contentType = imgObj.HTTPMetadata.ContentType
}
w.Header().Set("Content-Type", contentType)
io.Copy(w, imgObj.Body)

View File

@ -18,6 +18,8 @@ var (
errorClass = global.Get("Error")
readableStreamClass = global.Get("ReadableStream")
stringClass = global.Get("String")
dateClass = global.Get("Date")
numberClass = global.Get("Number")
)
func newObject() js.Value {
@ -77,24 +79,19 @@ func strRecordToMap(v js.Value) map[string]string {
}
// maybeString returns string value of given JavaScript value or returns nil if the value is undefined.
func maybeString(v js.Value) *string {
func maybeString(v js.Value) string {
if v.IsUndefined() {
return nil
return ""
}
s := v.String()
return &s
return v.String()
}
// maybeDate returns time.Time value of given JavaScript Date value or returns nil if the value is undefined.
func maybeDate(v js.Value) (*time.Time, error) {
func maybeDate(v js.Value) (time.Time, error) {
if v.IsUndefined() {
return nil, nil
return time.Time{}, nil
}
d, err := dateToTime(v)
if err != nil {
return nil, err
}
return &d, nil
return dateToTime(v)
}
// dateToTime converts JavaScript side's Data object into time.Time.
@ -106,3 +103,9 @@ func dateToTime(v js.Value) (time.Time, error) {
}
return time.UnixMilli(milli), nil
}
// timeToDate converts Go side's time.Time into Date object.
func timeToDate(t time.Time) js.Value {
milliStr := strconv.FormatInt(t.UnixMilli(), 10)
return dateClass.New(numberClass.Call(milliStr))
}

View File

@ -12,7 +12,7 @@ import (
type R2Bucket interface {
Head(key string) (*R2Object, error)
Get(key string) (*R2Object, error)
Put(key string, value io.Reader) error
Put(key string, value io.ReadCloser, opts *R2PutOptions) (*R2Object, error)
Delete(key string) error
List() (*R2Objects, error)
}
@ -66,12 +66,57 @@ func (r *r2Bucket) Get(key string) (*R2Object, error) {
return toR2Object(v)
}
func (r *r2Bucket) Put(key string, value io.Reader) error {
panic("implement me")
type R2PutOptions struct {
HTTPMetadata R2HTTPMetadata
CustomMetadata map[string]string
MD5 string
}
func (opts *R2PutOptions) toJS() js.Value {
if opts == nil {
return js.Undefined()
}
obj := newObject()
if opts.HTTPMetadata != (R2HTTPMetadata{}) {
obj.Set("httpMetadata", opts.HTTPMetadata.toJS())
}
if opts.CustomMetadata != nil {
// convert map[string]string to map[string]any.
// This makes the map convertible to JS.
// see: https://pkg.go.dev/syscall/js#ValueOf
customMeta := make(map[string]any, len(opts.CustomMetadata))
for k, v := range opts.CustomMetadata {
customMeta[k] = v
}
obj.Set("customMetadata", customMeta)
}
if opts.MD5 != "" {
obj.Set("md5", opts.MD5)
}
return obj
}
// Put returns the result of `put` call to R2Bucket.
// * Body field of *R2Object is always nil for Put call.
// * if a network error happens, returns error.
func (r *r2Bucket) Put(key string, value io.ReadCloser, opts *R2PutOptions) (*R2Object, error) {
body := convertReaderToReadableStream(value)
p := r.instance.Call("put", key, body, opts.toJS())
v, err := awaitPromise(p)
if err != nil {
return nil, err
}
return toR2Object(v)
}
// Delete returns the result of `delete` call to R2Bucket.
// * if a network error happens, returns error.
func (r *r2Bucket) Delete(key string) error {
panic("implement me")
p := r.instance.Call("delete", key)
if _, err := awaitPromise(p); err != nil {
return err
}
return nil
}
// List returns the result of `list` call to R2Bucket.

View File

@ -71,12 +71,12 @@ func toR2Object(v js.Value) (*R2Object, error) {
// R2HTTPMetadata represents metadata of R2Object.
// * https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1053
type R2HTTPMetadata struct {
ContentType *string
ContentLanguage *string
ContentDisposition *string
ContentEncoding *string
CacheControl *string
CacheExpiry *time.Time
ContentType string
ContentLanguage string
ContentDisposition string
ContentEncoding string
CacheControl string
CacheExpiry time.Time
}
func toR2HTTPMetadata(v js.Value) (R2HTTPMetadata, error) {
@ -93,3 +93,23 @@ func toR2HTTPMetadata(v js.Value) (R2HTTPMetadata, error) {
CacheExpiry: cacheExpiry,
}, nil
}
func (md *R2HTTPMetadata) toJS() js.Value {
obj := newObject()
kv := map[string]string{
"contentType": md.ContentType,
"contentLanguage": md.ContentLanguage,
"contentDisposition": md.ContentDisposition,
"contentEncoding": md.ContentEncoding,
"cacheControl": md.CacheControl,
}
for k, v := range kv {
if v != "" {
obj.Set(k, v)
}
}
if !md.CacheExpiry.IsZero() {
obj.Set("cacheExpiry", timeToDate(md.CacheExpiry))
}
return obj
}