teldrive/internal/reader/lr.go

151 lines
2.6 KiB
Go
Raw Normal View History

2023-09-20 03:20:44 +08:00
package reader
import (
"context"
"fmt"
"io"
2023-12-03 03:47:23 +08:00
"github.com/divyam234/teldrive/pkg/types"
2023-09-20 03:20:44 +08:00
"github.com/gotd/td/telegram"
"github.com/gotd/td/tg"
)
type linearReader struct {
2023-11-03 20:59:18 +08:00
ctx context.Context
parts []types.Part
pos int
client *telegram.Client
2023-11-03 22:26:47 +08:00
next func() ([]byte, error)
2023-11-03 20:59:18 +08:00
buffer []byte
bytesread int64
chunkSize int64
i int64
contentLength int64
2023-11-03 04:00:24 +08:00
}
func (*linearReader) Close() error {
return nil
2023-09-20 03:20:44 +08:00
}
2023-11-03 20:59:18 +08:00
func NewLinearReader(ctx context.Context, client *telegram.Client, parts []types.Part, contentLength int64) (io.ReadCloser, error) {
2023-09-20 03:20:44 +08:00
r := &linearReader{
2023-11-03 20:59:18 +08:00
ctx: ctx,
parts: parts,
client: client,
chunkSize: int64(1024 * 1024),
contentLength: contentLength,
2023-09-20 03:20:44 +08:00
}
2023-11-03 04:00:24 +08:00
r.next = r.partStream()
2023-09-20 03:20:44 +08:00
return r, nil
}
func (r *linearReader) Read(p []byte) (n int, err error) {
2023-11-03 20:59:18 +08:00
if r.bytesread == r.contentLength {
return 0, io.EOF
}
2023-11-03 04:00:24 +08:00
if r.i >= int64(len(r.buffer)) {
2023-11-03 22:26:47 +08:00
r.buffer, err = r.next()
if err != nil {
return 0, err
}
2023-11-03 20:59:18 +08:00
if len(r.buffer) == 0 {
r.pos++
2023-11-03 22:26:47 +08:00
if r.pos == len(r.parts) {
return 0, io.EOF
} else {
r.next = r.partStream()
2023-11-03 22:26:47 +08:00
r.buffer, err = r.next()
if err != nil {
return 0, err
}
}
2023-11-03 04:00:24 +08:00
}
r.i = 0
2023-09-20 03:20:44 +08:00
}
2023-11-03 04:00:24 +08:00
n = copy(p, r.buffer[r.i:])
r.i += int64(n)
2023-09-20 03:20:44 +08:00
r.bytesread += int64(n)
return n, nil
}
func (r *linearReader) chunk(offset int64, limit int64) ([]byte, error) {
req := &tg.UploadGetFileRequest{
Offset: offset,
Limit: int(limit),
Location: r.parts[r.pos].Location,
}
res, err := r.client.API().UploadGetFile(r.ctx, req)
if err != nil {
return nil, err
}
switch result := res.(type) {
case *tg.UploadFile:
return result.Bytes, nil
default:
return nil, fmt.Errorf("unexpected type %T", r)
}
}
2023-11-03 22:26:47 +08:00
func (r *linearReader) partStream() func() ([]byte, error) {
2023-09-20 03:20:44 +08:00
start := r.parts[r.pos].Start
end := r.parts[r.pos].End
offset := start - (start % r.chunkSize)
firstPartCut := start - offset
lastPartCut := (end % r.chunkSize) + 1
partCount := int((end - offset + r.chunkSize) / r.chunkSize)
currentPart := 1
2023-11-03 22:26:47 +08:00
readData := func() ([]byte, error) {
2023-09-20 03:20:44 +08:00
2023-11-03 04:00:24 +08:00
if currentPart > partCount {
2023-11-03 22:26:47 +08:00
return make([]byte, 0), nil
2023-11-03 04:00:24 +08:00
}
2023-09-20 03:20:44 +08:00
2023-11-03 22:26:47 +08:00
res, err := r.chunk(offset, r.chunkSize)
if err != nil {
return nil, err
}
2023-09-20 03:20:44 +08:00
2023-11-03 04:00:24 +08:00
if len(res) == 0 {
2023-11-03 22:26:47 +08:00
return res, nil
2023-11-03 04:00:24 +08:00
} else if partCount == 1 {
res = res[firstPartCut:lastPartCut]
2023-09-20 03:20:44 +08:00
2023-11-03 04:00:24 +08:00
} else if currentPart == 1 {
res = res[firstPartCut:]
2023-09-20 03:20:44 +08:00
2023-11-03 04:00:24 +08:00
} else if currentPart == partCount {
res = res[:lastPartCut]
2023-09-20 03:20:44 +08:00
2023-11-03 04:00:24 +08:00
}
2023-09-20 03:20:44 +08:00
2023-11-03 04:00:24 +08:00
currentPart++
2023-09-20 03:20:44 +08:00
2023-11-03 04:00:24 +08:00
offset += r.chunkSize
2023-09-20 03:20:44 +08:00
2023-11-03 22:26:47 +08:00
return res, nil
2023-09-20 03:20:44 +08:00
2023-11-03 04:00:24 +08:00
}
return readData
2023-09-20 03:20:44 +08:00
}