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 } } // if strings.HasPrefix(dUrl, "/api") { // dUrl = d.Address + dUrl // } 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 } // 将 map 转换为 http.Header 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) } //func (d *FastWebdav) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) { // return nil, errs.NotSupport //} var _ driver.Driver = (*FastWebdav)(nil)