Files
files/internal/storage/aliyun/object.go
2026-09-09 16:42:21 +08:00

100 lines
3.0 KiB
Go

package aliyun
import (
"context"
"errors"
"fmt"
"io"
"strings"
"git.apinb.com/ops/files/internal/storage"
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
)
// Open 返回对象存储中的只读内容流。
func (c *Client) Open(ctx context.Context, objectKey string, byteRange *storage.ByteRange) (io.ReadCloser, error) {
if strings.TrimSpace(objectKey) == "" {
return nil, fmt.Errorf("对象键不能为空")
}
request := &oss.GetObjectRequest{
Bucket: oss.Ptr(c.bucket),
Key: oss.Ptr(objectKey),
}
if byteRange != nil {
rangeHeader := fmt.Sprintf("bytes=%d-%d", byteRange.Start, byteRange.End)
request.Range = &rangeHeader
}
result, err := c.client.GetObject(ctx, request)
if err != nil {
return nil, fmt.Errorf("读取对象: %w", err)
}
if result == nil || result.Body == nil {
return nil, fmt.Errorf("对象内容为空")
}
return result.Body, nil
}
func (c *Client) Stat(ctx context.Context, objectKey string) (storage.ObjectInfo, error) {
if strings.TrimSpace(objectKey) == "" {
return storage.ObjectInfo{}, fmt.Errorf("对象键不能为空")
}
result, err := c.client.GetObjectMeta(ctx, &oss.GetObjectMetaRequest{
Bucket: oss.Ptr(c.bucket),
Key: oss.Ptr(objectKey),
})
if err != nil {
var serviceError *oss.ServiceError
if errors.As(err, &serviceError) && serviceError.Code == "NoSuchKey" {
return storage.ObjectInfo{}, storage.ErrObjectNotFound
}
return storage.ObjectInfo{}, fmt.Errorf("查询对象元数据: %w", err)
}
if result == nil {
return storage.ObjectInfo{}, fmt.Errorf("对象元数据为空")
}
if result.ContentLength < 0 {
return storage.ObjectInfo{}, fmt.Errorf("对象大小无效: %d", result.ContentLength)
}
if result.ETag == nil {
return storage.ObjectInfo{}, fmt.Errorf("对象 ETag 缺失")
}
etag := strings.TrimSpace(strings.Trim(strings.TrimSpace(*result.ETag), "\""))
if etag == "" {
return storage.ObjectInfo{}, fmt.Errorf("对象 ETag 无效")
}
if result.LastModified == nil || result.LastModified.IsZero() {
return storage.ObjectInfo{}, fmt.Errorf("对象最后修改时间缺失")
}
return storage.ObjectInfo{
Size: result.ContentLength,
StorageETag: etag,
LastModified: *result.LastModified,
}, nil
}
func (c *Client) Delete(ctx context.Context, objectKey string) error {
if strings.TrimSpace(objectKey) == "" {
return fmt.Errorf("对象键不能为空")
}
_, err := c.client.DeleteObject(ctx, &oss.DeleteObjectRequest{
Bucket: oss.Ptr(c.bucket),
Key: oss.Ptr(objectKey),
})
if err != nil {
return fmt.Errorf("删除对象: %w", err)
}
return nil
}
func (c *Client) Status(ctx context.Context) (storage.RuntimeStatus, error) {
_, err := c.client.ListObjectsV2(ctx, &oss.ListObjectsV2Request{Bucket: oss.Ptr(c.bucket), MaxKeys: 1})
if err != nil {
return storage.RuntimeStatus{Provider: c.Provider(), Container: c.Container()}, fmt.Errorf("检查 OSS 存储状态: %w", err)
}
return storage.RuntimeStatus{Provider: c.Provider(), Container: c.Container(), Writable: true}, nil
}