diff --git a/pkg/services/oss_service.go b/pkg/services/oss_service.go index e72f9b0..cf09dfa 100755 --- a/pkg/services/oss_service.go +++ b/pkg/services/oss_service.go @@ -2,12 +2,30 @@ package services import ( "fmt" + "io" "log" + "time" "github.com/aliyun/aliyun-oss-go-sdk/oss" "github.com/sujit-baniya/fiber-boilerplate/pkg/models" ) +// OSSObject representa un objeto/archivo listado en el bucket +type OSSObject struct { + Key string `json:"key"` + Size int64 `json:"size"` + LastModified time.Time `json:"last_modified"` + ETag string `json:"etag"` +} + +// OSSListResult resultado paginado de listado de objetos +type OSSListResult struct { + Objects []OSSObject `json:"objects"` + CommonPrefixes []string `json:"prefixes"` // "carpetas" virtuales + IsTruncated bool `json:"is_truncated"` + NextMarker string `json:"next_marker"` +} + type OSSService struct { Client *oss.Client Bucket *oss.Bucket @@ -91,3 +109,77 @@ func (s *OSSService) DeleteFile(objectKey string) error { log.Printf("Archivo eliminado de OSS: %s", objectKey) return nil } + +// ListObjects lista objetos del bucket con soporte de prefijo (carpeta), delimitador y paginación. +func (s *OSSService) ListObjects(prefix, marker string, maxKeys int) (*OSSListResult, error) { + if maxKeys <= 0 || maxKeys > 1000 { + maxKeys = 100 + } + opts := []oss.Option{ + oss.MaxKeys(maxKeys), + oss.Delimiter("/"), + } + if prefix != "" { + opts = append(opts, oss.Prefix(prefix)) + } + if marker != "" { + opts = append(opts, oss.Marker(marker)) + } + + resp, err := s.Bucket.ListObjects(opts...) + if err != nil { + return nil, fmt.Errorf("error listando objetos OSS: %w", err) + } + + result := &OSSListResult{ + IsTruncated: resp.IsTruncated, + NextMarker: resp.NextMarker, + } + for _, obj := range resp.Objects { + result.Objects = append(result.Objects, OSSObject{ + Key: obj.Key, + Size: obj.Size, + LastModified: obj.LastModified, + ETag: obj.ETag, + }) + } + for _, cp := range resp.CommonPrefixes { + result.CommonPrefixes = append(result.CommonPrefixes, cp) + } + return result, nil +} + +// SignedURL genera una URL firmada temporal para descargar/previsualizar un objeto. +func (s *OSSService) SignedURL(objectKey string, expireSeconds int) (string, error) { + if expireSeconds <= 0 { + expireSeconds = 3600 + } + url, err := s.Bucket.SignURL(objectKey, oss.HTTPGet, int64(expireSeconds)) + if err != nil { + return "", fmt.Errorf("error generando URL firmada: %w", err) + } + return url, nil +} + +// UploadFromReader sube un archivo desde un io.Reader con el content-type dado. +func (s *OSSService) UploadFromReader(objectKey, contentType string, r io.Reader) error { + var opts []oss.Option + if contentType != "" { + opts = append(opts, oss.ContentType(contentType)) + } + err := s.Bucket.PutObject(objectKey, r, opts...) + if err != nil { + return fmt.Errorf("error subiendo objeto '%s': %w", objectKey, err) + } + log.Printf("Objeto subido a OSS: %s", objectKey) + return nil +} + +// DeleteObjects elimina múltiples objetos en una sola llamada (batch). +func (s *OSSService) DeleteObjects(keys []string) error { + _, err := s.Bucket.DeleteObjects(keys) + if err != nil { + return fmt.Errorf("error eliminando objetos en batch: %w", err) + } + return nil +} diff --git a/resources/views/oss_api.html b/resources/views/oss_api.html index bc62823..a332238 100644 --- a/resources/views/oss_api.html +++ b/resources/views/oss_api.html @@ -1,20 +1,20 @@ - +
Gestiona las configuraciones de acceso a Alibaba Cloud Object Storage Service (OSS). La configuración activa es usada por todos los servicios de almacenamiento.
+Gestiona configuraciones de acceso y explora archivos del bucket activo.