github.com/cozy/cozy-stack@v0.0.0-20240327093429-939e4a21320e/pkg/assets/dynamic/impl_swift.go (about)

     1  package dynamic
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"path"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/cozy/cozy-stack/pkg/assets/model"
    12  	"github.com/cozy/cozy-stack/pkg/config/config"
    13  	"github.com/ncw/swift/v2"
    14  )
    15  
    16  // DynamicAssetsContainerName is the Swift container name for dynamic assets
    17  const DynamicAssetsContainerName = "__dyn-assets__"
    18  
    19  // SwiftFS is the Swift implementation of [AssetsFS].
    20  //
    21  // It save and fetch assets into/from any OpenStack Swift compatible API.
    22  type SwiftFS struct {
    23  	swiftConn *swift.Connection
    24  	ctx       context.Context
    25  }
    26  
    27  // NewSwiftFS instantiate a new SwiftFS.
    28  func NewSwiftFS() (*SwiftFS, error) {
    29  	ctx := context.Background()
    30  	swiftFS := &SwiftFS{swiftConn: config.GetSwiftConnection(), ctx: ctx}
    31  	err := swiftFS.swiftConn.ContainerCreate(ctx, DynamicAssetsContainerName, nil)
    32  	if err != nil {
    33  		return nil, fmt.Errorf("Cannot create container for dynamic assets: %s", err)
    34  	}
    35  
    36  	return swiftFS, nil
    37  }
    38  
    39  func (s *SwiftFS) Add(context, name string, asset *model.Asset) error {
    40  	objectName := path.Join(asset.Context, asset.Name)
    41  	swiftConn := s.swiftConn
    42  	f, err := swiftConn.ObjectCreate(s.ctx, DynamicAssetsContainerName, objectName, true, "", "", nil)
    43  	if err != nil {
    44  		return err
    45  	}
    46  
    47  	// Writing the asset content to Swift
    48  	_, err = f.Write(asset.GetData())
    49  	if err != nil {
    50  		return err
    51  	}
    52  	return f.Close()
    53  }
    54  
    55  func (s *SwiftFS) Get(context, name string) ([]byte, error) {
    56  	objectName := path.Join(context, name)
    57  	assetContent := new(bytes.Buffer)
    58  
    59  	_, err := s.swiftConn.ObjectGet(s.ctx, DynamicAssetsContainerName, objectName, assetContent, true, nil)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  
    64  	return assetContent.Bytes(), nil
    65  }
    66  
    67  func (s *SwiftFS) Remove(context, name string) error {
    68  	objectName := path.Join(context, name)
    69  
    70  	return s.swiftConn.ObjectDelete(s.ctx, DynamicAssetsContainerName, objectName)
    71  }
    72  
    73  func (s *SwiftFS) List() (map[string][]*model.Asset, error) {
    74  	objs := map[string][]*model.Asset{}
    75  
    76  	opts := &swift.ObjectsOpts{Limit: 10_000}
    77  	objNames, err := s.swiftConn.ObjectNamesAll(s.ctx, DynamicAssetsContainerName, opts)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	for _, obj := range objNames {
    83  		splitted := strings.SplitN(obj, "/", 2)
    84  		ctx := splitted[0]
    85  		assetName := model.NormalizeAssetName(splitted[1])
    86  
    87  		a, err := GetAsset(ctx, assetName)
    88  		if err != nil {
    89  			return nil, err
    90  		}
    91  
    92  		objs[ctx] = append(objs[ctx], a)
    93  	}
    94  
    95  	return objs, nil
    96  }
    97  
    98  func (s *SwiftFS) CheckStatus(ctx context.Context) (time.Duration, error) {
    99  	before := time.Now()
   100  	var err error
   101  	if config.GetConfig().Fs.CanQueryInfo {
   102  		_, err = s.swiftConn.QueryInfo(ctx)
   103  	} else {
   104  		_, _, err = s.swiftConn.Container(ctx, DynamicAssetsContainerName)
   105  	}
   106  	if err != nil {
   107  		return 0, err
   108  	}
   109  	return time.Since(before), nil
   110  }