diff --git a/api/core/types/config.go b/api/core/types/config.go index eb90c4f3..ac1e2295 100644 --- a/api/core/types/config.go +++ b/api/core/types/config.go @@ -40,34 +40,6 @@ type AliYunSmsConfig struct { Domain string } -type OSSConfig struct { - Active string - Local LocalStorageConfig - Minio MinioConfig - QiNiu QiNiuConfig -} -type MinioConfig struct { - Endpoint string - AccessKey string - AccessSecret string - Bucket string - UseSSL bool - Domain string -} - -type QiNiuConfig struct { - Zone string - AccessKey string - AccessSecret string - Bucket string - Domain string -} - -type LocalStorageConfig struct { - BasePath string - BaseURL string -} - type RedisConfig struct { Host string Port int diff --git a/api/core/types/oss.go b/api/core/types/oss.go new file mode 100644 index 00000000..bacfdad8 --- /dev/null +++ b/api/core/types/oss.go @@ -0,0 +1,38 @@ +package types + +type OSSConfig struct { + Active string + Local LocalStorageConfig + Minio MiniOssConfig + QiNiu QiNiuOssConfig + AliYun AliYunOssConfig +} +type MiniOssConfig struct { + Endpoint string + AccessKey string + AccessSecret string + Bucket string + UseSSL bool + Domain string +} + +type QiNiuOssConfig struct { + Zone string + AccessKey string + AccessSecret string + Bucket string + Domain string +} + +type AliYunOssConfig struct { + Endpoint string + AccessKey string + AccessSecret string + Bucket string + Domain string +} + +type LocalStorageConfig struct { + BasePath string + BaseURL string +} diff --git a/api/go.mod b/api/go.mod index a48895e1..2b6d41f1 100644 --- a/api/go.mod +++ b/api/go.mod @@ -21,6 +21,7 @@ require ( ) require ( + github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible // indirect github.com/andybalholm/brotli v1.0.4 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect @@ -63,6 +64,7 @@ require ( golang.org/x/net v0.14.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/text v0.12.0 // indirect + golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.10.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/api/go.sum b/api/go.sum index 9aa2a401..0a70646e 100644 --- a/api/go.sum +++ b/api/go.sum @@ -2,6 +2,8 @@ github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/aliyun/alibaba-cloud-sdk-go v1.62.405 h1:cKNFQmeCQFN0WNfjScKoVrGi7vXxTVbkCvCqSrOf+P4= github.com/aliyun/alibaba-cloud-sdk-go v1.62.405/go.mod h1:Api2AkmMgGaSUAhmk76oaFObkoeCPc/bKAqcyplPODs= +github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible h1:Sg/2xHwDrioHpxTN6WMiwbXTpUEinBpHsN7mG21Rc2k= +github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= @@ -260,6 +262,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= diff --git a/api/service/oss/aliyun_oss.go b/api/service/oss/aliyun_oss.go new file mode 100644 index 00000000..4dfb089c --- /dev/null +++ b/api/service/oss/aliyun_oss.go @@ -0,0 +1,86 @@ +package oss + +import ( + "bytes" + "chatplus/core/types" + "chatplus/utils" + "fmt" + "github.com/aliyun/aliyun-oss-go-sdk/oss" + "github.com/gin-gonic/gin" + "path/filepath" + "time" +) + +type AliYunOss struct { + config *types.AliYunOssConfig + bucket *oss.Bucket + proxyURL string +} + +func NewAliYunOss(appConfig *types.AppConfig) (*AliYunOss, error) { + config := &appConfig.OSS.AliYun + // 创建 OSS 客户端 + client, err := oss.New(config.Endpoint, config.AccessKey, config.AccessSecret) + if err != nil { + return nil, err + } + + // 获取存储空间 + bucket, err := client.Bucket(config.Bucket) + if err != nil { + return nil, err + } + + return &AliYunOss{ + config: config, + bucket: bucket, + proxyURL: appConfig.ProxyURL, + }, nil + +} + +func (s AliYunOss) PutFile(ctx *gin.Context, name string) (string, error) { + // 解析表单 + file, err := ctx.FormFile(name) + if err != nil { + return "", err + } + // 打开上传文件 + src, err := file.Open() + if err != nil { + return "", err + } + defer src.Close() + + fileExt := filepath.Ext(file.Filename) + objectKey := fmt.Sprintf("%d%s", time.Now().UnixMicro(), fileExt) + // 上传文件 + err = s.bucket.PutObject(objectKey, src) + if err != nil { + return "", err + } + + return fmt.Sprintf("https://%s.%s/%s", s.config.Bucket, s.config.Endpoint, objectKey), nil +} + +func (s AliYunOss) PutImg(imageURL string) (string, error) { + imageData, err := utils.DownloadImage(imageURL, s.proxyURL) + if err != nil { + return "", fmt.Errorf("error with download image: %v", err) + } + fileExt := filepath.Ext(filepath.Base(imageURL)) + objectKey := fmt.Sprintf("%d%s", time.Now().UnixMicro(), fileExt) + // 上传文件字节数据 + err = s.bucket.PutObject(objectKey, bytes.NewReader(imageData)) + if err != nil { + return "", err + } + return fmt.Sprintf("https://%s.%s/%s", s.config.Bucket, s.config.Endpoint, objectKey), nil +} + +func (s AliYunOss) Delete(fileURL string) error { + objectName := filepath.Base(fileURL) + return s.bucket.DeleteObject(objectName) +} + +var _ Uploader = AliYunOss{} diff --git a/api/service/oss/localstorage_service.go b/api/service/oss/localstorage.go similarity index 76% rename from api/service/oss/localstorage_service.go rename to api/service/oss/localstorage.go index f51a2664..e0d19d79 100644 --- a/api/service/oss/localstorage_service.go +++ b/api/service/oss/localstorage.go @@ -10,19 +10,19 @@ import ( "strings" ) -type LocalStorageService struct { +type LocalStorage struct { config *types.LocalStorageConfig proxyURL string } -func NewLocalStorageService(config *types.AppConfig) LocalStorageService { - return LocalStorageService{ +func NewLocalStorage(config *types.AppConfig) LocalStorage { + return LocalStorage{ config: &config.OSS.Local, proxyURL: config.ProxyURL, } } -func (s LocalStorageService) PutFile(ctx *gin.Context, name string) (string, error) { +func (s LocalStorage) PutFile(ctx *gin.Context, name string) (string, error) { file, err := ctx.FormFile(name) if err != nil { return "", fmt.Errorf("error with get form: %v", err) @@ -41,7 +41,7 @@ func (s LocalStorageService) PutFile(ctx *gin.Context, name string) (string, err return utils.GenUploadUrl(s.config.BasePath, s.config.BaseURL, filePath), nil } -func (s LocalStorageService) PutImg(imageURL string) (string, error) { +func (s LocalStorage) PutImg(imageURL string) (string, error) { filename := filepath.Base(imageURL) filePath, err := utils.GenUploadPath(s.config.BasePath, filename) if err != nil { @@ -56,9 +56,9 @@ func (s LocalStorageService) PutImg(imageURL string) (string, error) { return utils.GenUploadUrl(s.config.BasePath, s.config.BaseURL, filePath), nil } -func (s LocalStorageService) Delete(fileURL string) error { +func (s LocalStorage) Delete(fileURL string) error { filePath := strings.Replace(fileURL, s.config.BaseURL, s.config.BasePath, 1) return os.Remove(filePath) } -var _ Uploader = LocalStorageService{} +var _ Uploader = LocalStorage{} diff --git a/api/service/oss/minio_service.go b/api/service/oss/minio_oss.go similarity index 80% rename from api/service/oss/minio_service.go rename to api/service/oss/minio_oss.go index c898189f..ee859540 100644 --- a/api/service/oss/minio_service.go +++ b/api/service/oss/minio_oss.go @@ -13,25 +13,25 @@ import ( "time" ) -type MinioService struct { - config *types.MinioConfig +type MiniOss struct { + config *types.MiniOssConfig client *minio.Client proxyURL string } -func NewMinioService(appConfig *types.AppConfig) (MinioService, error) { +func NewMiniOss(appConfig *types.AppConfig) (MiniOss, error) { config := &appConfig.OSS.Minio minioClient, err := minio.New(config.Endpoint, &minio.Options{ Creds: credentials.NewStaticV4(config.AccessKey, config.AccessSecret, ""), Secure: config.UseSSL, }) if err != nil { - return MinioService{}, err + return MiniOss{}, err } - return MinioService{config: config, client: minioClient, proxyURL: appConfig.ProxyURL}, nil + return MiniOss{config: config, client: minioClient, proxyURL: appConfig.ProxyURL}, nil } -func (s MinioService) PutImg(imageURL string) (string, error) { +func (s MiniOss) PutImg(imageURL string) (string, error) { imageData, err := utils.DownloadImage(imageURL, s.proxyURL) if err != nil { return "", fmt.Errorf("error with download image: %v", err) @@ -51,7 +51,7 @@ func (s MinioService) PutImg(imageURL string) (string, error) { return fmt.Sprintf("%s/%s/%s", s.config.Domain, s.config.Bucket, info.Key), nil } -func (s MinioService) PutFile(ctx *gin.Context, name string) (string, error) { +func (s MiniOss) PutFile(ctx *gin.Context, name string) (string, error) { file, err := ctx.FormFile(name) if err != nil { return "", fmt.Errorf("error with get form: %v", err) @@ -75,9 +75,9 @@ func (s MinioService) PutFile(ctx *gin.Context, name string) (string, error) { return fmt.Sprintf("%s/%s/%s", s.config.Domain, s.config.Bucket, info.Key), nil } -func (s MinioService) Delete(fileURL string) error { +func (s MiniOss) Delete(fileURL string) error { objectName := filepath.Base(fileURL) return s.client.RemoveObject(context.Background(), s.config.Bucket, objectName, minio.RemoveObjectOptions{}) } -var _ Uploader = MinioService{} +var _ Uploader = MiniOss{} diff --git a/api/service/oss/qiniu_service.go b/api/service/oss/qiniu_oss.go similarity index 85% rename from api/service/oss/qiniu_service.go rename to api/service/oss/qiniu_oss.go index a47212fd..a4f8dd62 100644 --- a/api/service/oss/qiniu_service.go +++ b/api/service/oss/qiniu_oss.go @@ -13,8 +13,8 @@ import ( "time" ) -type QiNiuService struct { - config *types.QiNiuConfig +type QinNiuOss struct { + config *types.QiNiuOssConfig token string uploader *storage.FormUploader manager *storage.BucketManager @@ -22,7 +22,7 @@ type QiNiuService struct { dir string } -func NewQiNiuService(appConfig *types.AppConfig) QiNiuService { +func NewQiNiuOss(appConfig *types.AppConfig) QinNiuOss { config := &appConfig.OSS.QiNiu // build storage uploader zone, ok := storage.GetRegionByID(storage.RegionID(config.Zone)) @@ -36,7 +36,7 @@ func NewQiNiuService(appConfig *types.AppConfig) QiNiuService { putPolicy := storage.PutPolicy{ Scope: config.Bucket, } - return QiNiuService{ + return QinNiuOss{ config: config, token: putPolicy.UploadToken(mac), uploader: formUploader, @@ -46,7 +46,7 @@ func NewQiNiuService(appConfig *types.AppConfig) QiNiuService { } } -func (s QiNiuService) PutFile(ctx *gin.Context, name string) (string, error) { +func (s QinNiuOss) PutFile(ctx *gin.Context, name string) (string, error) { // 解析表单 file, err := ctx.FormFile(name) if err != nil { @@ -72,7 +72,7 @@ func (s QiNiuService) PutFile(ctx *gin.Context, name string) (string, error) { return fmt.Sprintf("%s/%s", s.config.Domain, ret.Key), nil } -func (s QiNiuService) PutImg(imageURL string) (string, error) { +func (s QinNiuOss) PutImg(imageURL string) (string, error) { imageData, err := utils.DownloadImage(imageURL, s.proxyURL) if err != nil { return "", fmt.Errorf("error with download image: %v", err) @@ -89,10 +89,10 @@ func (s QiNiuService) PutImg(imageURL string) (string, error) { return fmt.Sprintf("%s/%s", s.config.Domain, ret.Key), nil } -func (s QiNiuService) Delete(fileURL string) error { +func (s QinNiuOss) Delete(fileURL string) error { objectName := filepath.Base(fileURL) key := fmt.Sprintf("%s/%s", s.dir, objectName) return s.manager.Delete(s.config.Bucket, key) } -var _ Uploader = QiNiuService{} +var _ Uploader = QinNiuOss{} diff --git a/api/service/oss/uploader_manager.go b/api/service/oss/uploader_manager.go index 25732a46..6cff655f 100644 --- a/api/service/oss/uploader_manager.go +++ b/api/service/oss/uploader_manager.go @@ -12,6 +12,7 @@ type UploaderManager struct { const Local = "LOCAL" const Minio = "MINIO" const QiNiu = "QINIU" +const AliYun = "ALIYUN" func NewUploaderManager(config *types.AppConfig) (*UploaderManager, error) { active := Local @@ -21,17 +22,25 @@ func NewUploaderManager(config *types.AppConfig) (*UploaderManager, error) { var handler Uploader switch active { case Local: - handler = NewLocalStorageService(config) + handler = NewLocalStorage(config) break case Minio: - service, err := NewMinioService(config) + client, err := NewMiniOss(config) if err != nil { return nil, err } - handler = service + handler = client break case QiNiu: - handler = NewQiNiuService(config) + handler = NewQiNiuOss(config) + break + case AliYun: + client, err := NewAliYunOss(config) + if err != nil { + return nil, err + } + handler = client + break } return &UploaderManager{handler: handler}, nil diff --git a/web/src/views/Test.vue b/web/src/views/Test.vue index 81e860c1..217a5004 100644 --- a/web/src/views/Test.vue +++ b/web/src/views/Test.vue @@ -1,5 +1,7 @@