|
|
@@ -0,0 +1,280 @@
|
|
|
+package three_party
|
|
|
+
|
|
|
+import (
|
|
|
+ "errors"
|
|
|
+ "fmt"
|
|
|
+ uuid "github.com/iris-contrib/go.uuid"
|
|
|
+ "github.com/kataras/iris/v12"
|
|
|
+ "github.com/minio/minio-go/v7"
|
|
|
+ "github.com/minio/minio-go/v7/pkg/credentials"
|
|
|
+ "io"
|
|
|
+ "log"
|
|
|
+ "mime/multipart"
|
|
|
+ "os"
|
|
|
+ "path/filepath"
|
|
|
+ "strings"
|
|
|
+ "sync"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+var defaultFileBucket = "file"
|
|
|
+var defaultIconBucket = "icon"
|
|
|
+var defaultLocation = "us-east-1"
|
|
|
+var minioServerPool *sync.Pool
|
|
|
+
|
|
|
+// client version and secret, it should be from client side
|
|
|
+const (
|
|
|
+ UploadDir string = "./public/upload/"
|
|
|
+ UrlBase string = "/upload/"
|
|
|
+)
|
|
|
+
|
|
|
+// DstFile 文件
|
|
|
+type DstFile struct {
|
|
|
+ Name string `json:"name"`
|
|
|
+ Src string `json:"src"`
|
|
|
+}
|
|
|
+
|
|
|
+func init() {
|
|
|
+ minioServerPool = &sync.Pool{
|
|
|
+ New: func() interface{}{
|
|
|
+ return &MinioServe{}
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+type MinioFileObject struct {
|
|
|
+ BucketName string
|
|
|
+ ObjectName string
|
|
|
+ FilePath string
|
|
|
+ ContentType string
|
|
|
+ Config MinioConfig
|
|
|
+}
|
|
|
+
|
|
|
+type MinioConfig struct {
|
|
|
+ MinioHost string `json:"minioHost"`
|
|
|
+ MinioPort int64 `json:"minioPort"`
|
|
|
+ AccessKey string `json:"accessKey"`
|
|
|
+ SecretKey string `json:"secretKey"`
|
|
|
+ UseSSL bool `json:"useSSL"`
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func (c *MinioConfig) Validate() error {
|
|
|
+ if c.MinioHost == "" {
|
|
|
+ return errors.New("minio host not specified")
|
|
|
+ }
|
|
|
+
|
|
|
+ if c.MinioPort <= 0 {
|
|
|
+ return errors.New("minio port not specified")
|
|
|
+ }
|
|
|
+
|
|
|
+ if c.AccessKey == "" {
|
|
|
+ return errors.New("minio access key is not specified")
|
|
|
+ }
|
|
|
+
|
|
|
+ if c.SecretKey == "" {
|
|
|
+ return errors.New("minio secret key is not specified")
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (c *MinioConfig) GetClient()(*minio.Client, error) {
|
|
|
+ if err := c.Validate(); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ endPoint := fmt.Sprintf("%s:%d", c.MinioHost, c.MinioPort)
|
|
|
+ minioClient, err := minio.New(
|
|
|
+ endPoint,
|
|
|
+ &minio.Options{
|
|
|
+ Creds: credentials.NewStaticV4(c.AccessKey, c.SecretKey, ""),
|
|
|
+ Secure: c.UseSSL,
|
|
|
+ })
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ log.Fatalf("connect minio server fail %s url %s", err.Error(), endPoint)
|
|
|
+ }
|
|
|
+ return minioClient, nil
|
|
|
+}
|
|
|
+
|
|
|
+type MinioServerOption func(*MinioServe)
|
|
|
+type MinioServe struct {
|
|
|
+ Client *minio.Client
|
|
|
+}
|
|
|
+
|
|
|
+func NewMinioServer(opts ...MinioServerOption)(*MinioServe, error){
|
|
|
+ m := &MinioServe{}
|
|
|
+ for _, opt := range opts {
|
|
|
+ opt(m)
|
|
|
+ }
|
|
|
+
|
|
|
+ return m, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (m *MinioServe) Reset() {
|
|
|
+ m.Client = nil
|
|
|
+}
|
|
|
+
|
|
|
+func (m *MinioServe) checkBucket(ctx iris.Context, bucketName string) bool {
|
|
|
+ isExist, err1 := m.Client.BucketExists(ctx, bucketName)
|
|
|
+ if err1 != nil {
|
|
|
+ log.Fatalf("checkBucket error " + err1.Error())
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ if !isExist {
|
|
|
+ err2 := m.Client.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{Region: defaultLocation})
|
|
|
+ if err2 != nil {
|
|
|
+ log.Fatalf("checkBucket error " + err2.Error())
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+func (m *MinioServe) CheckBuckets(ctx iris.Context) bool {
|
|
|
+ b1 := m.checkBucket(ctx, defaultFileBucket)
|
|
|
+ b2 := m.checkBucket(ctx, defaultIconBucket)
|
|
|
+ return b1&&b2
|
|
|
+}
|
|
|
+
|
|
|
+func (m *MinioServe) UploadFile(ctx iris.Context, obj *MinioFileObject)(*minio.UploadInfo, error) {
|
|
|
+ bBucketExist := m.CheckBuckets(ctx)
|
|
|
+ if !bBucketExist {
|
|
|
+ return nil, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ info, err := m.Client.FPutObject(ctx, obj.BucketName, obj.ObjectName, obj.FilePath, minio.PutObjectOptions{
|
|
|
+ ContentType: obj.ContentType,
|
|
|
+ })
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ return &info, err
|
|
|
+ }
|
|
|
+
|
|
|
+ return &info, nil
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func acquireMinioServer() *MinioServe {
|
|
|
+ return minioServerPool.Get().(*MinioServe)
|
|
|
+}
|
|
|
+
|
|
|
+func releaseMinioServer(m *MinioServe) {
|
|
|
+ m.Reset()
|
|
|
+ minioServerPool.Put(m)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func UploadFile(ctx iris.Context) (*DstFile,error){
|
|
|
+ file ,info ,err := ctx.FormFile("uploadfile")
|
|
|
+ if err != nil {
|
|
|
+ return nil ,err
|
|
|
+ }
|
|
|
+ defer file.Close()
|
|
|
+
|
|
|
+ oldFileName := info.Filename
|
|
|
+ destFile, url := GenerateNewFileName(oldFileName)
|
|
|
+
|
|
|
+ out, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, 0666)
|
|
|
+ if err != nil{
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ defer out.Close()
|
|
|
+ _ ,err = io.Copy(out, file)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ outfile := &DstFile{Name: oldFileName ,Src:url }
|
|
|
+
|
|
|
+ return outfile, nil
|
|
|
+}
|
|
|
+
|
|
|
+// UploadMultiFiles Upload Multi Files
|
|
|
+func UploadMultiFiles(ctx iris.Context)(int, []DstFile, error){
|
|
|
+
|
|
|
+ maxSize := ctx.Application().ConfigurationReadOnly().GetPostMaxMemory()
|
|
|
+
|
|
|
+ err := ctx.Request().ParseMultipartForm(maxSize)
|
|
|
+ if err != nil {
|
|
|
+ return 0 , nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ form := ctx.Request().MultipartForm
|
|
|
+ files := form.File["files[]"]
|
|
|
+ count := len(files)
|
|
|
+
|
|
|
+ failures := 0
|
|
|
+ dstIndex := 1
|
|
|
+
|
|
|
+ outFiles := []DstFile{}
|
|
|
+ for _, file := range files {
|
|
|
+ url, err := SaveUploadFile(file)
|
|
|
+ if err != nil {
|
|
|
+ failures++
|
|
|
+ }else{
|
|
|
+ out := DstFile{Name: file.Filename ,Src:url}
|
|
|
+ outFiles = append(outFiles, out)
|
|
|
+ dstIndex++
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ num := count - failures
|
|
|
+
|
|
|
+ return num ,outFiles ,nil
|
|
|
+}
|
|
|
+
|
|
|
+func SaveUploadFile(fh *multipart.FileHeader)(string, error){
|
|
|
+ src ,err := fh.Open()
|
|
|
+ if err != nil {
|
|
|
+ return "" ,err
|
|
|
+ }
|
|
|
+ defer src.Close()
|
|
|
+
|
|
|
+ oldFileName := fh.Filename
|
|
|
+ srcFile, urlFile := GenerateNewFileName(oldFileName)
|
|
|
+
|
|
|
+ out, err := os.OpenFile(srcFile ,os.O_WRONLY|os.O_CREATE ,os.FileMode(0666))
|
|
|
+ if err != nil {
|
|
|
+ return "" ,err
|
|
|
+ }
|
|
|
+
|
|
|
+ defer out.Close()
|
|
|
+
|
|
|
+ _, err = io.Copy(out, src)
|
|
|
+
|
|
|
+ return urlFile, err
|
|
|
+}
|
|
|
+
|
|
|
+// CreateDateDir Create date directory
|
|
|
+func CreateDateDir() (srcPath, urlPath string) {
|
|
|
+ folderName := time.Now().Format("20060102")
|
|
|
+ src := filepath.Join(UploadDir, folderName)
|
|
|
+ url := filepath.Join(UrlBase, folderName)
|
|
|
+ _, err := os.Stat(srcPath)
|
|
|
+ if os.IsNotExist(err ){
|
|
|
+ _ = os.Mkdir(src, os.ModePerm)
|
|
|
+ _ = os.Chmod(src, os.ModePerm)
|
|
|
+ }
|
|
|
+
|
|
|
+ return src ,url
|
|
|
+}
|
|
|
+
|
|
|
+// GenerateNewFileName Generate new file name
|
|
|
+func GenerateNewFileName(oldFileName string) (srcPath, urlPath string) {
|
|
|
+ u1, _ := uuid.NewV4()
|
|
|
+ newFileName := u1.String()
|
|
|
+ src , url := CreateDateDir()
|
|
|
+
|
|
|
+ dotIndex := strings.LastIndex(oldFileName, ".")
|
|
|
+ if dotIndex != -1 && dotIndex != 0 {
|
|
|
+ newFileName += oldFileName[dotIndex:]
|
|
|
+ }
|
|
|
+
|
|
|
+ src = filepath.Join(src, newFileName)
|
|
|
+ url = filepath.Join(url, newFileName)
|
|
|
+
|
|
|
+ return src, url
|
|
|
+}
|