mirror of https://github.com/Xhofe/alist
93 lines
1.7 KiB
Go
93 lines
1.7 KiB
Go
package mega
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/alist-org/alist/v3/pkg/utils"
|
|
"github.com/t3rm1n4l/go-mega"
|
|
"io"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// do others that not defined in Driver interface
|
|
// openObject represents a download in progress
|
|
type openObject struct {
|
|
ctx context.Context
|
|
mu sync.Mutex
|
|
d *mega.Download
|
|
id int
|
|
skip int64
|
|
chunk []byte
|
|
closed bool
|
|
}
|
|
|
|
// get the next chunk
|
|
func (oo *openObject) getChunk(ctx context.Context) (err error) {
|
|
if oo.id >= oo.d.Chunks() {
|
|
return io.EOF
|
|
}
|
|
var chunk []byte
|
|
err = utils.Retry(3, time.Second, func() (err error) {
|
|
chunk, err = oo.d.DownloadChunk(oo.id)
|
|
return err
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
oo.id++
|
|
oo.chunk = chunk
|
|
return nil
|
|
}
|
|
|
|
// Read reads up to len(p) bytes into p.
|
|
func (oo *openObject) Read(p []byte) (n int, err error) {
|
|
oo.mu.Lock()
|
|
defer oo.mu.Unlock()
|
|
if oo.closed {
|
|
return 0, fmt.Errorf("read on closed file")
|
|
}
|
|
// Skip data at the start if requested
|
|
for oo.skip > 0 {
|
|
_, size, err := oo.d.ChunkLocation(oo.id)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if oo.skip < int64(size) {
|
|
break
|
|
}
|
|
oo.id++
|
|
oo.skip -= int64(size)
|
|
}
|
|
if len(oo.chunk) == 0 {
|
|
err = oo.getChunk(oo.ctx)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if oo.skip > 0 {
|
|
oo.chunk = oo.chunk[oo.skip:]
|
|
oo.skip = 0
|
|
}
|
|
}
|
|
n = copy(p, oo.chunk)
|
|
oo.chunk = oo.chunk[n:]
|
|
return n, nil
|
|
}
|
|
|
|
// Close closed the file - MAC errors are reported here
|
|
func (oo *openObject) Close() (err error) {
|
|
oo.mu.Lock()
|
|
defer oo.mu.Unlock()
|
|
if oo.closed {
|
|
return nil
|
|
}
|
|
err = utils.Retry(3, 500*time.Millisecond, func() (err error) {
|
|
return oo.d.Finish()
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to finish download: %w", err)
|
|
}
|
|
oo.closed = true
|
|
return nil
|
|
}
|