feat(storage): Support for displaying file storage classes

Adds storage class information to file metadata and API responses.

This change introduces the ability to store file storage classes in file metadata and display them in API responses. This allows users to view a file's storage tier (e.g., S3 Standard, Glacier), enhancing data management capabilities.

Implementation details include:
- Introducing the StorageClassProvider interface and the ObjWrapStorageClass structure to uniformly handle and communicate object storage class information.
- Updated file metadata structures (e.g., ArchiveObj, FileInfo, RespFile) to include a StorageClass field.
- Modified relevant API response functions (e.g., GetFileInfo, GetFileList) to populate and return storage classes.
- Integrated functionality for retrieving object storage classes from underlying storage systems (e.g., S3) and wrapping them in lists.
This commit is contained in:
okatu-loli 2025-10-15 15:59:55 +08:00
parent e673ae069b
commit a2be86c7c6
5 changed files with 116 additions and 64 deletions

View File

@ -109,13 +109,13 @@ func (d *S3) listV1(prefix string, args model.ListArgs) ([]model.Obj, error) {
if !args.S3ShowPlaceholder && (name == getPlaceholderName(d.Placeholder) || name == d.Placeholder) { if !args.S3ShowPlaceholder && (name == getPlaceholderName(d.Placeholder) || name == d.Placeholder) {
continue continue
} }
file := model.Object{ file := &model.Object{
//Id: *object.Key, //Id: *object.Key,
Name: name, Name: name,
Size: *object.Size, Size: *object.Size,
Modified: *object.LastModified, Modified: *object.LastModified,
} }
files = append(files, &file) files = append(files, model.WrapObjStorageClass(file, aws.StringValue(object.StorageClass)))
} }
if listObjectsResult.IsTruncated == nil { if listObjectsResult.IsTruncated == nil {
return nil, errors.New("IsTruncated nil") return nil, errors.New("IsTruncated nil")
@ -164,13 +164,13 @@ func (d *S3) listV2(prefix string, args model.ListArgs) ([]model.Obj, error) {
if !args.S3ShowPlaceholder && (name == getPlaceholderName(d.Placeholder) || name == d.Placeholder) { if !args.S3ShowPlaceholder && (name == getPlaceholderName(d.Placeholder) || name == d.Placeholder) {
continue continue
} }
file := model.Object{ file := &model.Object{
//Id: *object.Key, //Id: *object.Key,
Name: name, Name: name,
Size: *object.Size, Size: *object.Size,
Modified: *object.LastModified, Modified: *object.LastModified,
} }
files = append(files, &file) files = append(files, model.WrapObjStorageClass(file, aws.StringValue(object.StorageClass)))
} }
if !aws.BoolValue(listObjectsResult.IsTruncated) { if !aws.BoolValue(listObjectsResult.IsTruncated) {
break break

View File

@ -20,6 +20,10 @@ type ObjUnwrap interface {
Unwrap() Obj Unwrap() Obj
} }
type StorageClassProvider interface {
StorageClass() string
}
type Obj interface { type Obj interface {
GetSize() int64 GetSize() int64
GetName() string GetName() string
@ -141,6 +145,13 @@ func WrapObjsName(objs []Obj) {
} }
} }
func WrapObjStorageClass(obj Obj, storageClass string) Obj {
if storageClass == "" {
return obj
}
return &ObjWrapStorageClass{Obj: obj, storageClass: storageClass}
}
func UnwrapObj(obj Obj) Obj { func UnwrapObj(obj Obj) Obj {
if unwrap, ok := obj.(ObjUnwrap); ok { if unwrap, ok := obj.(ObjUnwrap); ok {
obj = unwrap.Unwrap() obj = unwrap.Unwrap()
@ -168,6 +179,20 @@ func GetUrl(obj Obj) (url string, ok bool) {
return url, false return url, false
} }
func GetStorageClass(obj Obj) (string, bool) {
if provider, ok := obj.(StorageClassProvider); ok {
value := provider.StorageClass()
if value == "" {
return "", false
}
return value, true
}
if unwrap, ok := obj.(ObjUnwrap); ok {
return GetStorageClass(unwrap.Unwrap())
}
return "", false
}
func GetRawObject(obj Obj) *Object { func GetRawObject(obj Obj) *Object {
switch v := obj.(type) { switch v := obj.(type) {
case *ObjThumbURL: case *ObjThumbURL:

View File

@ -11,6 +11,11 @@ type ObjWrapName struct {
Obj Obj
} }
type ObjWrapStorageClass struct {
storageClass string
Obj
}
func (o *ObjWrapName) Unwrap() Obj { func (o *ObjWrapName) Unwrap() Obj {
return o.Obj return o.Obj
} }
@ -19,6 +24,20 @@ func (o *ObjWrapName) GetName() string {
return o.Name return o.Name
} }
func (o *ObjWrapStorageClass) Unwrap() Obj {
return o.Obj
}
func (o *ObjWrapStorageClass) StorageClass() string {
return o.storageClass
}
func (o *ObjWrapStorageClass) SetPath(path string) {
if setter, ok := o.Obj.(SetPath); ok {
setter.SetPath(path)
}
}
type Object struct { type Object struct {
ID string ID string
Path string Path string

View File

@ -44,17 +44,19 @@ type ArchiveContentResp struct {
} }
func toObjsRespWithoutSignAndThumb(obj model.Obj) ObjResp { func toObjsRespWithoutSignAndThumb(obj model.Obj) ObjResp {
storageClass, _ := model.GetStorageClass(obj)
return ObjResp{ return ObjResp{
Name: obj.GetName(), Name: obj.GetName(),
Size: obj.GetSize(), Size: obj.GetSize(),
IsDir: obj.IsDir(), IsDir: obj.IsDir(),
Modified: obj.ModTime(), Modified: obj.ModTime(),
Created: obj.CreateTime(), Created: obj.CreateTime(),
HashInfoStr: obj.GetHash().String(), HashInfoStr: obj.GetHash().String(),
HashInfo: obj.GetHash().Export(), HashInfo: obj.GetHash().Export(),
Sign: "", Sign: "",
Thumb: "", Thumb: "",
Type: utils.GetObjType(obj.GetName(), obj.IsDir()), Type: utils.GetObjType(obj.GetName(), obj.IsDir()),
StorageClass: storageClass,
} }
} }

View File

@ -33,18 +33,19 @@ type DirReq struct {
} }
type ObjResp struct { type ObjResp struct {
Id string `json:"id"` Id string `json:"id"`
Path string `json:"path"` Path string `json:"path"`
Name string `json:"name"` Name string `json:"name"`
Size int64 `json:"size"` Size int64 `json:"size"`
IsDir bool `json:"is_dir"` IsDir bool `json:"is_dir"`
Modified time.Time `json:"modified"` Modified time.Time `json:"modified"`
Created time.Time `json:"created"` Created time.Time `json:"created"`
Sign string `json:"sign"` Sign string `json:"sign"`
Thumb string `json:"thumb"` Thumb string `json:"thumb"`
Type int `json:"type"` Type int `json:"type"`
HashInfoStr string `json:"hashinfo"` HashInfoStr string `json:"hashinfo"`
HashInfo map[*utils.HashType]string `json:"hash_info"` HashInfo map[*utils.HashType]string `json:"hash_info"`
StorageClass string `json:"storage_class,omitempty"`
} }
type FsListResp struct { type FsListResp struct {
@ -57,19 +58,20 @@ type FsListResp struct {
} }
type ObjLabelResp struct { type ObjLabelResp struct {
Id string `json:"id"` Id string `json:"id"`
Path string `json:"path"` Path string `json:"path"`
Name string `json:"name"` Name string `json:"name"`
Size int64 `json:"size"` Size int64 `json:"size"`
IsDir bool `json:"is_dir"` IsDir bool `json:"is_dir"`
Modified time.Time `json:"modified"` Modified time.Time `json:"modified"`
Created time.Time `json:"created"` Created time.Time `json:"created"`
Sign string `json:"sign"` Sign string `json:"sign"`
Thumb string `json:"thumb"` Thumb string `json:"thumb"`
Type int `json:"type"` Type int `json:"type"`
HashInfoStr string `json:"hashinfo"` HashInfoStr string `json:"hashinfo"`
HashInfo map[*utils.HashType]string `json:"hash_info"` HashInfo map[*utils.HashType]string `json:"hash_info"`
LabelList []model.Label `json:"label_list"` LabelList []model.Label `json:"label_list"`
StorageClass string `json:"storage_class,omitempty"`
} }
func FsList(c *gin.Context) { func FsList(c *gin.Context) {
@ -256,20 +258,22 @@ func toObjsResp(objs []model.Obj, parent string, encrypt bool) []ObjLabelResp {
labels = labelsByName[obj.GetName()] labels = labelsByName[obj.GetName()]
} }
thumb, _ := model.GetThumb(obj) thumb, _ := model.GetThumb(obj)
storageClass, _ := model.GetStorageClass(obj)
resp = append(resp, ObjLabelResp{ resp = append(resp, ObjLabelResp{
Id: obj.GetID(), Id: obj.GetID(),
Path: obj.GetPath(), Path: obj.GetPath(),
Name: obj.GetName(), Name: obj.GetName(),
Size: obj.GetSize(), Size: obj.GetSize(),
IsDir: obj.IsDir(), IsDir: obj.IsDir(),
Modified: obj.ModTime(), Modified: obj.ModTime(),
Created: obj.CreateTime(), Created: obj.CreateTime(),
HashInfoStr: obj.GetHash().String(), HashInfoStr: obj.GetHash().String(),
HashInfo: obj.GetHash().Export(), HashInfo: obj.GetHash().Export(),
Sign: common.Sign(obj, parent, encrypt), Sign: common.Sign(obj, parent, encrypt),
Thumb: thumb, Thumb: thumb,
Type: utils.GetObjType(obj.GetName(), obj.IsDir()), Type: utils.GetObjType(obj.GetName(), obj.IsDir()),
LabelList: labels, LabelList: labels,
StorageClass: storageClass,
}) })
} }
return resp return resp
@ -374,20 +378,22 @@ func FsGet(c *gin.Context) {
} }
parentMeta, _ := op.GetNearestMeta(parentPath) parentMeta, _ := op.GetNearestMeta(parentPath)
thumb, _ := model.GetThumb(obj) thumb, _ := model.GetThumb(obj)
storageClass, _ := model.GetStorageClass(obj)
common.SuccessResp(c, FsGetResp{ common.SuccessResp(c, FsGetResp{
ObjResp: ObjResp{ ObjResp: ObjResp{
Id: obj.GetID(), Id: obj.GetID(),
Path: obj.GetPath(), Path: obj.GetPath(),
Name: obj.GetName(), Name: obj.GetName(),
Size: obj.GetSize(), Size: obj.GetSize(),
IsDir: obj.IsDir(), IsDir: obj.IsDir(),
Modified: obj.ModTime(), Modified: obj.ModTime(),
Created: obj.CreateTime(), Created: obj.CreateTime(),
HashInfoStr: obj.GetHash().String(), HashInfoStr: obj.GetHash().String(),
HashInfo: obj.GetHash().Export(), HashInfo: obj.GetHash().Export(),
Sign: common.Sign(obj, parentPath, isEncrypt(meta, reqPath)), Sign: common.Sign(obj, parentPath, isEncrypt(meta, reqPath)),
Type: utils.GetFileType(obj.GetName()), Type: utils.GetFileType(obj.GetName()),
Thumb: thumb, Thumb: thumb,
StorageClass: storageClass,
}, },
RawURL: rawURL, RawURL: rawURL,
Readme: getReadme(meta, reqPath), Readme: getReadme(meta, reqPath),