adrive: add NewFS

This commit is contained in:
ns2kracy 2025-02-13 08:23:16 +00:00
parent 0bd42adcc8
commit aa3da19f7e
No known key found for this signature in database
GPG Key ID: 3E6E5EE4AFFF61DB

View File

@ -2,18 +2,52 @@ package adrive
import (
"context"
"fmt"
"io"
"strings"
"time"
"github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fs/config/configmap"
"github.com/rclone/rclone/fs/config/configstruct"
"github.com/rclone/rclone/fs/config/obscure"
"github.com/rclone/rclone/fs/fshttp"
"github.com/rclone/rclone/fs/hash"
"github.com/rclone/rclone/lib/dircache"
"github.com/rclone/rclone/lib/encoder"
"github.com/rclone/rclone/lib/oauthutil"
"github.com/rclone/rclone/lib/pacer"
"github.com/rclone/rclone/lib/rest"
"golang.org/x/oauth2"
)
const (
rcloneClientID = ""
rcloneEncryptedClientSecret = ""
minSleep = 10 * time.Millisecond
maxSleep = 2 * time.Second
decayConstant = 2 // bigger for slower decay, exponential
rootURL = "https://openapi.alipan.com"
)
// Globals
var (
// Description of how to auth for this app
oauthConfig = &oauthutil.Config{
Scopes: []string{
"user:base",
"file:all:read",
"file:all:write",
"album:shared:read",
"file:share:write",
},
AuthURL: "https://openapi.alipan.com/oauth/authorize",
TokenURL: "https://openapi.alipan.com/oauth/access_token ",
AuthStyle: oauth2.AuthStyleInParams,
ClientID: rcloneClientID,
ClientSecret: obscure.MustReveal(rcloneEncryptedClientSecret),
RedirectURL: oauthutil.RedirectURL,
}
)
// Register with Fs
@ -38,7 +72,7 @@ type Options struct {
Impersonate string `config:"impersonate"`
}
// Fs represents a remote box
// Fs represents a remote adrive
type Fs struct {
name string // name of this remote
root string // the path we are working on
@ -51,29 +85,88 @@ type Fs struct {
uploadToken *pacer.TokenDispenser // control concurrency
}
func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, error) {
opt := new(Options)
err := configstruct.Set(m, opt)
if err != nil {
return nil, err
}
f := &Fs{}
f.features = (&fs.Features{
CanHaveEmptyDirectories: true,
}).Fill(ctx, f)
return f, err
// Object describes a adrive object
//
// Will definitely have info but maybe not meta
type Object struct {
fs *Fs // what this object is part of
remote string // The remote path
hasMetaData bool // whether info below has been set
size int64 // size of the object
modTime time.Time // modification time of the object
id string // ID of the object
sha1 string // SHA-1 of the object content
}
// Features implements fs.Fs.
// ------------------------------------------------------------
// Name of the remote (as passed into NewFs)
func (f *Fs) Name() string {
return f.name
}
// Root of the remote (as passed into NewFs)
func (f *Fs) Root() string {
return f.root
}
// String converts this Fs to a string
func (f *Fs) String() string {
return fmt.Sprintf("adrive root '%s'", f.root)
}
// Features returns the optional features of this Fs
func (f *Fs) Features() *fs.Features {
return f.features
}
// Hashes returns the supported hash sets.
func (f *Fs) Hashes() hash.Set {
return hash.Set(hash.SHA1)
}
// CleanUp implements fs.CleanUpper.
func (f *Fs) CleanUp(ctx context.Context) error {
panic("unimplemented")
}
// Hashes implements fs.Fs.
func (f *Fs) Hashes() hash.Set {
// PublicLink implements fs.PublicLinker.
func (f *Fs) PublicLink(ctx context.Context, remote string, expire fs.Duration, unlink bool) (string, error) {
panic("unimplemented")
}
// DirCacheFlush implements fs.DirCacheFlusher.
func (f *Fs) DirCacheFlush() {
f.dirCache.ResetRoot()
}
// DirMove implements fs.DirMover.
func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote string, dstRemote string) error {
panic("unimplemented")
}
// Move implements fs.Mover.
func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object, error) {
panic("unimplemented")
}
// About implements fs.Abouter.
func (f *Fs) About(ctx context.Context) (*fs.Usage, error) {
panic("unimplemented")
}
// Copy implements fs.Copier.
func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, error) {
panic("unimplemented")
}
// PutStream implements fs.PutStreamer.
func (f *Fs) PutStream(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
panic("unimplemented")
}
// Purge implements fs.Purger.
func (f *Fs) Purge(ctx context.Context, dir string) error {
panic("unimplemented")
}
@ -87,11 +180,6 @@ func (f *Fs) Mkdir(ctx context.Context, dir string) error {
panic("unimplemented")
}
// Name implements fs.Fs.
func (f *Fs) Name() string {
panic("unimplemented")
}
// NewObject implements fs.Fs.
func (f *Fs) NewObject(ctx context.Context, remote string) (fs.Object, error) {
panic("unimplemented")
@ -112,12 +200,118 @@ func (f *Fs) Rmdir(ctx context.Context, dir string) error {
panic("unimplemented")
}
// Root implements fs.Fs.
func (f *Fs) Root() string {
// ------------------------------------------------------------
// ID implements fs.IDer.
func (o *Object) ID() string {
panic("unimplemented")
}
// String implements fs.Fs.
func (f *Fs) String() string {
// Fs implements fs.Object.
func (o *Object) Fs() fs.Info {
panic("unimplemented")
}
// Hash implements fs.Object.
func (o *Object) Hash(ctx context.Context, ty hash.Type) (string, error) {
panic("unimplemented")
}
// ModTime implements fs.Object.
func (o *Object) ModTime(context.Context) time.Time {
panic("unimplemented")
}
// Open implements fs.Object.
func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadCloser, error) {
panic("unimplemented")
}
// Remote implements fs.Object.
func (o *Object) Remote() string {
panic("unimplemented")
}
// Remove implements fs.Object.
func (o *Object) Remove(ctx context.Context) error {
panic("unimplemented")
}
// SetModTime implements fs.Object.
func (o *Object) SetModTime(ctx context.Context, t time.Time) error {
panic("unimplemented")
}
// Size implements fs.Object.
func (o *Object) Size() int64 {
panic("unimplemented")
}
// Storable implements fs.Object.
func (o *Object) Storable() bool {
panic("unimplemented")
}
// String implements fs.Object.
func (o *Object) String() string {
panic("unimplemented")
}
// Update implements fs.Object.
func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
panic("unimplemented")
}
func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, error) {
opt := new(Options)
err := configstruct.Set(m, opt)
if err != nil {
return nil, err
}
root = parsePath(root)
client := fshttp.NewClient(ctx)
f := &Fs{
name: name,
root: root,
opt: *opt,
srv: rest.NewClient(client).SetRoot(rootURL),
pacer: fs.NewPacer(ctx, pacer.NewDefault(pacer.MinSleep(minSleep), pacer.MaxSleep(maxSleep), pacer.DecayConstant(decayConstant))),
}
f.features = (&fs.Features{
CaseInsensitive: true,
CanHaveEmptyDirectories: true,
}).Fill(ctx, f)
// If using an accessToken, set the Authorization header
if f.opt.AccessToken != "" {
f.srv.SetHeader("Authorization", "Bearer "+f.opt.AccessToken)
}
return f, err
}
// parsePath parses a remote path
func parsePath(path string) (root string) {
root = strings.Trim(path, "/")
return
}
// Check the interfaces are satisfied
var (
_ fs.Fs = (*Fs)(nil)
_ fs.Purger = (*Fs)(nil)
_ fs.PutStreamer = (*Fs)(nil)
_ fs.Copier = (*Fs)(nil)
_ fs.Abouter = (*Fs)(nil)
_ fs.Mover = (*Fs)(nil)
_ fs.DirMover = (*Fs)(nil)
_ fs.DirCacheFlusher = (*Fs)(nil)
_ fs.PublicLinker = (*Fs)(nil)
_ fs.CleanUpper = (*Fs)(nil)
_ fs.Object = (*Object)(nil)
_ fs.IDer = (*Object)(nil)
)