diff --git a/kit/oss/aliyun.go b/kit/oss/aliyun.go new file mode 100644 index 0000000..33f3956 --- /dev/null +++ b/kit/oss/aliyun.go @@ -0,0 +1,88 @@ +package oss + +import ( + "github.com/pkg/errors" + "io" + + aliOssSdk "github.com/aliyun/aliyun-oss-go-sdk/oss" +) + +//oss 上传配置 +type AliConfig struct { + AccessKey string `json:"access_key"` + SecretKey string `json:"secret_key"` + Bucket string `json:"bucket"` + Endpoint string `json:"endpoint"` +} + +//oss 根据参数来创建 Bucket +func (c *AliConfig) CreateBucket() (bucket *aliOssSdk.Bucket, err error) { + // Endpoint以杭州为例,其它Region请按实际情况填写。 + endpoint := c.Endpoint + // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。 + accessKeyId := c.AccessKey + accessKeySecret := c.SecretKey + bucketName := c.Bucket + // 创建OSSClient实例。 + ossClient, err := aliOssSdk.New(endpoint, accessKeyId, accessKeySecret) + if err != nil { + return nil, errors.Wrapf(err, "创建 aliyun OSSClient实例失败") + } + // 获取存储空间。 + bucket, err = ossClient.Bucket(bucketName) + if err != nil { + return nil, errors.Wrapf(err, "获取 aliyun OSS 存储空间失败") + } + return +} + +//oss 上传客户端 +type aliOss struct { + bucket *aliOssSdk.Bucket +} + +func NewAliOss(c AliConfig) Driver { + bucket, err := c.CreateBucket() + if err != nil { + panic(any(err)) + } + return &aliOss{ + bucket: bucket, + } +} + +// Put 上传 +func (c *aliOss) Put(objectName string, localFileName string) error { + err := c.bucket.PutObjectFromFile(objectName, localFileName) + if err != nil { + return errors.Wrapf(err, "put oss file fail") + } + return nil +} + +func (c *aliOss) PutObj(objectName string, file io.Reader) error { + err := c.bucket.PutObject(objectName, file) + if err != nil { + return errors.Wrapf(err, "put oss file fail") + } + return nil +} + +// Get 下载 +func (c *aliOss) Get(objectName, downloadedFileName string) error { + err := c.bucket.GetObjectToFile(objectName, downloadedFileName) + if err != nil { + return errors.Wrapf(err, "get oss file fail") + } + return nil +} + +// Del 删除 +func (c *aliOss) Del(objectName string) error { + // 删除文件。 + err := c.bucket.DeleteObject(objectName) + if err != nil { + return errors.Wrapf(err, "del oss file fail") + } + return nil +} diff --git a/kit/oss/build.go b/kit/oss/build.go new file mode 100644 index 0000000..5bb346a --- /dev/null +++ b/kit/oss/build.go @@ -0,0 +1,40 @@ +package oss + +import ( + "net/http" + "os" + "path" + "time" + + "github.com/google/uuid" +) + +func BuildName(fileName, fileType string) (string, error) { + t := time.Now().Format("20060102") + newUUID, _ := uuid.NewUUID() + ext := path.Ext(fileName) + return t + "/" + fileType + "/" + newUUID.String() + ext, nil +} + +func GetFileContentType(fileName string) (string, error) { + + out, err := os.Open(fileName) + if err != nil { + return "", err + } + defer out.Close() + + // Only the first 512 bytes are used to sniff the content type. + buffer := make([]byte, 512) + + _, err = out.Read(buffer) + if err != nil { + return "", err + } + + // Use the net/http package's handy DectectContentType function. Always returns a valid + // content-type by returning "application/octet-stream" if no others seemed to match. + contentType := http.DetectContentType(buffer) + + return contentType, nil +} diff --git a/kit/oss/minio.go b/kit/oss/minio.go new file mode 100644 index 0000000..da335dc --- /dev/null +++ b/kit/oss/minio.go @@ -0,0 +1,95 @@ +package oss + +import ( + "context" + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" + "github.com/pkg/errors" + "io" + "log" +) + +//oss 上传配置 +type MiniOConfig struct { + Endpoint string + AccessKeyID string + SecretAccessKey string + BucketName string + Location string + UseSSL bool + TargetFilePath string +} + +func (m *MiniOConfig) CreateClient() *minio.Client { + client, err := minio.New(m.Endpoint, &minio.Options{ + Creds: credentials.NewStaticV4(m.AccessKeyID, m.SecretAccessKey, ""), + Secure: m.UseSSL, + }) + if err != nil { + log.Fatalln(err) + } + isExists, err := client.BucketExists(context.Background(), m.BucketName) + if err != nil { + log.Println(err) + return nil + } + + if !isExists { + err = client.MakeBucket(context.Background(), m.BucketName, minio.MakeBucketOptions{Region: m.Location}) + if err != nil { + log.Println(err) + return nil + } + } + return client +} + +type minioOss struct { + client *minio.Client + bucketName string +} + +func NewMiniOss(c MiniOConfig) Driver { + client := c.CreateClient() + return &minioOss{ + client: client, + bucketName: c.BucketName, + } +} + +// contentType 需要上传的文件类型 例如application/zip +func (m *minioOss) Put(objectName, localFileName string) error { + contentType, err := GetFileContentType(localFileName) + if err != nil { + return err + } + _, err = m.client.FPutObject(context.Background(), m.bucketName, objectName, localFileName, minio.PutObjectOptions{ContentType: contentType}) + if err != nil { + return errors.Wrapf(err, "put oss file fail") + } + return nil +} + +func (m *minioOss) PutObj(objectName string, file io.Reader) error { + _, err := m.client.PutObject(context.Background(), m.bucketName, objectName, file, -1, minio.PutObjectOptions{}) + if err != nil { + return errors.Wrapf(err, "put oss file fail") + } + return nil +} + +func (m *minioOss) Get(objectName, downloadedFileName string) error { + err := m.client.FGetObject(context.Background(), m.bucketName, objectName, downloadedFileName, minio.GetObjectOptions{}) + if err != nil { + return errors.Wrapf(err, "get oss file fail") + } + return nil +} + +func (m *minioOss) Del(objectName string) error { + err := m.client.RemoveObject(context.Background(), m.bucketName, objectName, minio.RemoveObjectOptions{GovernanceBypass: true}) + if err != nil { + return errors.Wrapf(err, "qiniu oss del file fail") + } + return nil +} diff --git a/kit/oss/oss.go b/kit/oss/oss.go new file mode 100644 index 0000000..3ecfcd4 --- /dev/null +++ b/kit/oss/oss.go @@ -0,0 +1,16 @@ +package oss + +import "io" + +// Driver oss驱动接口定义 +type Driver interface { + + //上传 + Put(objectName, localFileName string) error + + PutObj(objectName string, file io.Reader) error + //下载 + Get(objectName, downloadedFileName string) error + //删除 + Del(objectName string) error +} diff --git a/kit/oss/qiniu.go b/kit/oss/qiniu.go new file mode 100644 index 0000000..0a4702d --- /dev/null +++ b/kit/oss/qiniu.go @@ -0,0 +1,115 @@ +package oss + +import ( + "context" + "io" + utilFile "pandax/kit/file" + + "github.com/pkg/errors" + "github.com/qiniu/go-sdk/v7/auth/qbox" + "github.com/qiniu/go-sdk/v7/storage" +) + +type QiniuConfig struct { + AccessKey string + SecretKey string + Bucket string + PolicyExpires uint64 // 上传凭证的有效时间,单位秒 + Zone *storage.Zone // 空间所在的机房 + UseHTTPS bool // 是否使用https域名 + UseCdnDomains bool // 是否使用cdn加速域名 + CentralRsHost string // 中心机房的RsHost,用于list bucket + Domain string // 外链域名 +} + +type qiniuOss struct { + config QiniuConfig +} + +func NewQnOss(config QiniuConfig) Driver { + return &qiniuOss{ + config: config, + } +} + +func (q *qiniuOss) Put(objectName, localFileName string) error { + // 鉴权 + mac := qbox.NewMac(q.config.AccessKey, q.config.SecretKey) + // 上传策略 + putPolicy := storage.PutPolicy{ + Scope: q.config.Bucket, + Expires: q.config.PolicyExpires, + } + // 获取上传token + upToken := putPolicy.UploadToken(mac) + + // 上传Config对象 + cfg := storage.Config{ + Zone: q.config.Zone, //指定上传的区域 + UseHTTPS: q.config.UseHTTPS, // 是否使用https域名 + UseCdnDomains: q.config.UseCdnDomains, //是否使用CDN上传加速 + } + // 构建表单上传的对象 + formUploader := storage.NewFormUploader(&cfg) + ret := storage.PutRet{} + // 上传文件 + err := formUploader.PutFile(context.Background(), &ret, upToken, objectName, localFileName, nil) + if err != nil { + return errors.Wrapf(err, "qiniu oss put file fail") + } + return nil +} + +func (q *qiniuOss) PutObj(objectName string, file io.Reader) error { + // 鉴权 + mac := qbox.NewMac(q.config.AccessKey, q.config.SecretKey) + // 上传策略 + putPolicy := storage.PutPolicy{ + Scope: q.config.Bucket, + Expires: q.config.PolicyExpires, + } + // 获取上传token + upToken := putPolicy.UploadToken(mac) + + // 上传Config对象 + cfg := storage.Config{ + Zone: q.config.Zone, //指定上传的区域 + UseHTTPS: q.config.UseHTTPS, // 是否使用https域名 + UseCdnDomains: q.config.UseCdnDomains, //是否使用CDN上传加速 + } + // 构建表单上传的对象 + formUploader := storage.NewFormUploader(&cfg) + ret := storage.PutRet{} + + // 上传文件 + err := formUploader.Put(context.Background(), &ret, upToken, objectName, file, 0, nil) + if err != nil { + return errors.Wrapf(err, "qiniu oss put file fail") + } + return nil +} + +func (q *qiniuOss) Get(objectName, downloadedFileName string) error { + publicAccessURL := storage.MakePublicURL(q.config.Domain, objectName) + err := utilFile.DownloadFile(publicAccessURL, downloadedFileName) + if err != nil { + return errors.Wrapf(err, "qiniu oss get file fail") + } + return nil +} + +func (q *qiniuOss) Del(objectName string) error { + mac := qbox.NewMac(q.config.AccessKey, q.config.SecretKey) + cfg := storage.Config{ + Zone: q.config.Zone, //指定上传的区域 + UseHTTPS: q.config.UseHTTPS, // 是否使用https域名 + UseCdnDomains: q.config.UseCdnDomains, //是否使用CDN上传加速 + } + bucketManager := storage.NewBucketManager(mac, &cfg) + + err := bucketManager.Delete(q.config.Bucket, objectName) + if err != nil { + return errors.Wrapf(err, "qiniu oss del file fail") + } + return nil +}