topfans/backend/services/assetService/util/oss_util.go
2026-04-07 22:29:48 +08:00

144 lines
4.0 KiB
Go

package util
import (
"bytes"
"fmt"
"io"
"net/http"
"time"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/aliyun/credentials-go/credentials"
"github.com/topfans/backend/pkg/logger"
"go.uber.org/zap"
)
// OSSConfig OSS 配置
type OSSConfig struct {
Region string
BucketName string
RoleArn string
AccessKeyID string
AccessKeySecret string
}
// UploadImageToOSS 下载图片并上传到 OSS
func UploadImageToOSS(config OSSConfig, imageURL string, ossKey string) (string, error) {
// 1. 下载图片到内存
resp, err := http.Get(imageURL)
if err != nil {
return "", fmt.Errorf("下载图片失败: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("下载图片失败,状态码: %d", resp.StatusCode)
}
imageData, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("读取图片数据失败: %w", err)
}
// 2. 获取 STS 临时凭证
credConfig := new(credentials.Config).
SetType("ram_role_arn").
SetAccessKeyId(config.AccessKeyID).
SetAccessKeySecret(config.AccessKeySecret).
SetRoleArn(config.RoleArn).
SetRoleSessionName("topfans-asset-upload").
SetPolicy("").
SetRoleSessionExpiration(3600)
provider, err := credentials.NewCredential(credConfig)
if err != nil {
return "", fmt.Errorf("创建凭证提供器失败: %w", err)
}
cred, err := provider.GetCredential()
if err != nil {
return "", fmt.Errorf("获取临时凭证失败: %w", err)
}
// 3. 创建 OSS 客户端
endpoint := fmt.Sprintf("https://oss-%s.aliyuncs.com", config.Region)
client, err := oss.New(endpoint, *cred.AccessKeyId, *cred.AccessKeySecret,
oss.SecurityToken(*cred.SecurityToken))
if err != nil {
return "", fmt.Errorf("创建OSS客户端失败: %w", err)
}
// 4. 获取 Bucket
bucket, err := client.Bucket(config.BucketName)
if err != nil {
return "", fmt.Errorf("获取Bucket失败: %w", err)
}
// 5. 上传图片
err = bucket.PutObject(ossKey, bytes.NewReader(imageData))
if err != nil {
return "", fmt.Errorf("上传图片到OSS失败: %w", err)
}
// 6. 构建 OSS URL
ossURL := fmt.Sprintf("https://%s.oss-%s.aliyuncs.com/%s", config.BucketName, config.Region, ossKey)
logger.Logger.Info("图片上传到OSS成功",
zap.String("oss_key", ossKey),
zap.String("oss_url", ossURL),
)
return ossURL, nil
}
// DeleteObjectFromOSS 删除 OSS 对象(用于阶段一取消后清理素材)
func DeleteObjectFromOSS(config OSSConfig, ossKey string) error {
if ossKey == "" {
return fmt.Errorf("ossKey不能为空")
}
// 获取 STS 临时凭证
credConfig := new(credentials.Config).
SetType("ram_role_arn").
SetAccessKeyId(config.AccessKeyID).
SetAccessKeySecret(config.AccessKeySecret).
SetRoleArn(config.RoleArn).
SetRoleSessionName("topfans-asset-delete").
SetPolicy("").
SetRoleSessionExpiration(3600)
provider, err := credentials.NewCredential(credConfig)
if err != nil {
return fmt.Errorf("创建凭证提供器失败: %w", err)
}
cred, err := provider.GetCredential()
if err != nil {
return fmt.Errorf("获取临时凭证失败: %w", err)
}
endpoint := fmt.Sprintf("https://oss-%s.aliyuncs.com", config.Region)
client, err := oss.New(endpoint, *cred.AccessKeyId, *cred.AccessKeySecret,
oss.SecurityToken(*cred.SecurityToken))
if err != nil {
return fmt.Errorf("创建OSS客户端失败: %w", err)
}
bucket, err := client.Bucket(config.BucketName)
if err != nil {
return fmt.Errorf("获取Bucket失败: %w", err)
}
if err := bucket.DeleteObject(ossKey); err != nil {
return fmt.Errorf("删除OSS对象失败: %w", err)
}
logger.Logger.Info("删除OSS对象成功", zap.String("oss_key", ossKey))
return nil
}
// GenerateOSSKey 生成 OSS 对象键(路径)
// 格式: asset/{user_id}/{star_id}/covers/{asset_id}_{timestamp}.png
func GenerateOSSKey(userID, starID, assetID int64) string {
timestamp := time.Now().Unix()
return fmt.Sprintf("asset/%d/%d/covers/%d_%d.png", userID, starID, assetID, timestamp)
}