|
|
|
|
|
|
|
|
|
package file |
|
|
|
import ( |
|
"fmt" |
|
"io" |
|
"mime/multipart" |
|
"os" |
|
"path" |
|
"sync" |
|
|
|
"github.com/GoAdminGroup/go-admin/plugins/admin/modules" |
|
) |
|
|
|
|
|
type Uploader interface { |
|
Upload(*multipart.Form) error |
|
} |
|
|
|
|
|
type UploaderGenerator func() Uploader |
|
|
|
var uploaderList = map[string]UploaderGenerator{ |
|
"local": GetLocalFileUploader, |
|
} |
|
|
|
var upMu sync.Mutex |
|
|
|
|
|
|
|
|
|
func AddUploader(name string, up UploaderGenerator) { |
|
upMu.Lock() |
|
defer upMu.Unlock() |
|
if up == nil { |
|
panic("uploader generator is nil") |
|
} |
|
if _, dup := uploaderList[name]; dup { |
|
panic("add uploader generator twice " + name) |
|
} |
|
uploaderList[name] = up |
|
} |
|
|
|
|
|
func GetFileEngine(name string) Uploader { |
|
if up, ok := uploaderList[name]; ok { |
|
return up() |
|
} |
|
panic("wrong uploader name") |
|
} |
|
|
|
|
|
type UploadFun func(*multipart.FileHeader, string) (string, error) |
|
|
|
|
|
func Upload(c UploadFun, form *multipart.Form) error { |
|
var ( |
|
suffix string |
|
filename string |
|
) |
|
|
|
for k := range form.File { |
|
for _, fileObj := range form.File[k] { |
|
suffix = path.Ext(fileObj.Filename) |
|
filename = modules.Uuid() + suffix |
|
|
|
pathStr, err := c(fileObj, filename) |
|
|
|
if err != nil { |
|
return err |
|
} |
|
|
|
form.Value[k] = append(form.Value[k], pathStr) |
|
form.Value[k+"_size"] = append(form.Value[k+"_size"], fmt.Sprintf("%d", fileObj.Size)) |
|
} |
|
} |
|
|
|
return nil |
|
} |
|
|
|
|
|
func SaveMultipartFile(fh *multipart.FileHeader, path string) error { |
|
f, err := fh.Open() |
|
if err != nil { |
|
return err |
|
} |
|
|
|
if ff, ok := f.(*os.File); ok { |
|
|
|
if err := f.Close(); err != nil { |
|
return err |
|
} |
|
|
|
|
|
|
|
if os.Rename(ff.Name(), path) == nil { |
|
return nil |
|
} |
|
|
|
|
|
f, err = fh.Open() |
|
if err != nil { |
|
return err |
|
} |
|
} |
|
|
|
defer func() { |
|
if err2 := f.Close(); err2 != nil { |
|
err = err2 |
|
} |
|
}() |
|
|
|
ff, err := os.Create(path) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
defer func() { |
|
if err2 := ff.Close(); err2 != nil { |
|
err = err2 |
|
} |
|
}() |
|
_, err = copyZeroAlloc(ff, f) |
|
return err |
|
} |
|
|
|
func copyZeroAlloc(w io.Writer, r io.Reader) (int64, error) { |
|
buf := copyBufPool.Get().([]byte) |
|
n, err := io.CopyBuffer(w, r, buf) |
|
copyBufPool.Put(buf) |
|
return n, err |
|
} |
|
|
|
var copyBufPool = sync.Pool{ |
|
New: func() interface{} { |
|
return make([]byte, 4096) |
|
}, |
|
} |
|
|