qiniu-driver/driver.go
Lunny Xiao 6e505f23c4
All checks were successful
continuous-integration/drone/push Build is passing
update goftp.io interface (#1)
2019-10-27 08:33:26 +00:00

245 lines
5.6 KiB
Go

package qiniudriver
import (
"errors"
"fmt"
"io"
"net/http"
"strings"
"github.com/qiniu/api.v6/auth/digest"
"github.com/qiniu/api.v6/conf"
qio "github.com/qiniu/api.v6/io"
"github.com/qiniu/api.v6/rs"
"github.com/qiniu/api.v6/rsf"
"goftp.io/server"
)
type QiniuDriver struct {
curDir string
client rs.Client
client2 rsf.Client
bucket string
}
func (driver *QiniuDriver) Init(conn *server.Conn) {
//driver.conn = conn
}
func (driver *QiniuDriver) ChangeDir(path string) error {
f, err := driver.Stat(path)
if err != nil {
return err
}
if !f.IsDir() {
return errors.New("not a dir")
}
driver.curDir = path
return nil
}
func (driver *QiniuDriver) Stat(key string) (server.FileInfo, error) {
if strings.HasSuffix(key, "/") {
return &FileInfo{key, true, rs.Entry{}}, nil
}
entry, err := driver.client.Stat(nil, driver.bucket, strings.TrimLeft(key, "/"))
if err != nil {
entries, _, _ := driver.client2.ListPrefix(nil, driver.bucket, strings.TrimLeft(key, "/")+"/", "", 1)
if len(entries) > 0 {
return &FileInfo{key, true, rs.Entry{}}, nil
}
return nil, errors.New("dir not exists")
}
return &FileInfo{key, false, entry}, nil
}
func (driver *QiniuDriver) ListDir(prefix string, callback func(server.FileInfo) error) error {
d := strings.TrimLeft(prefix, "/")
if d != "" {
d = d + "/"
}
entries, _, err := driver.client2.ListPrefix(nil, driver.bucket, d, "", 1000)
if err == io.EOF {
err = nil
}
if err != nil {
return err
}
dirCache := make(map[string]bool)
for _, entry := range entries {
if prefix != "/" && prefix != "" && !strings.HasPrefix(entry.Key, d) {
continue
}
key := strings.TrimLeft(strings.TrimLeft(entry.Key, d), "/")
if key == "" {
continue
}
var f server.FileInfo
if strings.Contains(key, "/") {
key := strings.Trim(strings.Split(key, "/")[0], "/")
if _, ok := dirCache[key]; ok {
continue
}
dirCache[key] = true
f = &FileInfo{name: key, isDir: true}
} else {
f = &FileInfo{
name: key,
Entry: rs.Entry{
Hash: entry.Hash,
Fsize: entry.Fsize,
PutTime: entry.PutTime,
MimeType: entry.MimeType,
Customer: "",
},
}
}
err = callback(f)
if err != nil {
return err
}
}
return nil
}
func (driver *QiniuDriver) DeleteDir(key string) error {
d := strings.TrimLeft(key, "/")
entries, _, err := driver.client2.ListPrefix(nil, driver.bucket, d, "", 1000)
if err == io.EOF {
err = nil
}
if err != nil {
return err
}
if len(entries) == 0 {
return nil
}
delentries := make([]rs.EntryPath, 0)
for _, entry := range entries {
delentries = append(delentries, rs.EntryPath{
Bucket: driver.bucket,
Key: entry.Key,
})
}
fmt.Println("delete entries:", delentries)
_, err = driver.client.BatchDelete(nil, delentries)
return err
}
func (driver *QiniuDriver) DeleteFile(key string) error {
fmt.Println("delete file", key)
return driver.client.Delete(nil, driver.bucket, strings.TrimLeft(key, "/"))
}
func (driver *QiniuDriver) Rename(keySrc, keyDest string) error {
fmt.Println("rename from", keySrc, keyDest)
var from = strings.TrimLeft(keySrc, "/")
var to = strings.TrimLeft(keyDest, "/")
info, err := driver.client.Stat(nil, driver.bucket, from)
if err != nil && strings.Contains(err.Error(), "no such file or directory") {
from = strings.TrimLeft(keySrc, "/") + "/"
to = strings.TrimLeft(keyDest, "/") + "/"
info, err = driver.client.Stat(nil, driver.bucket, from)
if err != nil {
return err
}
entries, _, err := driver.client2.ListPrefix(nil, driver.bucket, from, "", 1000)
if err != nil {
return err
}
for _, entry := range entries {
newKey := strings.Replace(entry.Key, from, to, 1)
err = driver.client.Move(nil, driver.bucket, entry.Key, driver.bucket, newKey)
if err != nil {
return err
}
}
return nil
}
if err != nil {
fmt.Println(err)
return err
}
fmt.Println(info, from, to)
return driver.client.Move(nil, driver.bucket, from, driver.bucket, to)
}
func (driver *QiniuDriver) MakeDir(path string) error {
dir := strings.TrimLeft(path, "/") + "/"
fmt.Println("mkdir", dir)
var s string
reader := strings.NewReader(s)
_, err := driver.PutFile(dir, reader, false)
return err
}
func (driver *QiniuDriver) GetFile(key string, offset int64) (int64, io.ReadCloser, error) {
stat, err := driver.Stat(key)
if err != nil {
return 0, nil, err
}
key = strings.TrimLeft(key, "/")
domain := fmt.Sprintf("%s.qiniudn.com", driver.bucket)
baseUrl := rs.MakeBaseUrl(domain, key)
policy := rs.GetPolicy{}
downUrl := policy.MakeRequest(baseUrl, nil)
resp, err := http.Get(downUrl)
if err != nil {
return 0, nil, err
}
return stat.Size(), NewSkipReadCloser(resp.Body, offset), nil
}
func (driver *QiniuDriver) PutFile(key string, data io.Reader, appendData bool) (int64, error) {
var err error
var ret qio.PutRet
var extra = &qio.PutExtra{}
putPolicy := rs.PutPolicy{
Scope: driver.bucket,
}
uptoken := putPolicy.Token(nil)
rd := CountReader(data)
err = qio.Put(nil, &ret, uptoken, strings.TrimLeft(key, "/"), rd, extra)
if err != nil {
return 0, err
}
return int64(rd.Size()), nil
}
type QiniuDriverFactory struct {
bucket string
}
func NewQiniuDriverFactory(accessKey, secretKey, bucket string) server.DriverFactory {
conf.ACCESS_KEY = accessKey
conf.SECRET_KEY = secretKey
return &QiniuDriverFactory{bucket}
}
func (factory *QiniuDriverFactory) NewDriver() (server.Driver, error) {
mac := &digest.Mac{
AccessKey: conf.ACCESS_KEY,
SecretKey: []byte(conf.SECRET_KEY),
}
client := rs.New(mac)
client2 := rsf.New(mac)
return &QiniuDriver{"/", client, client2, factory.bucket}, nil
}