package upload import ( "bytes" "context" "errors" "io" "mime" "mime/multipart" "path/filepath" "strings" "time" "git.echol.cn/loser/ai_wanjia/global" "git.echol.cn/loser/ai_wanjia/utils" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "go.uber.org/zap" ) var MinioClient *Minio // 优化性能,但是不支持动态配置 type Minio struct { Client *minio.Client bucket string } func GetMinio(endpoint, accessKeyID, secretAccessKey, bucketName string, useSSL bool) (*Minio, error) { if MinioClient != nil { return MinioClient, nil } // Initialize minio client object. minioClient, err := minio.New(endpoint, &minio.Options{ Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""), Secure: useSSL, // Set to true if using https }) if err != nil { return nil, err } // 尝试创建bucket err = minioClient.MakeBucket(context.Background(), bucketName, minio.MakeBucketOptions{}) if err != nil { // Check to see if we already own this bucket (which happens if you run this twice) exists, errBucketExists := minioClient.BucketExists(context.Background(), bucketName) if errBucketExists == nil && exists { // log.Printf("We already own %s\n", bucketName) } else { return nil, err } } MinioClient = &Minio{Client: minioClient, bucket: bucketName} return MinioClient, nil } func (m *Minio) UploadFile(file *multipart.FileHeader, ctx UploadContext) (filePathres, key string, uploadErr error) { f, openError := file.Open() if openError != nil { global.GVA_LOG.Error("function file.Open() Failed", zap.Any("err", openError.Error())) return "", "", errors.New("function file.Open() Failed, err:" + openError.Error()) } filecontent := bytes.Buffer{} _, err := io.Copy(&filecontent, f) if err != nil { global.GVA_LOG.Error("读取文件失败", zap.Any("err", err.Error())) return "", "", errors.New("读取文件失败, err:" + err.Error()) } f.Close() // 对文件名进行加密存储,加时间戳保证唯一性 ext := filepath.Ext(file.Filename) filename := utils.MD5V([]byte(strings.TrimSuffix(file.Filename, ext))) + "_" + time.Now().Format("20060102150405") + ext // 生成按平台+用户+日期分组的子目录 subDir := ctx.SubDir() basePath := global.GVA_CONFIG.Minio.BasePath if basePath == "" { basePath = "uploads" } key = basePath + "/" + subDir + "/" + filename // 根据文件扩展名检测 MIME 类型 contentType := mime.TypeByExtension(ext) if contentType == "" { contentType = "application/octet-stream" } // 设置超时10分钟 uploadCtx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) defer cancel() // Upload the file with PutObject 大文件自动切换为分片上传 info, err := m.Client.PutObject(uploadCtx, global.GVA_CONFIG.Minio.BucketName, key, &filecontent, file.Size, minio.PutObjectOptions{ContentType: contentType}) if err != nil { global.GVA_LOG.Error("上传文件到minio失败", zap.Any("err", err.Error())) return "", "", errors.New("上传文件到minio失败, err:" + err.Error()) } return global.GVA_CONFIG.Minio.BucketUrl + "/" + info.Key, key, nil } func (m *Minio) DeleteFile(key string) error { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() err := m.Client.RemoveObject(ctx, m.bucket, key, minio.RemoveObjectOptions{}) return err }