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 }