alist/drivers/quark_uc/driver.go

272 lines
6.4 KiB
Go
Raw Normal View History

2022-09-02 13:36:47 +00:00
package quark
import (
"context"
"crypto/md5"
"crypto/sha1"
"encoding/hex"
"fmt"
2022-09-02 13:36:47 +00:00
"io"
"net/http"
"os"
"strconv"
"time"
2022-09-02 13:36:47 +00:00
"github.com/alist-org/alist/v3/drivers/base"
"github.com/alist-org/alist/v3/internal/driver"
"github.com/alist-org/alist/v3/internal/errs"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/pkg/http_range"
2022-09-02 13:36:47 +00:00
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/go-resty/resty/v2"
log "github.com/sirupsen/logrus"
)
type QuarkOrUC struct {
2022-09-02 13:36:47 +00:00
model.Storage
Addition
config driver.Config
conf Conf
2022-09-02 13:36:47 +00:00
}
func (d *QuarkOrUC) Config() driver.Config {
return d.config
2022-09-02 13:36:47 +00:00
}
func (d *QuarkOrUC) GetAddition() driver.Additional {
return &d.Addition
2022-09-02 13:36:47 +00:00
}
func (d *QuarkOrUC) Init(ctx context.Context) error {
_, err := d.request("/config", http.MethodGet, nil, nil)
2022-09-02 13:36:47 +00:00
return err
}
func (d *QuarkOrUC) Drop(ctx context.Context) error {
2022-09-02 13:36:47 +00:00
return nil
}
func (d *QuarkOrUC) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
2022-09-02 13:36:47 +00:00
files, err := d.GetFiles(dir.GetID())
if err != nil {
return nil, err
}
return utils.SliceConvert(files, func(src File) (model.Obj, error) {
return fileToObj(src), nil
})
2022-09-02 13:36:47 +00:00
}
func (d *QuarkOrUC) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
2022-09-02 13:36:47 +00:00
data := base.Json{
"fids": []string{file.GetID()},
}
var resp DownResp
ua := d.conf.ua
2022-09-02 13:36:47 +00:00
_, err := d.request("/file/download", http.MethodPost, func(req *resty.Request) {
req.SetHeader("User-Agent", ua).
SetBody(data)
2022-09-02 13:36:47 +00:00
}, &resp)
if err != nil {
return nil, err
}
u := resp.Data[0].DownloadUrl
start, end := int64(0), file.GetSize()
link := model.Link{
Header: http.Header{},
}
if rg := args.Header.Get("Range"); rg != "" {
parseRange, err := http_range.ParseRange(rg, file.GetSize())
if err != nil {
return nil, err
}
start, end = parseRange[0].Start, parseRange[0].Start+parseRange[0].Length
link.Header.Set("Content-Range", parseRange[0].ContentRange(file.GetSize()))
link.Header.Set("Content-Length", strconv.FormatInt(parseRange[0].Length, 10))
link.Status = http.StatusPartialContent
} else {
link.Header.Set("Content-Length", strconv.FormatInt(file.GetSize(), 10))
link.Status = http.StatusOK
}
link.Writer = func(w io.Writer) error {
// request 10 MB at a time
chunkSize := int64(10 * 1024 * 1024)
for start < end {
_end := start + chunkSize
if _end > end {
_end = end
}
_range := "bytes=" + strconv.FormatInt(start, 10) + "-" + strconv.FormatInt(_end-1, 10)
start = _end
err = func() error {
req, err := http.NewRequest(http.MethodGet, u, nil)
if err != nil {
return err
}
req.Header.Set("Range", _range)
req.Header.Set("User-Agent", ua)
req.Header.Set("Cookie", d.Cookie)
req.Header.Set("Referer", d.conf.referer)
resp, err := base.HttpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusPartialContent {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
_, err = io.Copy(w, resp.Body)
return err
}()
if err != nil {
return err
}
}
return nil
}
return &link, nil
2022-09-02 13:36:47 +00:00
}
func (d *QuarkOrUC) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
2022-09-02 13:36:47 +00:00
data := base.Json{
"dir_init_lock": false,
"dir_path": "",
"file_name": dirName,
"pdir_fid": parentDir.GetID(),
}
_, err := d.request("/file", http.MethodPost, func(req *resty.Request) {
req.SetBody(data)
}, nil)
if err == nil {
time.Sleep(time.Second)
}
2022-09-02 13:36:47 +00:00
return err
}
func (d *QuarkOrUC) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
2022-09-02 13:36:47 +00:00
data := base.Json{
"action_type": 1,
"exclude_fids": []string{},
"filelist": []string{srcObj.GetID()},
"to_pdir_fid": dstDir.GetID(),
}
_, err := d.request("/file/move", http.MethodPost, func(req *resty.Request) {
req.SetBody(data)
}, nil)
return err
}
func (d *QuarkOrUC) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
2022-09-02 13:36:47 +00:00
data := base.Json{
"fid": srcObj.GetID(),
"file_name": newName,
}
_, err := d.request("/file/rename", http.MethodPost, func(req *resty.Request) {
req.SetBody(data)
}, nil)
return err
}
func (d *QuarkOrUC) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
2022-09-02 13:36:47 +00:00
return errs.NotSupport
}
func (d *QuarkOrUC) Remove(ctx context.Context, obj model.Obj) error {
2022-09-02 13:36:47 +00:00
data := base.Json{
"action_type": 1,
"exclude_fids": []string{},
"filelist": []string{obj.GetID()},
}
_, err := d.request("/file/delete", http.MethodPost, func(req *resty.Request) {
req.SetBody(data)
}, nil)
return err
}
func (d *QuarkOrUC) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
tempFile, err := utils.CreateTempFile(stream.GetReadCloser())
if err != nil {
return err
2022-09-02 13:36:47 +00:00
}
defer func() {
_ = tempFile.Close()
_ = os.Remove(tempFile.Name())
}()
2022-09-02 13:36:47 +00:00
m := md5.New()
_, err = io.Copy(m, tempFile)
if err != nil {
return err
}
_, err = tempFile.Seek(0, io.SeekStart)
if err != nil {
return err
}
md5Str := hex.EncodeToString(m.Sum(nil))
s := sha1.New()
_, err = io.Copy(s, tempFile)
if err != nil {
return err
}
_, err = tempFile.Seek(0, io.SeekStart)
if err != nil {
return err
}
sha1Str := hex.EncodeToString(s.Sum(nil))
// pre
pre, err := d.upPre(stream, dstDir.GetID())
if err != nil {
return err
}
log.Debugln("hash: ", md5Str, sha1Str)
// hash
finish, err := d.upHash(md5Str, sha1Str, pre.Data.TaskId)
if err != nil {
return err
}
if finish {
return nil
}
// part up
partSize := pre.Metadata.PartSize
var bytes []byte
md5s := make([]string, 0)
defaultBytes := make([]byte, partSize)
total := stream.GetSize()
left := total
2022-09-02 13:36:47 +00:00
partNumber := 1
for left > 0 {
if utils.IsCanceled(ctx) {
return ctx.Err()
}
2022-09-02 13:36:47 +00:00
if left > int64(partSize) {
bytes = defaultBytes
} else {
bytes = make([]byte, left)
}
_, err := io.ReadFull(tempFile, bytes)
if err != nil {
return err
}
left -= int64(len(bytes))
2022-09-02 13:36:47 +00:00
log.Debugf("left: %d", left)
m, err := d.upPart(ctx, pre, stream.GetMimetype(), partNumber, bytes)
2022-09-02 13:36:47 +00:00
//m, err := driver.UpPart(pre, file.GetMIMEType(), partNumber, bytes, account, md5Str, sha1Str)
if err != nil {
return err
}
if m == "finish" {
return nil
}
md5s = append(md5s, m)
partNumber++
up(int(100 * (total - left) / total))
2022-09-02 13:36:47 +00:00
}
err = d.upCommit(pre, md5s)
if err != nil {
return err
}
return d.upFinish(pre)
}
var _ driver.Driver = (*QuarkOrUC)(nil)