mirror of
https://github.com/jkaninda/go-storage.git
synced 2026-03-11 03:59:03 +01:00
feat: add gsc and go_storage package
This commit is contained in:
156
gcs.go
Normal file
156
gcs.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package go_storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"cloud.google.com/go/storage"
|
||||
"google.golang.org/api/iterator"
|
||||
"google.golang.org/api/option"
|
||||
)
|
||||
|
||||
// GCSStorage implements Storage interface for Google Cloud Storage.
|
||||
type GCSStorage struct {
|
||||
client *storage.Client
|
||||
bucket string
|
||||
}
|
||||
|
||||
// NewGCSStorage creates a new Google Cloud Storage instance.
|
||||
func NewGCSStorage(config Config) (*GCSStorage, error) {
|
||||
if err := validateConfig(config, map[string]string{
|
||||
"bucket": config.GCSBucket,
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("gcs: %w", err)
|
||||
}
|
||||
|
||||
options := make([]option.ClientOption, 0)
|
||||
|
||||
if config.GCSEndpoint != "" {
|
||||
options = append(options, option.WithEndpoint(config.GCSEndpoint))
|
||||
}
|
||||
|
||||
if config.GCSCredentialsFile != "" {
|
||||
options = append(options, option.WithCredentialsFile(config.GCSCredentialsFile))
|
||||
}
|
||||
|
||||
client, err := storage.NewClient(context.Background(), options...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("gcs: failed to create client: %w", err)
|
||||
}
|
||||
|
||||
return &GCSStorage{
|
||||
client: client,
|
||||
bucket: config.GCSBucket,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Upload uploads a file to GCS.
|
||||
func (g *GCSStorage) Upload(ctx context.Context, localPath string, remotePath string) error {
|
||||
file, err := os.Open(localPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("gcs: failed to open local file: %w", err)
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err = file.Close()
|
||||
if err != nil {
|
||||
fmt.Printf("gcs: failed to close file: %v\n", err)
|
||||
}
|
||||
}(file)
|
||||
|
||||
obj := g.client.Bucket(g.bucket).Object(normalizePathSeparators(remotePath)).NewWriter(ctx)
|
||||
defer func(obj *storage.Writer) {
|
||||
err = obj.Close()
|
||||
if err != nil {
|
||||
fmt.Printf("gcs: failed to close object writer: %v\n", err)
|
||||
}
|
||||
}(obj)
|
||||
|
||||
if _, err := io.Copy(obj, file); err != nil {
|
||||
return fmt.Errorf("gcs: failed to write data: %w", err)
|
||||
}
|
||||
|
||||
if err = obj.Close(); err != nil {
|
||||
return fmt.Errorf("gcs: failed to finalize upload: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Download downloads a file from GCS.
|
||||
func (g *GCSStorage) Download(ctx context.Context, remotePath string, localPath string) error {
|
||||
file, err := os.Create(localPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("gcs: failed to create local file: %w", err)
|
||||
}
|
||||
defer func(file *os.File) {
|
||||
err = file.Close()
|
||||
if err != nil {
|
||||
fmt.Printf("gcs: failed to close file: %v\n", err)
|
||||
}
|
||||
}(file)
|
||||
|
||||
obj, err := g.client.Bucket(g.bucket).Object(normalizePathSeparators(remotePath)).NewReader(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("gcs: failed to create reader: %w", err)
|
||||
}
|
||||
defer func(obj *storage.Reader) {
|
||||
err = obj.Close()
|
||||
if err != nil {
|
||||
fmt.Printf("gcs: failed to close object reader: %v\n", err)
|
||||
}
|
||||
}(obj)
|
||||
|
||||
if _, err = io.Copy(file, obj); err != nil {
|
||||
return fmt.Errorf("gcs: failed to read data: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// List lists objects in GCS with the given prefix.
|
||||
func (g *GCSStorage) List(ctx context.Context, prefix string) ([]Item, error) {
|
||||
items := make([]Item, 0)
|
||||
|
||||
query := &storage.Query{
|
||||
Prefix: normalizePathSeparators(prefix),
|
||||
}
|
||||
|
||||
it := g.client.Bucket(g.bucket).Objects(ctx, query)
|
||||
|
||||
for {
|
||||
attrs, err := it.Next()
|
||||
if err == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("gcs: failed to iterate objects: %w", err)
|
||||
}
|
||||
|
||||
items = append(items, Item{
|
||||
Key: attrs.Name,
|
||||
ModifiedTime: attrs.Updated,
|
||||
Size: attrs.Size,
|
||||
IsDirectory: false,
|
||||
})
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// Remove deletes an object from GCS.
|
||||
func (g *GCSStorage) Remove(ctx context.Context, remotePath string) error {
|
||||
obj := g.client.Bucket(g.bucket).Object(normalizePathSeparators(remotePath))
|
||||
|
||||
if err := obj.Delete(ctx); err != nil {
|
||||
return fmt.Errorf("gcs: failed to remove object from bucket %s: %w", g.bucket, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close releases resources.
|
||||
func (g *GCSStorage) Close() error {
|
||||
return g.client.Close()
|
||||
}
|
||||
Reference in New Issue
Block a user