mirror of https://github.com/Xhofe/alist
✨ onedrive webdav write
parent
3c03344ef1
commit
606134f39c
|
@ -210,23 +210,85 @@ func (driver Onedrive) Preview(path string, account *model.Account) (interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (driver Onedrive) MakeDir(path string, account *model.Account) error {
|
func (driver Onedrive) MakeDir(path string, account *model.Account) error {
|
||||||
return base.ErrNotImplement
|
url := driver.GetMetaUrl(account, false, utils.Dir(path)) + "/children"
|
||||||
|
data := base.Json{
|
||||||
|
"name": utils.Base(path),
|
||||||
|
"folder": base.Json{},
|
||||||
|
"@microsoft.graph.conflictBehavior": "rename",
|
||||||
|
}
|
||||||
|
_, err := driver.Request(url, base.Post, nil, nil, nil, &data, nil, account)
|
||||||
|
if err == nil {
|
||||||
|
_ = base.DeleteCache(utils.Dir(path), account)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (driver Onedrive) Move(src string, dst string, account *model.Account) error {
|
func (driver Onedrive) Move(src string, dst string, account *model.Account) error {
|
||||||
return base.ErrNotImplement
|
log.Debugf("onedrive move")
|
||||||
|
dstParentFile, err := driver.GetFile(account, utils.Dir(dst))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := base.Json{
|
||||||
|
"parentReference": base.Json{
|
||||||
|
"id": dstParentFile.Id,
|
||||||
|
},
|
||||||
|
"name": utils.Base(dst),
|
||||||
|
}
|
||||||
|
url := driver.GetMetaUrl(account, false, src)
|
||||||
|
_, err = driver.Request(url, base.Patch, nil, nil, nil, &data, nil, account)
|
||||||
|
if err == nil {
|
||||||
|
_ = base.DeleteCache(utils.Dir(src), account)
|
||||||
|
if utils.Dir(src) != utils.Dir(dst) {
|
||||||
|
_ = base.DeleteCache(utils.Dir(dst), account)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (driver Onedrive) Copy(src string, dst string, account *model.Account) error {
|
func (driver Onedrive) Copy(src string, dst string, account *model.Account) error {
|
||||||
return base.ErrNotImplement
|
dstParentFile, err := driver.GetFile(account, utils.Dir(dst))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := base.Json{
|
||||||
|
"parentReference": base.Json{
|
||||||
|
"driveId": dstParentFile.ParentReference.DriveId,
|
||||||
|
"id": dstParentFile.Id,
|
||||||
|
},
|
||||||
|
"name": utils.Base(dst),
|
||||||
|
}
|
||||||
|
url := driver.GetMetaUrl(account, false, src) + "/copy"
|
||||||
|
_, err = driver.Request(url, base.Post, nil, nil, nil, &data, nil, account)
|
||||||
|
if err == nil {
|
||||||
|
_ = base.DeleteCache(utils.Dir(src), account)
|
||||||
|
if utils.Dir(src) != utils.Dir(dst) {
|
||||||
|
_ = base.DeleteCache(utils.Dir(dst), account)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (driver Onedrive) Delete(path string, account *model.Account) error {
|
func (driver Onedrive) Delete(path string, account *model.Account) error {
|
||||||
return base.ErrNotImplement
|
url := driver.GetMetaUrl(account, false, path)
|
||||||
|
_, err := driver.Request(url, base.Delete, nil, nil, nil, nil, nil, account)
|
||||||
|
if err == nil {
|
||||||
|
_ = base.DeleteCache(utils.Dir(path), account)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (driver Onedrive) Upload(file *model.FileStream, account *model.Account) error {
|
func (driver Onedrive) Upload(file *model.FileStream, account *model.Account) error {
|
||||||
return base.ErrNotImplement
|
var err error
|
||||||
|
if file.GetSize() <= 4*1024*1024 {
|
||||||
|
err = driver.UploadSmall(file, account)
|
||||||
|
} else {
|
||||||
|
err = driver.UploadBig(file, account)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
_ = base.DeleteCache(utils.Dir(file.ParentPath), account)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ base.Driver = (*Onedrive)(nil)
|
var _ base.Driver = (*Onedrive)(nil)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package onedrive
|
package onedrive
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Xhofe/alist/conf"
|
"github.com/Xhofe/alist/conf"
|
||||||
|
@ -8,8 +9,13 @@ import (
|
||||||
"github.com/Xhofe/alist/model"
|
"github.com/Xhofe/alist/model"
|
||||||
"github.com/Xhofe/alist/utils"
|
"github.com/Xhofe/alist/utils"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -111,6 +117,7 @@ func (driver Onedrive) refreshToken(account *model.Account) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type OneFile struct {
|
type OneFile struct {
|
||||||
|
Id string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
LastModifiedDateTime *time.Time `json:"lastModifiedDateTime"`
|
LastModifiedDateTime *time.Time `json:"lastModifiedDateTime"`
|
||||||
|
@ -118,11 +125,14 @@ type OneFile struct {
|
||||||
File struct {
|
File struct {
|
||||||
MimeType string `json:"mimeType"`
|
MimeType string `json:"mimeType"`
|
||||||
} `json:"file"`
|
} `json:"file"`
|
||||||
Thumbnails []struct{
|
Thumbnails []struct {
|
||||||
Medium struct{
|
Medium struct {
|
||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
} `json:"medium"`
|
} `json:"medium"`
|
||||||
} `json:"thumbnails"`
|
} `json:"thumbnails"`
|
||||||
|
ParentReference struct {
|
||||||
|
DriveId string `json:"driveId"`
|
||||||
|
} `json:"parentReference"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OneFiles struct {
|
type OneFiles struct {
|
||||||
|
@ -144,6 +154,7 @@ func (driver Onedrive) FormatFile(file *OneFile) *model.File {
|
||||||
UpdatedAt: file.LastModifiedDateTime,
|
UpdatedAt: file.LastModifiedDateTime,
|
||||||
Driver: driver.Config().Name,
|
Driver: driver.Config().Name,
|
||||||
Url: file.Url,
|
Url: file.Url,
|
||||||
|
Id: file.Id,
|
||||||
}
|
}
|
||||||
if len(file.Thumbnails) > 0 {
|
if len(file.Thumbnails) > 0 {
|
||||||
f.Thumbnail = file.Thumbnails[0].Medium.Url
|
f.Thumbnail = file.Thumbnails[0].Medium.Url
|
||||||
|
@ -198,6 +209,109 @@ func (driver Onedrive) GetFile(account *model.Account, path string) (*OneFile, e
|
||||||
return &file, nil
|
return &file, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (driver Onedrive) Request(url string, method int, headers, query, form map[string]string, data interface{}, resp interface{}, account *model.Account) ([]byte, error) {
|
||||||
|
rawUrl := url
|
||||||
|
if account.APIProxyUrl != "" {
|
||||||
|
url = fmt.Sprintf("%s/%s", account.APIProxyUrl, url)
|
||||||
|
}
|
||||||
|
req := base.RestyClient.R()
|
||||||
|
req.SetHeader("Authorization", "Bearer "+account.AccessToken)
|
||||||
|
if headers != nil {
|
||||||
|
req.SetHeaders(headers)
|
||||||
|
}
|
||||||
|
if query != nil {
|
||||||
|
req.SetQueryParams(query)
|
||||||
|
}
|
||||||
|
if form != nil {
|
||||||
|
req.SetFormData(form)
|
||||||
|
}
|
||||||
|
if data != nil {
|
||||||
|
req.SetBody(data)
|
||||||
|
}
|
||||||
|
if resp != nil {
|
||||||
|
req.SetResult(resp)
|
||||||
|
}
|
||||||
|
var res *resty.Response
|
||||||
|
var err error
|
||||||
|
var e OneRespErr
|
||||||
|
req.SetError(&e)
|
||||||
|
switch method {
|
||||||
|
case base.Get:
|
||||||
|
res, err = req.Get(url)
|
||||||
|
case base.Post:
|
||||||
|
res, err = req.Post(url)
|
||||||
|
case base.Patch:
|
||||||
|
res, err = req.Patch(url)
|
||||||
|
case base.Delete:
|
||||||
|
res, err = req.Delete(url)
|
||||||
|
case base.Put:
|
||||||
|
res, err = req.Put(url)
|
||||||
|
default:
|
||||||
|
return nil, base.ErrNotSupport
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Debug(res.String())
|
||||||
|
if e.Error.Code != "" {
|
||||||
|
if e.Error.Code == "InvalidAuthenticationToken" {
|
||||||
|
err = driver.RefreshToken(account)
|
||||||
|
if err != nil {
|
||||||
|
_ = model.SaveAccount(account)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return driver.Request(rawUrl, method, headers, query, form, data, resp, account)
|
||||||
|
}
|
||||||
|
return nil, errors.New(e.Error.Message)
|
||||||
|
}
|
||||||
|
return res.Body(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (driver Onedrive) UploadSmall(file *model.FileStream, account *model.Account) error {
|
||||||
|
url := driver.GetMetaUrl(account, false, utils.Join(file.ParentPath, file.Name)) + "/content"
|
||||||
|
data, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = driver.Request(url, base.Put, nil, nil, nil, data, nil, account)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (driver Onedrive) UploadBig(file *model.FileStream, account *model.Account) error {
|
||||||
|
url := driver.GetMetaUrl(account, false, utils.Join(file.ParentPath, file.Name)) + "/createUploadSession"
|
||||||
|
res, err := driver.Request(url, base.Post, nil, nil, nil, nil, nil, account)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
uploadUrl := jsoniter.Get(res, "uploadUrl").ToString()
|
||||||
|
var finish uint64 = 0
|
||||||
|
const DEFAULT = 4 * 1024 * 1024
|
||||||
|
for finish < file.GetSize() {
|
||||||
|
log.Debugf("upload: %d", finish)
|
||||||
|
var byteSize uint64 = DEFAULT
|
||||||
|
left := file.GetSize() - finish
|
||||||
|
if left < DEFAULT {
|
||||||
|
byteSize = left
|
||||||
|
}
|
||||||
|
byteData := make([]byte, byteSize)
|
||||||
|
n, err := io.ReadFull(file, byteData)
|
||||||
|
log.Debug(err, n)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("PUT", uploadUrl, bytes.NewBuffer(byteData))
|
||||||
|
req.Header.Set("Content-Length", strconv.Itoa(int(byteSize)))
|
||||||
|
req.Header.Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", finish, finish+byteSize-1, file.Size))
|
||||||
|
finish += byteSize
|
||||||
|
res, err := base.HttpClient.Do(req)
|
||||||
|
if res.StatusCode != 201 && res.StatusCode != 202 {
|
||||||
|
data, _ := ioutil.ReadAll(res.Body)
|
||||||
|
return errors.New(string(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
base.RegisterDriver(&Onedrive{})
|
base.RegisterDriver(&Onedrive{})
|
||||||
oneClient.SetRetryCount(3)
|
oneClient.SetRetryCount(3)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -34,7 +35,7 @@ func GetFileType(ext string) int {
|
||||||
if ext == "" {
|
if ext == "" {
|
||||||
return conf.UNKNOWN
|
return conf.UNKNOWN
|
||||||
}
|
}
|
||||||
ext = strings.ToLower(strings.TrimLeft(ext,"."))
|
ext = strings.ToLower(strings.TrimLeft(ext, "."))
|
||||||
if IsContain(conf.OfficeTypes, ext) {
|
if IsContain(conf.OfficeTypes, ext) {
|
||||||
return conf.OFFICE
|
return conf.OFFICE
|
||||||
}
|
}
|
||||||
|
@ -116,7 +117,7 @@ func Base(path string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Join(elem ...string) string {
|
func Join(elem ...string) string {
|
||||||
res := filepath.Join(elem...)
|
res := path.Join(elem...)
|
||||||
if res == "\\" {
|
if res == "\\" {
|
||||||
res = "/"
|
res = "/"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue