chore: 清理敏感与开发文档,仅同步代码
- 永久忽略并从仓库移除 开发文档/ - 移除并忽略 .env 与小程序私有配置 - 同步小程序/管理端/API与脚本改动 Made-with: Cursor
This commit is contained in:
124
soul-api/internal/oss/oss.go
Normal file
124
soul-api/internal/oss/oss.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package oss
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"soul-api/internal/database"
|
||||
"soul-api/internal/model"
|
||||
|
||||
alioss "github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||
)
|
||||
|
||||
// Config 阿里云 OSS 配置,与管理端 ossConfig 字段对应
|
||||
type Config struct {
|
||||
Endpoint string `json:"endpoint"`
|
||||
Bucket string `json:"bucket"`
|
||||
Region string `json:"region"`
|
||||
AccessKeyID string `json:"accessKeyId"`
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
}
|
||||
|
||||
// LoadConfig 从 system_config 读取 oss_config,配置不完整时返回 nil
|
||||
func LoadConfig() *Config {
|
||||
var row model.SystemConfig
|
||||
if err := database.DB().Where("config_key = ?", "oss_config").First(&row).Error; err != nil {
|
||||
return nil
|
||||
}
|
||||
var m map[string]interface{}
|
||||
if err := json.Unmarshal(row.ConfigValue, &m); err != nil {
|
||||
return nil
|
||||
}
|
||||
var cfg Config
|
||||
if v, ok := m["endpoint"].(string); ok && v != "" {
|
||||
cfg.Endpoint = strings.TrimSpace(v)
|
||||
}
|
||||
if v, ok := m["bucket"].(string); ok && v != "" {
|
||||
cfg.Bucket = strings.TrimSpace(v)
|
||||
}
|
||||
if v, ok := m["accessKeyId"].(string); ok && v != "" {
|
||||
cfg.AccessKeyID = v
|
||||
}
|
||||
if v, ok := m["accessKeySecret"].(string); ok && v != "" {
|
||||
cfg.AccessKeySecret = v
|
||||
}
|
||||
if cfg.Endpoint == "" || cfg.Bucket == "" || cfg.AccessKeyID == "" || cfg.AccessKeySecret == "" {
|
||||
return nil
|
||||
}
|
||||
// endpoint 去掉 scheme,SDK 需要
|
||||
cfg.Endpoint = strings.TrimPrefix(strings.TrimPrefix(cfg.Endpoint, "https://"), "http://")
|
||||
return &cfg
|
||||
}
|
||||
|
||||
// IsEnabled 是否已配置 OSS 且可用
|
||||
func IsEnabled() bool {
|
||||
return LoadConfig() != nil
|
||||
}
|
||||
|
||||
// Upload 上传文件到 OSS,objectKey 如 "uploads/avatars/xxx.jpg"
|
||||
// 返回公网访问 URL,如 https://bucket.oss-cn-hangzhou.aliyuncs.com/uploads/avatars/xxx.jpg
|
||||
func Upload(objectKey string, reader io.Reader, options ...alioss.Option) (string, error) {
|
||||
cfg := LoadConfig()
|
||||
if cfg == nil {
|
||||
return "", nil // 未配置,调用方需回退本地
|
||||
}
|
||||
client, err := alioss.New(cfg.Endpoint, cfg.AccessKeyID, cfg.AccessKeySecret)
|
||||
if err != nil {
|
||||
log.Printf("oss: client init failed: %v", err)
|
||||
return "", err
|
||||
}
|
||||
bucket, err := client.Bucket(cfg.Bucket)
|
||||
if err != nil {
|
||||
log.Printf("oss: bucket %s failed: %v", cfg.Bucket, err)
|
||||
return "", err
|
||||
}
|
||||
if err := bucket.PutObject(objectKey, reader, options...); err != nil {
|
||||
log.Printf("oss: PutObject %s failed: %v", objectKey, err)
|
||||
return "", err
|
||||
}
|
||||
// 公网 URL:https://{bucket}.{endpoint}/{objectKey}
|
||||
u := "https://" + cfg.Bucket + "." + cfg.Endpoint + "/" + objectKey
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// Delete 从 OSS 删除对象,objectKey 如 "uploads/avatars/xxx.jpg"
|
||||
func Delete(objectKey string) error {
|
||||
cfg := LoadConfig()
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
client, err := alioss.New(cfg.Endpoint, cfg.AccessKeyID, cfg.AccessKeySecret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bucket, err := client.Bucket(cfg.Bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return bucket.DeleteObject(objectKey)
|
||||
}
|
||||
|
||||
// ParseObjectKeyFromURL 从 OSS 公网 URL 解析出 objectKey
|
||||
// 格式: https://bucket.oss-cn-xxx.aliyuncs.com/uploads/avatars/xxx.jpg
|
||||
func ParseObjectKeyFromURL(rawURL string) string {
|
||||
u, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
path := strings.TrimPrefix(u.Path, "/")
|
||||
return path
|
||||
}
|
||||
|
||||
// IsOSSURL 判断是否为 OSS 公网 URL(用于删除时区分本地/OSS)
|
||||
func IsOSSURL(rawURL string) bool {
|
||||
cfg := LoadConfig()
|
||||
if cfg == nil {
|
||||
return false
|
||||
}
|
||||
// 格式: https://{bucket}.{endpoint}/...
|
||||
prefix := "https://" + cfg.Bucket + "." + cfg.Endpoint + "/"
|
||||
return strings.HasPrefix(rawURL, prefix)
|
||||
}
|
||||
Reference in New Issue
Block a user