初始化框架
This commit is contained in:
@@ -0,0 +1,41 @@
|
|||||||
|
package aliyun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.yun.ink/pkg/storagex"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 确保实现了 storage.Uploader 接口
|
||||||
|
var _ storagex.Uploader = (*AliyunUploader)(nil)
|
||||||
|
|
||||||
|
type AliyunFactory struct{}
|
||||||
|
|
||||||
|
// Create 根据配置创建 AliyunUploader 实例
|
||||||
|
func (f *AliyunFactory) Create(cfg storagex.Config) (storagex.Uploader, error) {
|
||||||
|
return &AliyunUploader{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type AliyunUploader struct {
|
||||||
|
storagex.UploaderImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (o *AliyunUploader) GetObject(ctx context.Context, objectKey string) (io.ReadCloser, error) {
|
||||||
|
return nil, errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *AliyunUploader) PutObject(ctx context.Context, objectKey string, value io.Reader) (*storagex.PutResult, error) {
|
||||||
|
return nil, errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *AliyunUploader) GetUrl(ctx context.Context, objectKey string, expire time.Duration) (string, error) {
|
||||||
|
return "", errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *AliyunUploader) DeleteObject(ctx context.Context, objectKey string) error {
|
||||||
|
return errors.New("not implemented")
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.yun.ink/pkg/storagex"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ storagex.Uploader = (*S3Uploader)(nil)
|
||||||
|
|
||||||
|
type S3Factory struct{}
|
||||||
|
|
||||||
|
func (f *S3Factory) Create(cfg storagex.Config) (storagex.Uploader, error) {
|
||||||
|
return &S3Uploader{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type S3Uploader struct {
|
||||||
|
storagex.UploaderImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *S3Uploader) GetObject(ctx context.Context, objectKey string) (io.ReadCloser, error) {
|
||||||
|
return nil, errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *S3Uploader) PutObject(ctx context.Context, objectKey string, value io.Reader) (*storagex.PutResult, error) {
|
||||||
|
return nil, errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *S3Uploader) GetUrl(ctx context.Context, objectKey string, expire time.Duration) (string, error) {
|
||||||
|
return "", errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *S3Uploader) DeleteObject(ctx context.Context, objectKey string) error {
|
||||||
|
return errors.New("not implemented")
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package storagex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config 通用配置结构 (可根据需要扩展)
|
||||||
|
type Config struct {
|
||||||
|
Provider string // 服务商: "aliyun", "aws", "tencent"
|
||||||
|
AccountID string // 账号标识: "account_01", "finance_team"
|
||||||
|
Options map[string]string // 具体配置: AK, SK, Bucket, Region, Endpoint 等
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutResult 上传成功后的返回信息
|
||||||
|
type PutResult struct {
|
||||||
|
URL string // 文件访问地址
|
||||||
|
Size int64 // 文件大小
|
||||||
|
ETag string // 文件指纹/哈希
|
||||||
|
Provider string // 服务商名称
|
||||||
|
AccountID string // 使用的账号ID(用于追踪)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Uploader interface {
|
||||||
|
// GetObject 获取对象
|
||||||
|
GetObject(ctx context.Context, objectKey string) (io.ReadCloser, error)
|
||||||
|
// GetUrl 获取对象URL地址
|
||||||
|
GetUrl(ctx context.Context, objectKey string, expire time.Duration) (string, error)
|
||||||
|
// PutObject 写入对象
|
||||||
|
PutObject(ctx context.Context, objectKey string, value io.Reader) (*PutResult, error)
|
||||||
|
// DeleteObject 删除对象
|
||||||
|
DeleteObject(ctx context.Context, objectKey string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploaderImpl struct{}
|
||||||
|
|
||||||
|
func NewUploader() *UploaderImpl {
|
||||||
|
return &UploaderImpl{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *UploaderImpl) GetObject(ctx context.Context, objectKey string) (io.ReadCloser, error) {
|
||||||
|
return nil, errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *UploaderImpl) PutObject(ctx context.Context, objectKey string, value io.Reader) (*PutResult, error) {
|
||||||
|
return nil, errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *UploaderImpl) GetUrl(ctx context.Context, objectKey string, expire time.Duration) (string, error) {
|
||||||
|
return "", errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *UploaderImpl) DeleteObject(ctx context.Context, objectKey string) error {
|
||||||
|
return errors.New("not implemented")
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.yun.ink/pkg/storagex"
|
||||||
|
"code.yun.ink/pkg/storagex/aliyun"
|
||||||
|
"code.yun.ink/pkg/storagex/aws"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// 在应用启动时注册所有支持的服务商
|
||||||
|
storagex.Register("aliyun", &aliyun.AliyunFactory{})
|
||||||
|
storagex.Register("aws", &aws.S3Factory{})
|
||||||
|
// storagex.Register("tencent", &tencent.COSFactory{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 场景 1: 使用阿里云账号 A 上传
|
||||||
|
cfgAli := storagex.Config{
|
||||||
|
Provider: "aliyun",
|
||||||
|
AccountID: "user_123", // 指定账号
|
||||||
|
Options: map[string]string{
|
||||||
|
"access_key": "LTAIxxxx",
|
||||||
|
"secret_key": "secretxxxx",
|
||||||
|
"bucket": "my-app-assets",
|
||||||
|
"endpoint": "oss-cn-hangzhou.aliyuncs.com",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取上传通道 (自动处理单例复用)
|
||||||
|
uploader, err := storagex.GetUploader("aliyun", "user_123", cfgAli)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行上传
|
||||||
|
result, err := uploader.PutObject(context.Background(), "images/test.png", strings.NewReader("file content"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("上传成功: %s\n", result.URL)
|
||||||
|
|
||||||
|
// 场景 2: 使用 AWS 账号 B 上传
|
||||||
|
// cfgAws := storagex.Config{
|
||||||
|
// Provider: "aws",
|
||||||
|
// AccountID: "finance_dept",
|
||||||
|
// Options: map[string]string{
|
||||||
|
// "region": "ap-northeast-1",
|
||||||
|
// "bucket": "finance-bucket",
|
||||||
|
// // AK/SK...
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 注意:这里会创建一个新的 S3 客户端,与阿里云互不干扰
|
||||||
|
// awsUploader, _ := storagex.GetUploader("aws", "finance_dept", cfgAws)
|
||||||
|
// awsUploader.Upload(...)
|
||||||
|
}
|
||||||
+78
@@ -0,0 +1,78 @@
|
|||||||
|
package storagex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DriverFactory 驱动工厂接口
|
||||||
|
type DriverFactory interface {
|
||||||
|
Create(cfg Config) (Uploader, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registry 注册中心,单例模式管理所有上传通道
|
||||||
|
type Registry struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
factories map[string]DriverFactory // 存储服务商工厂 (aliyun -> AliyunFactory)
|
||||||
|
clients map[string]Uploader // 缓存具体的客户端实例 (key = provider:accountID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全局注册中心实例
|
||||||
|
var globalRegistry = &Registry{
|
||||||
|
factories: make(map[string]DriverFactory),
|
||||||
|
clients: make(map[string]Uploader),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register 注册服务商工厂
|
||||||
|
// 例如: Register("aliyun", &AliyunFactory{})
|
||||||
|
func Register(provider string, factory DriverFactory) {
|
||||||
|
globalRegistry.mu.Lock()
|
||||||
|
defer globalRegistry.mu.Unlock()
|
||||||
|
globalRegistry.factories[provider] = factory
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUploader 获取指定服务商和账号的上传器
|
||||||
|
// 如果该账号的客户端已存在则复用,不存在则创建
|
||||||
|
func GetUploader(provider, accountID string, cfg Config) (Uploader, error) {
|
||||||
|
key := fmt.Sprintf("%s:%s", provider, accountID)
|
||||||
|
|
||||||
|
// 1. 尝试从缓存获取 (读锁)
|
||||||
|
globalRegistry.mu.RLock()
|
||||||
|
client, ok := globalRegistry.clients[key]
|
||||||
|
globalRegistry.mu.RUnlock()
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 缓存未命中,需要创建 (写锁)
|
||||||
|
globalRegistry.mu.Lock()
|
||||||
|
defer globalRegistry.mu.Unlock()
|
||||||
|
|
||||||
|
// 双重检查锁,防止并发下重复创建
|
||||||
|
if client, ok := globalRegistry.clients[key]; ok {
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
factory, ok := globalRegistry.factories[provider]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unknown provider: %s", provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新的 Uploader 实例
|
||||||
|
client, err := factory.Create(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create uploader for %s: %w", provider, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存入缓存
|
||||||
|
globalRegistry.clients[key] = client
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear 主要用于测试,清空缓存
|
||||||
|
func Clear() {
|
||||||
|
globalRegistry.mu.Lock()
|
||||||
|
defer globalRegistry.mu.Unlock()
|
||||||
|
globalRegistry.clients = make(map[string]Uploader)
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package tencent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.yun.ink/pkg/storagex"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TencentFactory struct{}
|
||||||
|
|
||||||
|
func (f *TencentFactory) Create(cfg storagex.Config) (storagex.Uploader, error) {
|
||||||
|
return &TencentUploader{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type TencentUploader struct {
|
||||||
|
storagex.UploaderImpl
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user