Skip to content

Commit

Permalink
chore(storage): internal client interface design (#5426)
Browse files Browse the repository at this point in the history
  • Loading branch information
noahdietz committed Feb 22, 2022
1 parent bd2c600 commit 9775203
Showing 1 changed file with 182 additions and 0 deletions.
182 changes: 182 additions & 0 deletions storage/client.go
@@ -0,0 +1,182 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package storage

import (
"context"

gax "github.com/googleapis/gax-go/v2"
iampb "google.golang.org/genproto/googleapis/iam/v1"
)

// TODO(noahdietz): Move existing factory methods to this file.

// storageClient is an internal-only interface designed to separate the
// transport-specific logic of making Storage API calls from the logic of the
// client library.
//
// Implementation requirements beyond implementing the interface include:
// * factory method(s) must accept a `userProject string` param
// * `settings` must be retained per instance
// * `storageOption`s must be resolved in the order they are received
// * all API errors must be wrapped in the gax-go APIError type
// * any unimplemented interface methods must return a StorageUnimplementedErr
//
// TODO(noahdietz): This interface is currently not used in the production code
// paths
type storageClient interface {

// Top-level methods.

GetServiceAccount(ctx context.Context, project string, opts ...storageOption) (string, error)
CreateBucket(ctx context.Context, project string, attrs *BucketAttrs, opts ...storageOption) (*BucketAttrs, error)
ListBuckets(ctx context.Context, project string, opts ...storageOption) (BucketIterator, error)

// Bucket methods.

DeleteBucket(ctx context.Context, bucket string, conds *BucketConditions, opts ...storageOption) error
GetBucket(ctx context.Context, bucket string, conds *BucketConditions, opts ...storageOption) (*BucketAttrs, error)
UpdateBucket(ctx context.Context, uattrs *BucketAttrsToUpdate, conds *BucketConditions, opts ...storageOption) (*BucketAttrs, error)
LockBucketRetentionPolicy(ctx context.Context, bucket string, conds *BucketConditions, opts ...storageOption) error
ListObjects(ctx context.Context, bucket string, q *Query, opts ...storageOption) (*ObjectIterator, error)

// Object metadata methods.

DeleteObject(ctx context.Context, bucket, object string, conds *Conditions, opts ...storageOption) error
GetObject(ctx context.Context, bucket, object string, conds *Conditions, opts ...storageOption) (*ObjectAttrs, error)
UpdateObject(ctx context.Context, bucket, object string, uattrs *ObjectAttrsToUpdate, conds *Conditions, opts ...storageOption) (*ObjectAttrs, error)

// Default Object ACL methods.

DeleteDefaultObjectACL(ctx context.Context, bucket string, entity ACLEntity, opts ...storageOption) error
ListDefaultObjectACLs(ctx context.Context, bucket string, opts ...storageOption) ([]ACLRule, error)
UpdateDefaultObjectACL(ctx context.Context, opts ...storageOption) (ACLRule, error)

// Bucket ACL methods.

DeleteBucketACL(ctx context.Context, bucket string, entity ACLEntity, opts ...storageOption) error
ListBucketACLs(ctx context.Context, bucket string, opts ...storageOption) ([]ACLRule, error)
UpdateBucketACL(ctx context.Context, bucket string, entity ACLEntity, role ACLRole, opts ...storageOption) (ACLRule, error)

// Object ACL methods.

DeleteObjectACL(ctx context.Context, bucket, object string, entity ACLEntity, opts ...storageOption) error
ListObjectACLs(ctx context.Context, bucket, object string, opts ...storageOption) ([]ACLRule, error)
UpdateObjectACL(ctx context.Context, bucket, object string, entity ACLEntity, role ACLRole, opts ...storageOption) (ACLRule, error)

// Media operations.

ComposeObject(ctx context.Context, req *composeObjectRequest, opts ...storageOption) (*ObjectAttrs, error)
RewriteObject(ctx context.Context, req *rewriteObjectRequest, opts ...storageOption) (*rewriteObjectResponse, error)

OpenReader(ctx context.Context, r *Reader, opts ...storageOption) error
OpenWriter(ctx context.Context, w *Writer, opts ...storageOption) error

// IAM methods.

GetIamPolicy(ctx context.Context, resource string, version int32, opts ...storageOption) (*iampb.Policy, error)
SetIamPolicy(ctx context.Context, resource string, policy *iampb.Policy, opts ...storageOption) error
TestIamPermissions(ctx context.Context, resource string, permissions []string, opts ...storageOption) ([]string, error)

// HMAC Key methods.

GetHMACKey(ctx context.Context, desc *hmacKeyDesc, opts ...storageOption) (*HMACKey, error)
ListHMACKey(ctx context.Context, desc *hmacKeyDesc, opts ...storageOption) *HMACKeysIterator
UpdateHMACKey(ctx context.Context, desc *hmacKeyDesc, attrs *HMACKeyAttrsToUpdate, opts ...storageOption) (*HMACKey, error)
CreateHMACKey(ctx context.Context, desc *hmacKeyDesc, opts ...storageOption) (*HMACKey, error)
DeleteHMACKey(ctx context.Context, desc *hmacKeyDesc, opts ...storageOption) error
}

// settings contains transport-agnostic configuration for API calls made via
// the storageClient inteface. All implementations must utilize settings
// and respect those that are applicable.
type settings struct {
// retry is the complete retry configuration to use when evaluating if an
// API call should be retried.
retry *retryConfig

// gax is a set of gax.CallOption to be conveyed to gax.Invoke.
// Note: Not all storageClient interfaces will must use gax.Invoke.
gax []gax.CallOption

// idempotent indicates if the call is idempotent or not when considering
// if the call should be retired or not.
idempotent bool
}

// storageOption is the transport-agnostic call option for the storageClient
// interface.
type storageOption interface {
Apply(s *settings)
}

func withGAXOptions(opts ...gax.CallOption) storageOption {
return &gaxOption{opts}
}

type gaxOption struct {
opts []gax.CallOption
}

func (o *gaxOption) Apply(s *settings) { s.gax = o.opts }

func withRetryConfig(rc *retryConfig) storageOption {
return &retryOption{rc}
}

type retryOption struct {
rc *retryConfig
}

func (o *retryOption) Apply(s *settings) { s.retry = o.rc }

func idempotent(i bool) storageOption {
return &idempotentOption{i}
}

type idempotentOption struct {
idempotency bool
}

func (o *idempotentOption) Apply(s *settings) { s.idempotent = o.idempotency }

type composeObjectRequest struct {
dstBucket string
dstObject string
srcs []string
gen int64
conds *Conditions
predefinedACL string
}

type rewriteObjectRequest struct {
srcBucket string
srcObject string
dstBucket string
dstObject string
dstKeyName string
attrs *ObjectAttrs
gen int64
conds *Conditions
predefinedACL string
token string
}

type rewriteObjectResponse struct {
resource *ObjectAttrs
done bool
written int64
token string
}

0 comments on commit 9775203

Please sign in to comment.