Skip to content

Commit

Permalink
Add readonly backend
Browse files Browse the repository at this point in the history
  • Loading branch information
donny-dont committed Jun 26, 2020
1 parent 29d49d4 commit 8094b3e
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 0 deletions.
52 changes: 52 additions & 0 deletions readonly/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package readonly

import (
"errors"
"net/url"

"github.com/graymeta/stow"
)

const (
ConfigWrappedKind = "wrapped_kind"
ConfigWrapped = "wrapped"
)

// Kind is the kid of Location this package provides
const Kind = "readonly"

func init() {
validatefn := func(config stow.Config) error {
wrappedKind, ok := config.Config(ConfigWrappedKind)
if !ok || wrappedKind == "" {
return errors.New("missing wrapped kind")
}
wrappedConfig, ok := config.NestedConfig(ConfigWrapped)
if !ok {
return errors.New("missing config for wrapped")
}
return stow.Validate(wrappedKind, wrappedConfig)
}
makefn := func(config stow.Config) (stow.Location, error) {
wrappedKind, ok := config.Config(ConfigWrappedKind)
if !ok || wrappedKind == "" {
return nil, errors.New("missing wrapped kind")
}
wrappedConfig, ok := config.NestedConfig(ConfigWrapped)
if !ok {
return nil, errors.New("missing config for wrapped")
}

w, err := stow.Dial(wrappedKind, wrappedConfig)
if err != nil {
return nil, err
}

return &location{wrapped: w}, nil
}
kindfn := func(u *url.URL) bool {
return u.Scheme == Kind
}

stow.Register(Kind, makefn, kindfn, validatefn)
}
66 changes: 66 additions & 0 deletions readonly/container.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package readonly

import (
"errors"
"io"

"github.com/graymeta/stow"
)

type container struct {
wrapped stow.Container
}

// ID gets a unique string describing this Container.
func (c *container) ID() string {
return c.wrapped.ID()
}

// Name gets a human-readable name describing this Container.
func (c *container) Name() string {
return c.wrapped.Name()
}

// Item gets an item by its ID.
func (c *container) Item(id string) (stow.Item, error) {
it, err := c.wrapped.Item(id)
if err != nil {
return nil, err
}

return &item{wrapped: it}, nil
}

// Items gets a page of items with the specified
// prefix for this Container.
// The specified cursor is a pointer to the start of
// the items to get. It it obtained from a previous
// call to this method, or should be CursorStart for the
// first page.
// count is the number of items to return per page.
// The returned cursor can be checked with IsCursorEnd to
// decide if there are any more items or not.
func (c *container) Items(prefix, cursor string, count int) ([]stow.Item, string, error) {
its, startAfter, err := c.wrapped.Items(prefix, cursor, count)
if err != nil {
return nil, "", err
}

wrapped := make([]stow.Item, len(its))
for i, val := range its {
wrapped[i] = &item{wrapped: val}
}

return wrapped, startAfter, nil
}

// RemoveItem removes the Item with the specified ID.
func (c *container) RemoveItem(id string) error {
return errors.New("readonly")
}

// Put creates a new Item with the specified name, and contents
// read from the reader.
func (c *container) Put(name string, r io.Reader, size int64, metadata map[string]interface{}) (stow.Item, error) {
return nil, errors.New("readonly")
}
61 changes: 61 additions & 0 deletions readonly/item.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package readonly

import (
"io"
"net/url"
"time"

"github.com/graymeta/stow"
)

type item struct {
wrapped stow.Item
}

// ID gets a unique string describing this Item.
func (i *item) ID() string {
return i.wrapped.ID()
}

// Name gets a human-readable name describing this Item.
func (i *item) Name() string {
return i.wrapped.Name()
}

// URL gets a URL for this item.
// For example:
// local: file:///path/to/something
// azure: azure://host:port/api/something
// s3: s3://host:post/etc
func (i *item) URL() *url.URL {
return i.wrapped.URL()
}

// Size gets the size of the Item's contents in bytes.
func (i *item) Size() (int64, error) {
return i.wrapped.Size()
}

// Open opens the Item for reading.
// Calling code must close the io.ReadCloser.
func (i *item) Open() (io.ReadCloser, error) {
return i.wrapped.Open()
}

// ETag is a string that is different when the Item is
// different, and the same when the item is the same.
// Usually this is the last modified datetime.
func (i *item) ETag() (string, error) {
return i.wrapped.ETag()
}

// LastMod returns the last modified date of the file.
func (i *item) LastMod() (time.Time, error) {
return i.wrapped.LastMod()
}

// Metadata gets a map of key/values that belong
// to this Item.
func (i *item) Metadata() (map[string]interface{}, error) {
return i.wrapped.Metadata()
}
73 changes: 73 additions & 0 deletions readonly/location.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package readonly

import (
"errors"
"net/url"

"github.com/graymeta/stow"
)

type location struct {
wrapped stow.Location
}

// Closes the underlying location.
func (l *location) Close() error {
return l.wrapped.Close()
}

// CreateContainer creates a new Container with the
// specified name.
func (l *location) CreateContainer(name string) (stow.Container, error) {
return nil, errors.New("readonly")
}

// Containers gets a page of containers
// with the specified prefix from this Location.
// The specified cursor is a pointer to the start of
// the containers to get. It it obtained from a previous
// call to this method, or should be CursorStart for the
// first page.
// count is the number of items to return per page.
// The returned cursor can be checked with IsCursorEnd to
// decide if there are any more items or not.
func (l *location) Containers(prefix string, cursor string, count int) ([]stow.Container, string, error) {
cs, startAfter, err := l.wrapped.Containers(prefix, cursor, count)
if err != nil {
return nil, "", err
}

wrapped := make([]stow.Container, len(cs))
for i, val := range cs {
wrapped[i] = &container{wrapped: val}
}

return wrapped, startAfter, nil
}

// Container gets the Container with the specified
// identifier.
func (l *location) Container(id string) (stow.Container, error) {
c, err := l.wrapped.Container(id)
if err != nil {
return nil, err
}

return &container{wrapped: c}, nil
}

// RemoveContainer removes the container with the specified ID.
func (l *location) RemoveContainer(id string) error {
return errors.New("readonly")
}

// ItemByURL gets an Item at this location with the
// specified URL.
func (l *location) ItemByURL(url *url.URL) (stow.Item, error) {
i, err := l.wrapped.ItemByURL(url)
if err != nil {
return nil, err
}

return &item{wrapped: i}, nil
}

0 comments on commit 8094b3e

Please sign in to comment.