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 }