package upload import ( "errors" "mime/multipart" "path" "strings" "time" "github.com/google/uuid" ) var ( ErrFileEmpty = errors.New("文件为空") ErrFileTooLarge = errors.New("文件过大") ErrFileTypeError = errors.New("文件类型不允许") ) // OSS 对象存储接口 type OSS interface { UploadFile(file *multipart.FileHeader) (string, string, error) DeleteFile(key string) error } // Config 上传配置 type Config struct { Type string // local, aliyun, tencent, qiniu, minio, aws-s3, huawei-obs, cloudflare-r2 Path string MaxSize int64 } // OSSConfig 完整的OSS配置 type OSSConfig struct { OssType string // Local配置 LocalPath string LocalStorePath string // 七牛云配置 QiniuZone string QiniuBucket string QiniuImgPath string QiniuAccessKey string QiniuSecretKey string QiniuUseHTTPS bool QiniuUseCdnDomains bool // 腾讯云COS配置 TencentBucket string TencentRegion string TencentSecretID string TencentSecretKey string TencentBaseURL string TencentPathPrefix string // 阿里云OSS配置 AliyunEndpoint string AliyunAccessKeyID string AliyunAccessKeySecret string AliyunBucketName string AliyunBucketURL string AliyunBasePath string // 华为云OBS配置 HuaweiPath string HuaweiBucket string HuaweiEndpoint string HuaweiAccessKey string HuaweiSecretKey string // AWS S3配置 AwsBucket string AwsRegion string AwsEndpoint string AwsSecretID string AwsSecretKey string AwsBaseURL string AwsPathPrefix string AwsS3ForcePathStyle bool AwsDisableSSL bool // Cloudflare R2配置 CloudflareBucket string CloudflareBaseURL string CloudflarePath string CloudflareAccountID string CloudflareAccessKeyID string CloudflareSecretAccessKey string // MinIO配置 MinioEndpoint string MinioAccessKeyID string MinioAccessKeySecret string MinioBucketName string MinioUseSSL bool MinioBasePath string MinioBucketURL string } // NewOSS 根据配置创建OSS实例 func NewOSS(cfg *OSSConfig) (OSS, error) { switch cfg.OssType { case "local": return NewLocal(cfg.LocalStorePath, cfg.LocalPath), nil case "qiniu": return NewQiniu( cfg.QiniuZone, cfg.QiniuBucket, cfg.QiniuImgPath, cfg.QiniuAccessKey, cfg.QiniuSecretKey, cfg.QiniuUseHTTPS, cfg.QiniuUseCdnDomains, ), nil case "tencent-cos": return NewTencent( cfg.TencentBucket, cfg.TencentRegion, cfg.TencentSecretID, cfg.TencentSecretKey, cfg.TencentBaseURL, cfg.TencentPathPrefix, ), nil case "aliyun-oss": return NewAliyun( cfg.AliyunEndpoint, cfg.AliyunAccessKeyID, cfg.AliyunAccessKeySecret, cfg.AliyunBucketName, cfg.AliyunBucketURL, cfg.AliyunBasePath, ), nil case "huawei-obs": return NewHuaweiObs( cfg.HuaweiPath, cfg.HuaweiBucket, cfg.HuaweiEndpoint, cfg.HuaweiAccessKey, cfg.HuaweiSecretKey, ), nil case "aws-s3": return NewAwsS3( cfg.AwsBucket, cfg.AwsRegion, cfg.AwsEndpoint, cfg.AwsSecretID, cfg.AwsSecretKey, cfg.AwsBaseURL, cfg.AwsPathPrefix, cfg.AwsS3ForcePathStyle, cfg.AwsDisableSSL, ), nil case "cloudflare-r2": return NewCloudflareR2( cfg.CloudflareBucket, cfg.CloudflareBaseURL, cfg.CloudflarePath, cfg.CloudflareAccountID, cfg.CloudflareAccessKeyID, cfg.CloudflareSecretAccessKey, ), nil case "minio": return NewMinio( cfg.MinioAccessKeyID, cfg.MinioAccessKeySecret, cfg.MinioBucketName, cfg.MinioEndpoint, cfg.MinioBasePath, cfg.MinioUseSSL, ), nil default: return NewLocal(cfg.LocalStorePath, cfg.LocalPath), nil } } // GenerateFileName 生成文件名 func GenerateFileName(originalName string) string { ext := path.Ext(originalName) name := uuid.New().String() return name + ext } // GeneratePath 生成存储路径 func GeneratePath(basePath string) string { now := time.Now() return path.Join(basePath, now.Format("2006/01/02")) } // CheckFileSize 检查文件大小 func CheckFileSize(size int64, maxSize int64) error { if size > maxSize { return ErrFileTooLarge } return nil } // CheckFileType 检查文件类型 func CheckFileType(filename string, allowTypes []string) error { ext := strings.ToLower(path.Ext(filename)) for _, t := range allowTypes { if ext == t || t == "*" { return nil } } return ErrFileTypeError } // DefaultAllowTypes 默认允许的文件类型 var DefaultAllowTypes = []string{ ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".txt", ".md", ".json", ".xml", ".csv", ".zip", ".rar", ".7z", ".tar", ".gz", ".mp3", ".mp4", ".avi", ".mov", ".wmv", }