2023-12-08 05:46:06 +08:00
|
|
|
package reader
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"io"
|
|
|
|
|
2024-06-14 02:37:48 +08:00
|
|
|
"github.com/divyam234/teldrive/internal/config"
|
2024-06-22 20:29:59 +08:00
|
|
|
"github.com/divyam234/teldrive/internal/tgc"
|
2023-12-08 05:46:06 +08:00
|
|
|
"github.com/divyam234/teldrive/pkg/types"
|
|
|
|
)
|
|
|
|
|
2024-03-20 01:01:56 +08:00
|
|
|
func calculatePartByteRanges(startByte, endByte, partSize int64) []types.Range {
|
|
|
|
|
|
|
|
partByteRanges := []types.Range{}
|
|
|
|
|
|
|
|
startPart := startByte / partSize
|
|
|
|
|
|
|
|
endPart := endByte / partSize
|
|
|
|
|
|
|
|
startOffset := startByte % partSize
|
|
|
|
|
|
|
|
for part := startPart; part <= endPart; part++ {
|
|
|
|
partStartByte := int64(0)
|
|
|
|
partEndByte := partSize - 1
|
|
|
|
if part == startPart {
|
|
|
|
partStartByte = startOffset
|
|
|
|
}
|
|
|
|
if part == endPart {
|
|
|
|
partEndByte = int64(endByte % partSize)
|
|
|
|
}
|
|
|
|
partByteRanges = append(partByteRanges, types.Range{Start: partStartByte, End: partEndByte, PartNo: part})
|
|
|
|
|
|
|
|
startOffset = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
return partByteRanges
|
|
|
|
}
|
|
|
|
|
2023-12-08 05:46:06 +08:00
|
|
|
type linearReader struct {
|
2024-06-22 20:29:59 +08:00
|
|
|
ctx context.Context
|
|
|
|
parts []types.Part
|
|
|
|
ranges []types.Range
|
|
|
|
pos int
|
|
|
|
reader io.ReadCloser
|
|
|
|
limit int64
|
|
|
|
config *config.TGConfig
|
|
|
|
channelId int64
|
|
|
|
worker *tgc.StreamWorker
|
|
|
|
client *tgc.Client
|
|
|
|
fileId string
|
|
|
|
concurrency int
|
2023-12-08 05:46:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewLinearReader(ctx context.Context,
|
2024-06-22 20:29:59 +08:00
|
|
|
fileId string,
|
2023-12-08 05:46:06 +08:00
|
|
|
parts []types.Part,
|
2024-03-20 01:01:56 +08:00
|
|
|
start, end int64,
|
2024-06-22 20:29:59 +08:00
|
|
|
channelId int64,
|
2024-06-14 02:37:48 +08:00
|
|
|
config *config.TGConfig,
|
2024-06-22 20:29:59 +08:00
|
|
|
concurrency int,
|
|
|
|
client *tgc.Client,
|
|
|
|
worker *tgc.StreamWorker,
|
2023-12-08 05:46:06 +08:00
|
|
|
) (reader io.ReadCloser, err error) {
|
|
|
|
|
|
|
|
r := &linearReader{
|
2024-06-22 20:29:59 +08:00
|
|
|
ctx: ctx,
|
|
|
|
parts: parts,
|
|
|
|
limit: end - start + 1,
|
|
|
|
ranges: calculatePartByteRanges(start, end, parts[0].Size),
|
|
|
|
config: config,
|
|
|
|
client: client,
|
|
|
|
worker: worker,
|
|
|
|
channelId: channelId,
|
|
|
|
fileId: fileId,
|
|
|
|
concurrency: concurrency,
|
2023-12-08 05:46:06 +08:00
|
|
|
}
|
|
|
|
|
2024-03-20 01:01:56 +08:00
|
|
|
r.reader, err = r.nextPart()
|
2023-12-08 05:46:06 +08:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return r, nil
|
|
|
|
}
|
|
|
|
|
2024-06-22 20:29:59 +08:00
|
|
|
func (r *linearReader) Read(p []byte) (int, error) {
|
2024-03-10 22:40:09 +08:00
|
|
|
|
|
|
|
if r.limit <= 0 {
|
|
|
|
return 0, io.EOF
|
|
|
|
}
|
|
|
|
|
2024-06-22 20:29:59 +08:00
|
|
|
n, err := r.reader.Read(p)
|
2023-12-08 05:46:06 +08:00
|
|
|
|
2024-03-10 22:40:09 +08:00
|
|
|
if err == io.EOF {
|
|
|
|
if r.limit > 0 {
|
|
|
|
err = nil
|
2024-06-22 20:29:59 +08:00
|
|
|
if r.reader != nil {
|
|
|
|
r.reader.Close()
|
|
|
|
}
|
2024-03-10 22:40:09 +08:00
|
|
|
}
|
2023-12-08 05:46:06 +08:00
|
|
|
r.pos++
|
2024-03-20 01:01:56 +08:00
|
|
|
if r.pos < len(r.ranges) {
|
|
|
|
r.reader, err = r.nextPart()
|
|
|
|
|
2023-12-08 05:46:06 +08:00
|
|
|
}
|
|
|
|
}
|
2024-06-23 00:57:42 +08:00
|
|
|
r.limit -= int64(n)
|
2024-06-22 20:29:59 +08:00
|
|
|
return n, err
|
2023-12-08 05:46:06 +08:00
|
|
|
}
|
|
|
|
|
2024-03-20 01:01:56 +08:00
|
|
|
func (r *linearReader) nextPart() (io.ReadCloser, error) {
|
|
|
|
|
2024-06-22 20:29:59 +08:00
|
|
|
start := r.ranges[r.pos].Start
|
|
|
|
end := r.ranges[r.pos].End
|
2024-06-14 02:37:48 +08:00
|
|
|
|
2024-06-22 20:29:59 +08:00
|
|
|
chunkSrc := &chunkSource{channelId: r.channelId, worker: r.worker,
|
|
|
|
fileId: r.fileId, partId: r.parts[r.ranges[r.pos].PartNo].ID,
|
|
|
|
client: r.client, concurrency: r.concurrency}
|
|
|
|
return newTGReader(r.ctx, start, end, r.config, chunkSrc)
|
2024-03-20 01:01:56 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-12-08 05:46:06 +08:00
|
|
|
func (r *linearReader) Close() (err error) {
|
|
|
|
if r.reader != nil {
|
|
|
|
err = r.reader.Close()
|
|
|
|
r.reader = nil
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|