|
package fastwebdav |
|
|
|
import ( |
|
"context" |
|
"encoding/base64" |
|
"encoding/json" |
|
"fmt" |
|
"io" |
|
"net/http" |
|
"strconv" |
|
"strings" |
|
|
|
"github.com/alist-org/alist/v3/drivers/base" |
|
"github.com/alist-org/alist/v3/internal/driver" |
|
"github.com/alist-org/alist/v3/internal/model" |
|
"github.com/alist-org/alist/v3/pkg/utils" |
|
"github.com/go-resty/resty/v2" |
|
) |
|
|
|
type FastWebdav struct { |
|
model.Storage |
|
Addition |
|
} |
|
|
|
func (d *FastWebdav) Config() driver.Config { |
|
return config |
|
} |
|
|
|
func (d *FastWebdav) GetAddition() driver.Additional { |
|
return &d.Addition |
|
} |
|
|
|
func (d *FastWebdav) Init(ctx context.Context) error { |
|
d.Address = strings.TrimSuffix(d.Address, "/") |
|
return nil |
|
} |
|
|
|
func (d *FastWebdav) Drop(ctx context.Context) error { |
|
return nil |
|
} |
|
|
|
func (d *FastWebdav) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { |
|
files, err := d.getFiles(dir.GetPath(), dir.GetID()) |
|
if err != nil { |
|
return nil, err |
|
} |
|
return utils.SliceConvert(files, func(src File) (model.Obj, error) { |
|
return fileToObj(src), nil |
|
}) |
|
} |
|
|
|
func (d *FastWebdav) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { |
|
var dUrl string |
|
b, _ := base64.StdEncoding.DecodeString(file.GetID()) |
|
|
|
var f File |
|
_ = json.Unmarshal(b, &f) |
|
url := f.Provider + "/url" |
|
|
|
if len(f.DownloadUrl) > 4 { |
|
dUrl = f.DownloadUrl |
|
} else { |
|
err := d.request(http.MethodPost, url, func(req *resty.Request) { |
|
req.SetBody(f) |
|
}, &dUrl) |
|
if err != nil { |
|
return nil, err |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
link := &model.Link{ |
|
URL: dUrl, |
|
} |
|
|
|
if len(f.PlayHeaders) > 4 { |
|
var headers map[string]string |
|
err := json.Unmarshal([]byte(f.PlayHeaders), &headers) |
|
if err != nil { |
|
fmt.Println("无法解析自定义Header:", err) |
|
return link, err |
|
} |
|
|
|
|
|
header := make(http.Header) |
|
for key, value := range headers { |
|
header.Add(key, value) |
|
} |
|
|
|
link.Header = header |
|
} |
|
return link, nil |
|
} |
|
|
|
func (d *FastWebdav) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { |
|
return d.request(http.MethodPut, "/directory", func(req *resty.Request) { |
|
req.SetBody(base.Json{ |
|
"path": parentDir.GetPath() + "/" + dirName, |
|
}) |
|
}, nil) |
|
} |
|
|
|
func (d *FastWebdav) Move(ctx context.Context, srcObj, dstDir model.Obj) error { |
|
body := base.Json{ |
|
"action": "move", |
|
"src_dir": srcObj.GetPath(), |
|
"dst": dstDir.GetPath(), |
|
"src": convertSrc(srcObj), |
|
} |
|
return d.request(http.MethodPatch, "/object", func(req *resty.Request) { |
|
req.SetBody(body) |
|
}, nil) |
|
} |
|
|
|
func (d *FastWebdav) Rename(ctx context.Context, srcObj model.Obj, newName string) error { |
|
body := base.Json{ |
|
"action": "rename", |
|
"new_name": newName, |
|
"src": convertSrc(srcObj), |
|
} |
|
return d.request(http.MethodPatch, "/object/rename", func(req *resty.Request) { |
|
req.SetBody(body) |
|
}, nil) |
|
} |
|
|
|
func (d *FastWebdav) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { |
|
body := base.Json{ |
|
"src_dir": srcObj.GetPath(), |
|
"dst": dstDir.GetPath(), |
|
"src": convertSrc(srcObj), |
|
} |
|
return d.request(http.MethodPost, "/object/copy", func(req *resty.Request) { |
|
req.SetBody(body) |
|
}, nil) |
|
} |
|
|
|
func (d *FastWebdav) Remove(ctx context.Context, obj model.Obj) error { |
|
body := convertSrc(obj) |
|
err := d.request(http.MethodDelete, "/object", func(req *resty.Request) { |
|
req.SetBody(body) |
|
}, nil) |
|
return err |
|
} |
|
|
|
func (d *FastWebdav) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error { |
|
if io.ReadCloser(stream) == http.NoBody { |
|
return d.create(ctx, dstDir, stream) |
|
} |
|
var r DirectoryResp |
|
err := d.request(http.MethodGet, "/directory"+dstDir.GetPath(), nil, &r) |
|
if err != nil { |
|
return err |
|
} |
|
uploadBody := base.Json{ |
|
"path": dstDir.GetPath(), |
|
"size": stream.GetSize(), |
|
"name": stream.GetName(), |
|
"policy_id": r.Policy.Id, |
|
"last_modified": stream.ModTime().Unix(), |
|
} |
|
var u UploadInfo |
|
err = d.request(http.MethodPut, "/file/upload", func(req *resty.Request) { |
|
req.SetBody(uploadBody) |
|
}, &u) |
|
if err != nil { |
|
return err |
|
} |
|
var chunkSize = u.ChunkSize |
|
var buf []byte |
|
var chunk int |
|
for { |
|
var n int |
|
buf = make([]byte, chunkSize) |
|
n, err = io.ReadAtLeast(stream, buf, chunkSize) |
|
if err != nil && err != io.ErrUnexpectedEOF { |
|
if err == io.EOF { |
|
return nil |
|
} |
|
return err |
|
} |
|
|
|
if n == 0 { |
|
break |
|
} |
|
buf = buf[:n] |
|
err = d.request(http.MethodPost, "/file/upload/"+u.SessionID+"/"+strconv.Itoa(chunk), func(req *resty.Request) { |
|
req.SetHeader("Content-Type", "application/octet-stream") |
|
req.SetHeader("Content-Length", strconv.Itoa(n)) |
|
req.SetBody(buf) |
|
}, nil) |
|
if err != nil { |
|
break |
|
} |
|
chunk++ |
|
|
|
} |
|
return err |
|
} |
|
|
|
func (d *FastWebdav) create(ctx context.Context, dir model.Obj, file model.Obj) error { |
|
body := base.Json{"path": dir.GetPath() + "/" + file.GetName()} |
|
if file.IsDir() { |
|
err := d.request(http.MethodPut, "directory", func(req *resty.Request) { |
|
req.SetBody(body) |
|
}, nil) |
|
return err |
|
} |
|
return d.request(http.MethodPost, "/file/create", func(req *resty.Request) { |
|
req.SetBody(body) |
|
}, nil) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
var _ driver.Driver = (*FastWebdav)(nil) |
|
|