go.temporal.io/server@v1.23.0/common/archiver/gcloud/connector/client_delegate.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  //go:generate mockgen -copyright_file ../../../../LICENSE -package $GOPACKAGE -source $GOFILE -destination client_delegate_mock.go
    26  
    27  package connector
    28  
    29  import (
    30  	"context"
    31  	"os"
    32  
    33  	"cloud.google.com/go/storage"
    34  	"golang.org/x/oauth2/google"
    35  	"google.golang.org/api/option"
    36  )
    37  
    38  type (
    39  	// GcloudStorageClient is an interface that expose some methods from gcloud storage client
    40  	GcloudStorageClient interface {
    41  		Bucket(URI string) BucketHandleWrapper
    42  	}
    43  
    44  	clientDelegate struct {
    45  		nativeClient *storage.Client
    46  	}
    47  )
    48  
    49  type (
    50  	// BucketHandleWrapper is an interface that expose some methods from gcloud storage bucket
    51  	BucketHandleWrapper interface {
    52  		Object(name string) ObjectHandleWrapper
    53  		Objects(ctx context.Context, q *storage.Query) ObjectIteratorWrapper
    54  		Attrs(ctx context.Context) (*storage.BucketAttrs, error)
    55  	}
    56  
    57  	bucketDelegate struct {
    58  		bucket *storage.BucketHandle
    59  	}
    60  )
    61  
    62  type (
    63  	// ObjectHandleWrapper is an interface that expose some methods from gcloud storage object
    64  	ObjectHandleWrapper interface {
    65  		NewWriter(ctx context.Context) WriterWrapper
    66  		NewReader(ctx context.Context) (ReaderWrapper, error)
    67  		Attrs(ctx context.Context) (*storage.ObjectAttrs, error)
    68  	}
    69  
    70  	objectDelegate struct {
    71  		object *storage.ObjectHandle
    72  	}
    73  )
    74  
    75  type (
    76  	// WriterWrapper is an interface that expose some methods from gcloud storage writer
    77  	WriterWrapper interface {
    78  		Close() error
    79  		Write(p []byte) (n int, err error)
    80  		CloseWithError(err error) error
    81  	}
    82  
    83  	writerDelegate struct {
    84  		writer *storage.Writer
    85  	}
    86  )
    87  
    88  type (
    89  	// ReaderWrapper is an interface that expose some methods from gcloud storage reader
    90  	ReaderWrapper interface {
    91  		Close() error
    92  		Read(p []byte) (int, error)
    93  	}
    94  
    95  	readerDelegate struct {
    96  		reader *storage.Reader
    97  	}
    98  )
    99  
   100  type (
   101  	// ObjectIteratorWrapper is an interface that expose some methods from gcloud storage objectIterator
   102  	ObjectIteratorWrapper interface {
   103  		Next() (*storage.ObjectAttrs, error)
   104  	}
   105  )
   106  
   107  func newDefaultClientDelegate(ctx context.Context) (*clientDelegate, error) {
   108  	nativeClient, err := storage.NewClient(ctx)
   109  	return &clientDelegate{nativeClient: nativeClient}, err
   110  }
   111  
   112  func newClientDelegateWithCredentials(ctx context.Context, credentialsPath string) (*clientDelegate, error) {
   113  
   114  	jsonKey, err := os.ReadFile(credentialsPath)
   115  	if err != nil {
   116  		return newDefaultClientDelegate(ctx)
   117  	}
   118  
   119  	conf, err := google.JWTConfigFromJSON(jsonKey, storage.ScopeFullControl)
   120  	if err != nil {
   121  		return newDefaultClientDelegate(ctx)
   122  	}
   123  
   124  	nativeClient, err := storage.NewClient(ctx, option.WithTokenSource(conf.TokenSource(ctx)))
   125  	return &clientDelegate{nativeClient: nativeClient}, err
   126  }
   127  
   128  // Bucket returns a BucketHandle, which provides operations on the named bucket.
   129  // This call does not perform any network operations.
   130  //
   131  // The supplied name must contain only lowercase letters, numbers, dashes,
   132  // underscores, and dots. The full specification for valid bucket names can be
   133  // found at:
   134  //
   135  //	https://cloud.google.com/storage/docs/bucket-naming
   136  func (c *clientDelegate) Bucket(bucketName string) BucketHandleWrapper {
   137  	return &bucketDelegate{bucket: c.nativeClient.Bucket(bucketName)}
   138  }
   139  
   140  // Object returns an ObjectHandle, which provides operations on the named object.
   141  // This call does not perform any network operations.
   142  //
   143  // name must consist entirely of valid UTF-8-encoded runes. The full specification
   144  // for valid object names can be found at:
   145  //
   146  //	https://cloud.google.com/storage/docs/bucket-naming
   147  func (b *bucketDelegate) Object(name string) ObjectHandleWrapper {
   148  	return &objectDelegate{object: b.bucket.Object(name)}
   149  }
   150  
   151  // Objects returns an iterator over the objects in the bucket that match the Query q.
   152  // If q is nil, no filtering is done.
   153  func (b *bucketDelegate) Objects(ctx context.Context, q *storage.Query) ObjectIteratorWrapper {
   154  	return b.bucket.Objects(ctx, q)
   155  }
   156  
   157  // Attrs returns the metadata for the bucket.
   158  func (b *bucketDelegate) Attrs(ctx context.Context) (*storage.BucketAttrs, error) {
   159  	return b.bucket.Attrs(ctx)
   160  }
   161  
   162  // NewWriter returns a storage Writer that writes to the GCS object
   163  // associated with this ObjectHandle.
   164  //
   165  // A new object will be created unless an object with this name already exists.
   166  // Otherwise any previous object with the same name will be replaced.
   167  // The object will not be available (and any previous object will remain)
   168  // until Close has been called.
   169  //
   170  // Attributes can be set on the object by modifying the returned Writer's
   171  // ObjectAttrs field before the first call to Write. If no ContentType
   172  // attribute is specified, the content type will be automatically sniffed
   173  // using net/http.DetectContentType.
   174  //
   175  // It is the caller's responsibility to call Close when writing is done. To
   176  // stop writing without saving the data, cancel the context.
   177  func (o *objectDelegate) NewWriter(ctx context.Context) WriterWrapper {
   178  	return &writerDelegate{writer: o.object.NewWriter(ctx)}
   179  }
   180  
   181  // NewReader creates a new Reader to read the contents of the
   182  // object.
   183  // ErrObjectNotExist will be returned if the object is not found.
   184  //
   185  // The caller must call Close on the returned Reader when done reading.
   186  func (o *objectDelegate) NewReader(ctx context.Context) (ReaderWrapper, error) {
   187  	r, err := o.object.NewReader(ctx)
   188  	return &readerDelegate{reader: r}, err
   189  }
   190  
   191  func (o *objectDelegate) Attrs(ctx context.Context) (attrs *storage.ObjectAttrs, err error) {
   192  	return o.object.Attrs(ctx)
   193  }
   194  
   195  // Close completes the write operation and flushes any buffered data.
   196  // If Close doesn't return an error, metadata about the written object
   197  // can be retrieved by calling Attrs.
   198  func (w *writerDelegate) Close() error {
   199  	return w.writer.Close()
   200  }
   201  
   202  // Write appends to w. It implements the io.Writer interface.
   203  //
   204  // Since writes happen asynchronously, Write may return a nil
   205  // error even though the write failed (or will fail). Always
   206  // use the error returned from Writer.Close to determine if
   207  // the upload was successful.
   208  func (w *writerDelegate) Write(p []byte) (int, error) {
   209  	return w.writer.Write(p)
   210  }
   211  
   212  // CloseWithError aborts the write operation with the provided error.
   213  // CloseWithError always returns nil.
   214  //
   215  // Deprecated: cancel the context passed to NewWriter instead.
   216  func (w *writerDelegate) CloseWithError(err error) error {
   217  	return w.writer.CloseWithError(err)
   218  }
   219  
   220  // Close closes the Reader. It must be called when done reading.
   221  func (r *readerDelegate) Close() error {
   222  	return r.reader.Close()
   223  }
   224  
   225  func (r *readerDelegate) Read(p []byte) (int, error) {
   226  	return r.reader.Read(p)
   227  
   228  }