|
|
@@ -22,6 +22,8 @@ import ( |
|
|
|
"golang.org/x/oauth2/google" |
|
|
|
"google.golang.org/api/drive/v3" |
|
|
|
"google.golang.org/api/googleapi" |
|
|
|
"storj.io/storj/lib/uplink" |
|
|
|
"storj.io/storj/pkg/storj" |
|
|
|
) |
|
|
|
|
|
|
|
type Storage interface { |
|
|
@@ -561,3 +563,104 @@ func saveGDriveToken(path string, token *oauth2.Token, logger *log.Logger) { |
|
|
|
|
|
|
|
json.NewEncoder(f).Encode(token) |
|
|
|
} |
|
|
|
|
|
|
|
type StorjStorage struct { |
|
|
|
Storage |
|
|
|
uplink *uplink.Uplink |
|
|
|
project *uplink.Project |
|
|
|
bucket *uplink.Bucket |
|
|
|
logger *log.Logger |
|
|
|
} |
|
|
|
|
|
|
|
func NewStorjStorage(endpoint, apiKey, bucket, encKey string) (*StorjStorage, error) { |
|
|
|
var instance StorjStorage |
|
|
|
var err error |
|
|
|
|
|
|
|
ctx := context.Background() |
|
|
|
|
|
|
|
instance.uplink, err = uplink.NewUplink(ctx, nil) |
|
|
|
if err != nil { |
|
|
|
return nil, fmt.Errorf("could not create new Uplink Instance: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
key, err := uplink.ParseAPIKey(apiKey) |
|
|
|
if err != nil { |
|
|
|
return nil, fmt.Errorf("could not parse api key %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
instance.project, err = instance.uplink.OpenProject(ctx, endpoint, key) |
|
|
|
if err != nil { |
|
|
|
return nil, fmt.Errorf("could not open project: %v", err) |
|
|
|
} |
|
|
|
|
|
|
|
access := uplink.NewEncryptionAccessWithDefaultKey(toStorjKey(encKey)) |
|
|
|
instance.bucket, err = instance.project.OpenBucket(ctx, bucket, access) |
|
|
|
if err != nil { |
|
|
|
return nil, fmt.Errorf("could not open bucket %q: %v", bucket, err) |
|
|
|
} |
|
|
|
|
|
|
|
return &instance, nil |
|
|
|
} |
|
|
|
|
|
|
|
func (s *StorjStorage) Type() string { |
|
|
|
return "storj" |
|
|
|
} |
|
|
|
|
|
|
|
func (s *StorjStorage) Head(token string, filename string) (contentType string, contentLength uint64, err error) { |
|
|
|
key := fmt.Sprintf("%s/%s", token, filename) |
|
|
|
|
|
|
|
ctx := context.TODO() |
|
|
|
|
|
|
|
obj, err := s.bucket.OpenObject(ctx, key) |
|
|
|
if err != nil { |
|
|
|
return "", 0, fmt.Errorf("unable to open object %v", err) |
|
|
|
} |
|
|
|
contentType = obj.Meta.ContentType |
|
|
|
contentLength = uint64(obj.Meta.Size) |
|
|
|
|
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
func (s *StorjStorage) Get(token string, filename string) (reader io.ReadCloser, contentType string, contentLength uint64, err error) { |
|
|
|
key := fmt.Sprintf("%s/%s", token, filename) |
|
|
|
ctx := context.TODO() |
|
|
|
|
|
|
|
obj, err := s.bucket.OpenObject(ctx, key) |
|
|
|
if err != nil { |
|
|
|
return nil, "", 0, fmt.Errorf("unable to open object %v", err) |
|
|
|
} |
|
|
|
contentType = obj.Meta.ContentType |
|
|
|
contentLength = uint64(obj.Meta.Size) |
|
|
|
reader, err = obj.DownloadRange(ctx, 0, -1) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
func (s *StorjStorage) Delete(token string, filename string) (err error) { |
|
|
|
key := fmt.Sprintf("%s/%s", token, filename) |
|
|
|
|
|
|
|
ctx := context.TODO() |
|
|
|
|
|
|
|
err = s.bucket.DeleteObject(ctx, key) |
|
|
|
|
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
func (s *StorjStorage) Put(token string, filename string, reader io.Reader, contentType string, contentLength uint64) (err error) { |
|
|
|
key := fmt.Sprintf("%s/%s", token, filename) |
|
|
|
|
|
|
|
s.logger.Printf("Uploading file %s to S3 Bucket", filename) |
|
|
|
|
|
|
|
ctx := context.TODO() |
|
|
|
|
|
|
|
err = s.bucket.UploadObject(ctx, key, reader, &uplink.UploadOptions{ContentType: contentType}) |
|
|
|
if err != nil { |
|
|
|
return fmt.Errorf("could not upload: %v", err) |
|
|
|
} |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
func toStorjKey(key string) (newKey storj.Key) { |
|
|
|
var encryptionKey storj.Key |
|
|
|
copy(encryptionKey[:], []byte(key)) |
|
|
|
return encryptionKey |
|
|
|
} |