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"
|
|
|
|
)
|
|
|
|
|
2023-12-08 05:46:06 +08:00
|
|
|
type tgReader struct {
|
|
|
|
ctx context.Context
|
|
|
|
client *telegram.Client
|
|
|
|
location *tg.InputDocumentFileLocation
|
|
|
|
start int64
|
|
|
|
end int64
|
|
|
|
next func() ([]byte, error)
|
|
|
|
buffer []byte
|
|
|
|
bytesread int64
|
|
|
|
chunkSize int64
|
|
|
|
i int64
|
2023-11-03 04:00:24 +08:00
|
|
|
}
|
|
|
|
|
2023-12-08 05:46:06 +08:00
|
|
|
func NewTGReader(
|
|
|
|
ctx context.Context,
|
|
|
|
client *telegram.Client,
|
|
|
|
part types.Part,
|
2023-09-20 03:20:44 +08:00
|
|
|
|
2023-12-08 05:46:06 +08:00
|
|
|
) (io.ReadCloser, error) {
|
2023-09-20 03:20:44 +08:00
|
|
|
|
2023-12-08 05:46:06 +08:00
|
|
|
r := &tgReader{
|
|
|
|
ctx: ctx,
|
|
|
|
location: part.Location,
|
|
|
|
client: client,
|
|
|
|
start: part.Start,
|
|
|
|
end: part.End,
|
|
|
|
chunkSize: int64(1024 * 1024),
|
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
|
|
|
|
}
|
|
|
|
|
2023-12-08 05:46:06 +08:00
|
|
|
func (r *tgReader) Read(p []byte) (n int, err error) {
|
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 {
|
2023-12-08 05:46:06 +08:00
|
|
|
r.next = r.partStream()
|
|
|
|
r.buffer, err = r.next()
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
2023-11-03 21:32:41 +08:00
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
2023-12-08 05:46:06 +08:00
|
|
|
if r.bytesread == r.end-r.start+1 {
|
|
|
|
return n, io.EOF
|
|
|
|
}
|
2023-09-20 03:20:44 +08:00
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
2023-12-08 05:46:06 +08:00
|
|
|
func (*tgReader) Close() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *tgReader) chunk(offset int64, limit int64) ([]byte, error) {
|
2023-09-20 03:20:44 +08:00
|
|
|
|
|
|
|
req := &tg.UploadGetFileRequest{
|
|
|
|
Offset: offset,
|
|
|
|
Limit: int(limit),
|
2023-12-08 05:46:06 +08:00
|
|
|
Location: r.location,
|
2023-09-20 03:20:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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-12-08 05:46:06 +08:00
|
|
|
func (r *tgReader) partStream() func() ([]byte, error) {
|
2023-09-20 03:20:44 +08:00
|
|
|
|
2023-12-08 05:46:06 +08:00
|
|
|
start := r.start
|
|
|
|
end := r.end
|
2023-09-20 03:20:44 +08:00
|
|
|
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-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-11-03 22:26:47 +08:00
|
|
|
res, err := r.chunk(offset, r.chunkSize)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
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]
|
|
|
|
} else if currentPart == 1 {
|
|
|
|
res = res[firstPartCut:]
|
|
|
|
} else if currentPart == partCount {
|
|
|
|
res = res[:lastPartCut]
|
|
|
|
}
|
2023-09-20 03:20:44 +08:00
|
|
|
|
2023-11-03 04:00:24 +08:00
|
|
|
currentPart++
|
|
|
|
offset += r.chunkSize
|
2023-11-03 22:26:47 +08:00
|
|
|
return res, nil
|
2023-11-03 04:00:24 +08:00
|
|
|
}
|
|
|
|
return readData
|
2023-09-20 03:20:44 +08:00
|
|
|
}
|