yuan-lab-llm--clawmanager
115 行
3.4 KiB
Go
115 行
3.4 KiB
Go
package services
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"clawreef/internal/config"
|
|
|
|
"github.com/minio/minio-go/v7"
|
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
|
)
|
|
|
|
type ObjectStorageService interface {
|
|
PutObject(ctx context.Context, objectKey string, body []byte, contentType string) error
|
|
GetObject(ctx context.Context, objectKey string) ([]byte, error)
|
|
}
|
|
|
|
type objectStorageService struct {
|
|
minioClient *minio.Client
|
|
bucket string
|
|
basePath string
|
|
localPath string
|
|
}
|
|
|
|
func NewObjectStorageService(cfg config.ObjectStorageConfig) (ObjectStorageService, error) {
|
|
service := &objectStorageService{
|
|
bucket: strings.TrimSpace(cfg.Bucket),
|
|
basePath: strings.Trim(strings.TrimSpace(cfg.BasePath), "/"),
|
|
localPath: strings.TrimSpace(cfg.LocalFallback),
|
|
}
|
|
if service.localPath == "" {
|
|
service.localPath = ".data/object-storage"
|
|
}
|
|
if strings.TrimSpace(cfg.Endpoint) == "" {
|
|
return service, nil
|
|
}
|
|
|
|
client, err := minio.New(cfg.Endpoint, &minio.Options{
|
|
Creds: credentials.NewStaticV4(cfg.AccessKey, cfg.SecretKey, ""),
|
|
Secure: cfg.UseSSL,
|
|
Region: cfg.Region,
|
|
BucketLookup: minio.BucketLookupPath,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to initialize object storage client: %w", err)
|
|
}
|
|
service.minioClient = client
|
|
return service, nil
|
|
}
|
|
|
|
func (s *objectStorageService) PutObject(ctx context.Context, objectKey string, body []byte, contentType string) error {
|
|
if s.minioClient == nil {
|
|
target := filepath.Join(s.localPath, filepath.FromSlash(s.resolveObjectKey(objectKey)))
|
|
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
|
|
return fmt.Errorf("failed to prepare local object storage directory: %w", err)
|
|
}
|
|
if err := os.WriteFile(target, body, 0o644); err != nil {
|
|
return fmt.Errorf("failed to write local object storage object: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
exists, err := s.minioClient.BucketExists(ctx, s.bucket)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to check object storage bucket: %w", err)
|
|
}
|
|
if !exists {
|
|
if err := s.minioClient.MakeBucket(ctx, s.bucket, minio.MakeBucketOptions{}); err != nil {
|
|
return fmt.Errorf("failed to create object storage bucket: %w", err)
|
|
}
|
|
}
|
|
_, err = s.minioClient.PutObject(ctx, s.bucket, s.resolveObjectKey(objectKey), bytes.NewReader(body), int64(len(body)), minio.PutObjectOptions{
|
|
ContentType: contentType,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to upload object: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *objectStorageService) GetObject(ctx context.Context, objectKey string) ([]byte, error) {
|
|
if s.minioClient == nil {
|
|
target := filepath.Join(s.localPath, filepath.FromSlash(s.resolveObjectKey(objectKey)))
|
|
content, err := os.ReadFile(target)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read local object storage object: %w", err)
|
|
}
|
|
return content, nil
|
|
}
|
|
|
|
reader, err := s.minioClient.GetObject(ctx, s.bucket, s.resolveObjectKey(objectKey), minio.GetObjectOptions{})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open object: %w", err)
|
|
}
|
|
defer reader.Close()
|
|
content, err := io.ReadAll(reader)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read object: %w", err)
|
|
}
|
|
return content, nil
|
|
}
|
|
|
|
func (s *objectStorageService) resolveObjectKey(objectKey string) string {
|
|
objectKey = strings.Trim(strings.TrimSpace(objectKey), "/")
|
|
if s.basePath == "" {
|
|
return objectKey
|
|
}
|
|
return s.basePath + "/" + objectKey
|
|
}
|