mirror of
https://github.com/syumai/workers.git
synced 2025-03-10 17:29:11 +00:00
move R2 features to cloudflare/r2 package
This commit is contained in:
parent
2d9f50ba40
commit
443e50a8bb
135
cloudflare/r2/bucket.go
Normal file
135
cloudflare/r2/bucket.go
Normal file
@ -0,0 +1,135 @@
|
||||
package r2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/syumai/workers/cloudflare/internal/cfruntimecontext"
|
||||
"github.com/syumai/workers/internal/jsutil"
|
||||
)
|
||||
|
||||
// Bucket represents interface of Cloudflare Worker's R2 Bucket instance.
|
||||
// - https://developers.cloudflare.com/r2/runtime-apis/#bucket-method-definitions
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1006
|
||||
type Bucket struct {
|
||||
instance js.Value
|
||||
}
|
||||
|
||||
// NewBucket returns Bucket for given variable name.
|
||||
// - variable name must be defined in wrangler.toml.
|
||||
// - see example: https://github.com/syumai/workers/tree/main/_examples/r2-image-viewer
|
||||
// - if the given variable name doesn't exist on runtime context, returns error.
|
||||
// - This function panics when a runtime context is not found.
|
||||
func NewBucket(varName string) (*Bucket, error) {
|
||||
inst := cfruntimecontext.MustGetRuntimeContextEnv().Get(varName)
|
||||
if inst.IsUndefined() {
|
||||
return nil, fmt.Errorf("%s is undefined", varName)
|
||||
}
|
||||
return &Bucket{instance: inst}, nil
|
||||
}
|
||||
|
||||
// Head returns the result of `head` call to Bucket.
|
||||
// - Body field of *Object is always nil for Head call.
|
||||
// - if the object for given key doesn't exist, returns nil.
|
||||
// - if a network error happens, returns error.
|
||||
func (r *Bucket) Head(key string) (*Object, error) {
|
||||
p := r.instance.Call("head", key)
|
||||
v, err := jsutil.AwaitPromise(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v.IsNull() {
|
||||
return nil, nil
|
||||
}
|
||||
return toObject(v)
|
||||
}
|
||||
|
||||
// Get returns the result of `get` call to Bucket.
|
||||
// - if the object for given key doesn't exist, returns nil.
|
||||
// - if a network error happens, returns error.
|
||||
func (r *Bucket) Get(key string) (*Object, error) {
|
||||
p := r.instance.Call("get", key)
|
||||
v, err := jsutil.AwaitPromise(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v.IsNull() {
|
||||
return nil, nil
|
||||
}
|
||||
return toObject(v)
|
||||
}
|
||||
|
||||
// PutOptions represents Cloudflare R2 put options.
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1128
|
||||
type PutOptions struct {
|
||||
HTTPMetadata HTTPMetadata
|
||||
CustomMetadata map[string]string
|
||||
MD5 string
|
||||
}
|
||||
|
||||
func (opts *PutOptions) toJS() js.Value {
|
||||
if opts == nil {
|
||||
return js.Undefined()
|
||||
}
|
||||
obj := jsutil.NewObject()
|
||||
if opts.HTTPMetadata != (HTTPMetadata{}) {
|
||||
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 Bucket.
|
||||
// - This method copies all bytes into memory for implementation restriction.
|
||||
// - Body field of *Object is always nil for Put call.
|
||||
// - if a network error happens, returns error.
|
||||
func (r *Bucket) Put(key string, value io.ReadCloser, opts *PutOptions) (*Object, error) {
|
||||
// fetch body cannot be ReadableStream. see: https://github.com/whatwg/fetch/issues/1438
|
||||
b, err := io.ReadAll(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer value.Close()
|
||||
ua := jsutil.NewUint8Array(len(b))
|
||||
js.CopyBytesToJS(ua, b)
|
||||
p := r.instance.Call("put", key, ua.Get("buffer"), opts.toJS())
|
||||
v, err := jsutil.AwaitPromise(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toObject(v)
|
||||
}
|
||||
|
||||
// Delete returns the result of `delete` call to Bucket.
|
||||
// - if a network error happens, returns error.
|
||||
func (r *Bucket) Delete(key string) error {
|
||||
p := r.instance.Call("delete", key)
|
||||
if _, err := jsutil.AwaitPromise(p); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// List returns the result of `list` call to Bucket.
|
||||
// - if a network error happens, returns error.
|
||||
func (r *Bucket) List() (*Objects, error) {
|
||||
p := r.instance.Call("list")
|
||||
v, err := jsutil.AwaitPromise(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toObjects(v)
|
||||
}
|
120
cloudflare/r2/object.go
Normal file
120
cloudflare/r2/object.go
Normal file
@ -0,0 +1,120 @@
|
||||
package r2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"syscall/js"
|
||||
"time"
|
||||
|
||||
"github.com/syumai/workers/internal/jsutil"
|
||||
)
|
||||
|
||||
// Object represents Cloudflare R2 object.
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1094
|
||||
type Object struct {
|
||||
instance js.Value
|
||||
Key string
|
||||
Version string
|
||||
Size int
|
||||
ETag string
|
||||
HTTPETag string
|
||||
Uploaded time.Time
|
||||
HTTPMetadata HTTPMetadata
|
||||
CustomMetadata map[string]string
|
||||
// Body is a body of Object.
|
||||
// This value is nil for the result of the `Head` or `Put` method.
|
||||
Body io.Reader
|
||||
}
|
||||
|
||||
// TODO: implement
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1106
|
||||
// func (o *Object) WriteHTTPMetadata(headers http.Header) {
|
||||
// }
|
||||
|
||||
func (o *Object) BodyUsed() (bool, error) {
|
||||
v := o.instance.Get("bodyUsed")
|
||||
if v.IsUndefined() {
|
||||
return false, errors.New("bodyUsed doesn't exist for this Object")
|
||||
}
|
||||
return v.Bool(), nil
|
||||
}
|
||||
|
||||
// toObject converts JavaScript side's Object to *Object.
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1094
|
||||
func toObject(v js.Value) (*Object, error) {
|
||||
uploaded, err := jsutil.DateToTime(v.Get("uploaded"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting uploaded: %w", err)
|
||||
}
|
||||
r2Meta, err := toHTTPMetadata(v.Get("httpMetadata"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting httpMetadata: %w", err)
|
||||
}
|
||||
bodyVal := v.Get("body")
|
||||
var body io.Reader
|
||||
if !bodyVal.IsUndefined() {
|
||||
body = jsutil.ConvertReadableStreamToReadCloser(v.Get("body"))
|
||||
}
|
||||
return &Object{
|
||||
instance: v,
|
||||
Key: v.Get("key").String(),
|
||||
Version: v.Get("version").String(),
|
||||
Size: v.Get("size").Int(),
|
||||
ETag: v.Get("etag").String(),
|
||||
HTTPETag: v.Get("httpEtag").String(),
|
||||
Uploaded: uploaded,
|
||||
HTTPMetadata: r2Meta,
|
||||
CustomMetadata: jsutil.StrRecordToMap(v.Get("customMetadata")),
|
||||
Body: body,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// HTTPMetadata represents metadata of Object.
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1053
|
||||
type HTTPMetadata struct {
|
||||
ContentType string
|
||||
ContentLanguage string
|
||||
ContentDisposition string
|
||||
ContentEncoding string
|
||||
CacheControl string
|
||||
CacheExpiry time.Time
|
||||
}
|
||||
|
||||
func toHTTPMetadata(v js.Value) (HTTPMetadata, error) {
|
||||
if v.IsUndefined() || v.IsNull() {
|
||||
return HTTPMetadata{}, nil
|
||||
}
|
||||
cacheExpiry, err := jsutil.MaybeDate(v.Get("cacheExpiry"))
|
||||
if err != nil {
|
||||
return HTTPMetadata{}, fmt.Errorf("error converting cacheExpiry: %w", err)
|
||||
}
|
||||
return HTTPMetadata{
|
||||
ContentType: jsutil.MaybeString(v.Get("contentType")),
|
||||
ContentLanguage: jsutil.MaybeString(v.Get("contentLanguage")),
|
||||
ContentDisposition: jsutil.MaybeString(v.Get("contentDisposition")),
|
||||
ContentEncoding: jsutil.MaybeString(v.Get("contentEncoding")),
|
||||
CacheControl: jsutil.MaybeString(v.Get("cacheControl")),
|
||||
CacheExpiry: cacheExpiry,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (md *HTTPMetadata) toJS() js.Value {
|
||||
obj := jsutil.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", jsutil.TimeToDate(md.CacheExpiry))
|
||||
}
|
||||
return obj
|
||||
}
|
44
cloudflare/r2/objects.go
Normal file
44
cloudflare/r2/objects.go
Normal file
@ -0,0 +1,44 @@
|
||||
package r2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/syumai/workers/internal/jsutil"
|
||||
)
|
||||
|
||||
// Objects represents Cloudflare R2 objects.
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1121
|
||||
type Objects struct {
|
||||
Objects []*Object
|
||||
Truncated bool
|
||||
// Cursor indicates next cursor of Objects.
|
||||
// - This becomes empty string if cursor doesn't exist.
|
||||
Cursor string
|
||||
DelimitedPrefixes []string
|
||||
}
|
||||
|
||||
// toObjects converts JavaScript side's Objects to *Objects.
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1121
|
||||
func toObjects(v js.Value) (*Objects, error) {
|
||||
objectsVal := v.Get("objects")
|
||||
objects := make([]*Object, objectsVal.Length())
|
||||
for i := 0; i < len(objects); i++ {
|
||||
obj, err := toObject(objectsVal.Index(i))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting to Object: %w", err)
|
||||
}
|
||||
objects[i] = obj
|
||||
}
|
||||
prefixesVal := v.Get("delimitedPrefixes")
|
||||
prefixes := make([]string, prefixesVal.Length())
|
||||
for i := 0; i < len(prefixes); i++ {
|
||||
prefixes[i] = prefixesVal.Index(i).String()
|
||||
}
|
||||
return &Objects{
|
||||
Objects: objects,
|
||||
Truncated: v.Get("truncated").Bool(),
|
||||
Cursor: jsutil.MaybeString(v.Get("cursor")),
|
||||
DelimitedPrefixes: prefixes,
|
||||
}, nil
|
||||
}
|
@ -1,135 +1,19 @@
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/syumai/workers/cloudflare/internal/cfruntimecontext"
|
||||
"github.com/syumai/workers/internal/jsutil"
|
||||
"github.com/syumai/workers/cloudflare/r2"
|
||||
)
|
||||
|
||||
// R2Bucket represents interface of Cloudflare Worker's R2 Bucket instance.
|
||||
// - https://developers.cloudflare.com/r2/runtime-apis/#bucket-method-definitions
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1006
|
||||
type R2Bucket struct {
|
||||
instance js.Value
|
||||
}
|
||||
// Deprecated: use r2.Bucket instead.
|
||||
type R2Bucket = r2.Bucket
|
||||
|
||||
// NewR2Bucket returns R2Bucket for given variable name.
|
||||
// - variable name must be defined in wrangler.toml.
|
||||
// - see example: https://github.com/syumai/workers/tree/main/_examples/r2-image-viewer
|
||||
// - if the given variable name doesn't exist on runtime context, returns error.
|
||||
// - This function panics when a runtime context is not found.
|
||||
// Deprecated: use r2.NewBucket instead.
|
||||
func NewR2Bucket(varName string) (*R2Bucket, error) {
|
||||
inst := cfruntimecontext.MustGetRuntimeContextEnv().Get(varName)
|
||||
if inst.IsUndefined() {
|
||||
return nil, fmt.Errorf("%s is undefined", varName)
|
||||
}
|
||||
return &R2Bucket{instance: inst}, nil
|
||||
}
|
||||
|
||||
// Head returns the result of `head` call to R2Bucket.
|
||||
// - Body field of *R2Object is always nil for Head call.
|
||||
// - if the object for given key doesn't exist, returns nil.
|
||||
// - if a network error happens, returns error.
|
||||
func (r *R2Bucket) Head(key string) (*R2Object, error) {
|
||||
p := r.instance.Call("head", key)
|
||||
v, err := jsutil.AwaitPromise(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v.IsNull() {
|
||||
return nil, nil
|
||||
}
|
||||
return toR2Object(v)
|
||||
}
|
||||
|
||||
// Get returns the result of `get` call to R2Bucket.
|
||||
// - if the object for given key doesn't exist, returns nil.
|
||||
// - if a network error happens, returns error.
|
||||
func (r *R2Bucket) Get(key string) (*R2Object, error) {
|
||||
p := r.instance.Call("get", key)
|
||||
v, err := jsutil.AwaitPromise(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v.IsNull() {
|
||||
return nil, nil
|
||||
}
|
||||
return toR2Object(v)
|
||||
return r2.NewBucket(varName)
|
||||
}
|
||||
|
||||
// R2PutOptions represents Cloudflare R2 put options.
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1128
|
||||
type R2PutOptions struct {
|
||||
HTTPMetadata R2HTTPMetadata
|
||||
CustomMetadata map[string]string
|
||||
MD5 string
|
||||
}
|
||||
|
||||
func (opts *R2PutOptions) toJS() js.Value {
|
||||
if opts == nil {
|
||||
return js.Undefined()
|
||||
}
|
||||
obj := jsutil.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.
|
||||
// - This method copies all bytes into memory for implementation restriction.
|
||||
// - 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) {
|
||||
// fetch body cannot be ReadableStream. see: https://github.com/whatwg/fetch/issues/1438
|
||||
b, err := io.ReadAll(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer value.Close()
|
||||
ua := jsutil.NewUint8Array(len(b))
|
||||
js.CopyBytesToJS(ua, b)
|
||||
p := r.instance.Call("put", key, ua.Get("buffer"), opts.toJS())
|
||||
v, err := jsutil.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 {
|
||||
p := r.instance.Call("delete", key)
|
||||
if _, err := jsutil.AwaitPromise(p); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// List returns the result of `list` call to R2Bucket.
|
||||
// - if a network error happens, returns error.
|
||||
func (r *R2Bucket) List() (*R2Objects, error) {
|
||||
p := r.instance.Call("list")
|
||||
v, err := jsutil.AwaitPromise(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toR2Objects(v)
|
||||
}
|
||||
// Deprecated: use r2.PutOptions instead.
|
||||
type R2PutOptions = r2.PutOptions
|
||||
|
@ -1,120 +1,13 @@
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"syscall/js"
|
||||
"time"
|
||||
|
||||
"github.com/syumai/workers/internal/jsutil"
|
||||
"github.com/syumai/workers/cloudflare/r2"
|
||||
)
|
||||
|
||||
// R2Object represents Cloudflare R2 object.
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1094
|
||||
type R2Object struct {
|
||||
instance js.Value
|
||||
Key string
|
||||
Version string
|
||||
Size int
|
||||
ETag string
|
||||
HTTPETag string
|
||||
Uploaded time.Time
|
||||
HTTPMetadata R2HTTPMetadata
|
||||
CustomMetadata map[string]string
|
||||
// Body is a body of R2Object.
|
||||
// This value is nil for the result of the `Head` or `Put` method.
|
||||
Body io.Reader
|
||||
}
|
||||
|
||||
// TODO: implement
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1106
|
||||
// func (o *R2Object) WriteHTTPMetadata(headers http.Header) {
|
||||
// }
|
||||
|
||||
func (o *R2Object) BodyUsed() (bool, error) {
|
||||
v := o.instance.Get("bodyUsed")
|
||||
if v.IsUndefined() {
|
||||
return false, errors.New("bodyUsed doesn't exist for this R2Object")
|
||||
}
|
||||
return v.Bool(), nil
|
||||
}
|
||||
|
||||
// toR2Object converts JavaScript side's R2Object to *R2Object.
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1094
|
||||
func toR2Object(v js.Value) (*R2Object, error) {
|
||||
uploaded, err := jsutil.DateToTime(v.Get("uploaded"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting uploaded: %w", err)
|
||||
}
|
||||
r2Meta, err := toR2HTTPMetadata(v.Get("httpMetadata"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting httpMetadata: %w", err)
|
||||
}
|
||||
bodyVal := v.Get("body")
|
||||
var body io.Reader
|
||||
if !bodyVal.IsUndefined() {
|
||||
body = jsutil.ConvertReadableStreamToReadCloser(v.Get("body"))
|
||||
}
|
||||
return &R2Object{
|
||||
instance: v,
|
||||
Key: v.Get("key").String(),
|
||||
Version: v.Get("version").String(),
|
||||
Size: v.Get("size").Int(),
|
||||
ETag: v.Get("etag").String(),
|
||||
HTTPETag: v.Get("httpEtag").String(),
|
||||
Uploaded: uploaded,
|
||||
HTTPMetadata: r2Meta,
|
||||
CustomMetadata: jsutil.StrRecordToMap(v.Get("customMetadata")),
|
||||
Body: body,
|
||||
}, nil
|
||||
}
|
||||
// Deprecated: use r2.Object instead.
|
||||
type R2Object = r2.Object
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func toR2HTTPMetadata(v js.Value) (R2HTTPMetadata, error) {
|
||||
if v.IsUndefined() || v.IsNull() {
|
||||
return R2HTTPMetadata{}, nil
|
||||
}
|
||||
cacheExpiry, err := jsutil.MaybeDate(v.Get("cacheExpiry"))
|
||||
if err != nil {
|
||||
return R2HTTPMetadata{}, fmt.Errorf("error converting cacheExpiry: %w", err)
|
||||
}
|
||||
return R2HTTPMetadata{
|
||||
ContentType: jsutil.MaybeString(v.Get("contentType")),
|
||||
ContentLanguage: jsutil.MaybeString(v.Get("contentLanguage")),
|
||||
ContentDisposition: jsutil.MaybeString(v.Get("contentDisposition")),
|
||||
ContentEncoding: jsutil.MaybeString(v.Get("contentEncoding")),
|
||||
CacheControl: jsutil.MaybeString(v.Get("cacheControl")),
|
||||
CacheExpiry: cacheExpiry,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (md *R2HTTPMetadata) toJS() js.Value {
|
||||
obj := jsutil.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", jsutil.TimeToDate(md.CacheExpiry))
|
||||
}
|
||||
return obj
|
||||
}
|
||||
// Deprecated: use r2.HTTPMetadata instead.
|
||||
type R2HTTPMetadata = r2.HTTPMetadata
|
||||
|
@ -1,44 +1,9 @@
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/syumai/workers/internal/jsutil"
|
||||
"github.com/syumai/workers/cloudflare/r2"
|
||||
)
|
||||
|
||||
// R2Objects represents Cloudflare R2 objects.
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1121
|
||||
type R2Objects struct {
|
||||
Objects []*R2Object
|
||||
Truncated bool
|
||||
// Cursor indicates next cursor of R2Objects.
|
||||
// - This becomes empty string if cursor doesn't exist.
|
||||
Cursor string
|
||||
DelimitedPrefixes []string
|
||||
}
|
||||
|
||||
// toR2Objects converts JavaScript side's R2Objects to *R2Objects.
|
||||
// - https://github.com/cloudflare/workers-types/blob/3012f263fb1239825e5f0061b267c8650d01b717/index.d.ts#L1121
|
||||
func toR2Objects(v js.Value) (*R2Objects, error) {
|
||||
objectsVal := v.Get("objects")
|
||||
objects := make([]*R2Object, objectsVal.Length())
|
||||
for i := 0; i < len(objects); i++ {
|
||||
obj, err := toR2Object(objectsVal.Index(i))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting to R2Object: %w", err)
|
||||
}
|
||||
objects[i] = obj
|
||||
}
|
||||
prefixesVal := v.Get("delimitedPrefixes")
|
||||
prefixes := make([]string, prefixesVal.Length())
|
||||
for i := 0; i < len(prefixes); i++ {
|
||||
prefixes[i] = prefixesVal.Index(i).String()
|
||||
}
|
||||
return &R2Objects{
|
||||
Objects: objects,
|
||||
Truncated: v.Get("truncated").Bool(),
|
||||
Cursor: jsutil.MaybeString(v.Get("cursor")),
|
||||
DelimitedPrefixes: prefixes,
|
||||
}, nil
|
||||
}
|
||||
// Deprecated: use r2.Objects instead.
|
||||
type R2Objects = r2.Objects
|
||||
|
Loading…
x
Reference in New Issue
Block a user