Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to new Google Cloud API. #148

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions google/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import (
"net/url"
"strings"

"cloud.google.com/go/storage"
"github.com/graymeta/stow"
"golang.org/x/net/context"
"golang.org/x/oauth2/google"
storage "google.golang.org/api/storage/v1"
"google.golang.org/api/option"
)

// Kind represents the name of the location/storage type.
Expand Down Expand Up @@ -57,20 +57,21 @@ func init() {
}

// Attempts to create a session based on the information given.
func newGoogleStorageClient(config stow.Config) (*storage.Service, error) {
func newGoogleStorageClient(config stow.Config) (*storage.Client, error) {
json, _ := config.Config(ConfigJSON)

scopes := []string{storage.DevstorageReadWriteScope}
scopes := []string{storage.ScopeReadWrite}
if s, ok := config.Config(ConfigScopes); ok && s != "" {
scopes = strings.Split(s, ",")
}

jwtConf, err := google.JWTConfigFromJSON([]byte(json), scopes...)

service, err := storage.New(jwtConf.Client(context.Background()))
if err != nil {
return nil, err
var opts []option.ClientOption
if json != "" {
opts = append(opts, option.WithServiceAccountFile(json))
}
if len(scopes) > 0 {
opts = append(opts, option.WithScopes(scopes...))
}

return service, nil
return storage.NewClient(context.Background(), opts...)
}
143 changes: 47 additions & 96 deletions google/container.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
package google

import (
"context"
"io"
"time"

"cloud.google.com/go/storage"
"github.com/graymeta/stow"
"github.com/pkg/errors"
storage "google.golang.org/api/storage/v1"
"google.golang.org/api/iterator"
)

type Container struct {
// Name is needed to retrieve items.
name string

//bucket *storage.BucketHandle

// Client is responsible for performing the requests.
client *storage.Service
client *storage.Client
}

// ID returns a string value which represents the name of the container.
Expand All @@ -27,104 +30,74 @@ func (c *Container) Name() string {
return c.name
}

func (c *Container) Bucket() (*storage.Bucket, error) {
return c.client.Buckets.Get(c.name).Do()
func (c *Container) Bucket() *storage.BucketHandle {
return c.client.Bucket(c.name)
}

// Item returns a stow.Item instance of a container based on the
// name of the container
func (c *Container) Item(id string) (stow.Item, error) {
res, err := c.client.Objects.Get(c.name, id).Do()
if err != nil {
return nil, stow.ErrNotFound
}

t, err := time.Parse(time.RFC3339, res.Updated)
if err != nil {
return nil, err
}

func (c *Container) objectAttrToItem(res *storage.ObjectAttrs) *Item {
u, err := prepUrl(res.MediaLink)
if err != nil {
return nil, err
return nil
}

mdParsed, err := parseMetadata(res.Metadata)
if err != nil {
return nil, err
return nil
}

i := &Item{
name: id,
return &Item{
name: res.Name,
container: c,
client: c.client,
size: int64(res.Size),
etag: res.Etag,
hash: res.Md5Hash,
lastModified: t,
size: res.Size,
etag: "",
hash: string(res.MD5),
lastModified: res.Updated,
url: u,
metadata: mdParsed,
object: res,
}
}

// Item returns a stow.Item instance of a container based on the
// name of the container
func (c *Container) Item(id string) (stow.Item, error) {
obj := c.Bucket().Object(id)
res, err := obj.Attrs(context.TODO())
if err != nil {
return nil, stow.ErrNotFound
}

return i, nil
itm := c.objectAttrToItem(res)
itm.object = obj
return itm, nil
}

// Items retrieves a list of items that are prepended with
// the prefix argument. The 'cursor' variable facilitates pagination.
func (c *Container) Items(prefix string, cursor string, count int) ([]stow.Item, string, error) {
// List all objects in a bucket using pagination
call := c.client.Objects.List(c.name).MaxResults(int64(count))

if prefix != "" {
call.Prefix(prefix)
q := storage.Query{
Prefix: prefix,
}

if cursor != "" {
call = call.PageToken(cursor)
}
pager := iterator.NewPager(c.Bucket().Objects(context.Background(), &q), count, cursor)

res, err := call.Do()
var attrs []*storage.ObjectAttrs
nextPageToken, err := pager.NextPage(&attrs)
if err != nil {
return nil, "", err
}
containerItems := make([]stow.Item, len(res.Items))
containerItems := make([]stow.Item, len(attrs))

for i, o := range res.Items {
t, err := time.Parse(time.RFC3339, o.Updated)
if err != nil {
return nil, "", err
}

u, err := prepUrl(o.MediaLink)
if err != nil {
return nil, "", err
}

mdParsed, err := parseMetadata(o.Metadata)
if err != nil {
return nil, "", err
}

containerItems[i] = &Item{
name: o.Name,
container: c,
client: c.client,
size: int64(o.Size),
etag: o.Etag,
hash: o.Md5Hash,
lastModified: t,
url: u,
metadata: mdParsed,
object: o,
}
for i, o := range attrs {
containerItems[i] = c.objectAttrToItem(o)
}

return containerItems, res.NextPageToken, nil
return containerItems, nextPageToken, nil
}

func (c *Container) RemoveItem(id string) error {
return c.client.Objects.Delete(c.name, id).Do()
return c.Bucket().Object(id).Delete(context.Background())
}

// Put sends a request to upload content to the container. The arguments
Expand All @@ -136,44 +109,22 @@ func (c *Container) Put(name string, r io.Reader, size int64, metadata map[strin
return nil, err
}

object := &storage.Object{
Name: name,
Metadata: mdPrepped,
}
obj := c.Bucket().Object(name)
writer := obj.NewWriter(context.Background())

res, err := c.client.Objects.Insert(c.name, object).Media(r).Do()
if err != nil {
return nil, err
}
writer.Name = name
writer.Metadata = mdPrepped

t, err := time.Parse(time.RFC3339, res.Updated)
_, err = io.Copy(writer, r)
if err != nil {
return nil, err
}

u, err := prepUrl(res.MediaLink)
if err != nil {
return nil, err
}

mdParsed, err := parseMetadata(res.Metadata)
err = writer.Close()
if err != nil {
return nil, err
}

newItem := &Item{
name: name,
container: c,
client: c.client,
size: size,
etag: res.Etag,
hash: res.Md5Hash,
lastModified: t,
url: u,
metadata: mdParsed,
object: res,
}
return newItem, nil
return c.Item(name)
}

func parseMetadata(metadataParsed map[string]string) (map[string]interface{}, error) {
Expand Down
22 changes: 8 additions & 14 deletions google/item.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
package google

import (
"context"
"io"
"net/url"

// "strings"
"time"

storage "google.golang.org/api/storage/v1"
"cloud.google.com/go/storage"
)

type Item struct {
container *Container // Container information is required by a few methods.
client *storage.Service // A client is needed to make requests.
container *Container // Container information is required by a few methods.
client *storage.Client // A client is needed to make requests.
name string
hash string
etag string
size int64
url *url.URL
lastModified time.Time
metadata map[string]interface{}
object *storage.Object
object *storage.ObjectHandle
}

// ID returns a string value that represents the name of a file.
Expand All @@ -45,12 +44,7 @@ func (i *Item) URL() *url.URL {

// Open returns an io.ReadCloser to the object. Useful for downloading/streaming the object.
func (i *Item) Open() (io.ReadCloser, error) {
res, err := i.client.Objects.Get(i.container.name, i.name).Download()
if err != nil {
return nil, err
}

return res.Body, nil
return i.container.Bucket().Object(i.name).NewReader(context.Background())
}

// LastMod returns the last modified date of the item.
Expand All @@ -70,7 +64,7 @@ func (i *Item) ETag() (string, error) {
}

// Object returns the Google Storage Object
func (i *Item) StorageObject() *storage.Object {
func (i *Item) StorageObject() *storage.ObjectHandle {
return i.object
}

Expand All @@ -80,7 +74,7 @@ func prepUrl(str string) (*url.URL, error) {
if err != nil {
return nil, err
}
u.Scheme = "google"
u.Scheme = "gs"

// Discard the query string
u.RawQuery = ""
Expand Down
Loading