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) {
continue
}
file := model.Object{
file := &model.Object{
//Id: *object.Key,
Name: name,
Size: *object.Size,
Modified: *object.LastModified,
}
files = append(files, &file)
files = append(files, model.WrapObjStorageClass(file, aws.StringValue(object.StorageClass)))
}
if listObjectsResult.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) {
continue
}
file := model.Object{
file := &model.Object{
//Id: *object.Key,
Name: name,
Size: *object.Size,
Modified: *object.LastModified,
}
files = append(files, &file)
files = append(files, model.WrapObjStorageClass(file, aws.StringValue(object.StorageClass)))
}
if !aws.BoolValue(listObjectsResult.IsTruncated) {
break

View File

@ -20,6 +20,10 @@ type ObjUnwrap interface {
Unwrap() Obj
}
type StorageClassProvider interface {
StorageClass() string
}
type Obj interface {
GetSize() int64
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 {
if unwrap, ok := obj.(ObjUnwrap); ok {
obj = unwrap.Unwrap()
@ -168,6 +179,20 @@ func GetUrl(obj Obj) (url string, ok bool) {
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 {
switch v := obj.(type) {
case *ObjThumbURL:

View File

@ -11,6 +11,11 @@ type ObjWrapName struct {
Obj
}
type ObjWrapStorageClass struct {
storageClass string
Obj
}
func (o *ObjWrapName) Unwrap() Obj {
return o.Obj
}
@ -19,6 +24,20 @@ func (o *ObjWrapName) GetName() string {
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 {
ID string
Path string

View File

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

View File

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