package reader import ( "context" "io" "github.com/divyam234/teldrive/internal/crypt" "github.com/divyam234/teldrive/pkg/types" "github.com/gotd/td/telegram" ) type decrpytedReader struct { ctx context.Context parts []types.Part ranges []types.Range pos int client *telegram.Client reader io.ReadCloser limit int64 err error encryptionKey string } func NewDecryptedReader( ctx context.Context, client *telegram.Client, parts []types.Part, start, end int64, encryptionKey string) (io.ReadCloser, error) { r := &decrpytedReader{ ctx: ctx, parts: parts, client: client, limit: end - start + 1, ranges: calculatePartByteRanges(start, end, parts[0].DecryptedSize), encryptionKey: encryptionKey, } res, err := r.nextPart() if err != nil { return nil, err } r.reader = res return r, nil } func (r *decrpytedReader) Read(p []byte) (n int, err error) { if r.err != nil { return 0, r.err } if r.limit <= 0 { return 0, io.EOF } n, err = r.reader.Read(p) if err == nil { r.limit -= int64(n) } if err == io.EOF { if r.limit > 0 { err = nil } r.pos++ if r.pos < len(r.ranges) { r.reader, err = r.nextPart() } } r.err = err return } func (r *decrpytedReader) Close() (err error) { if r.reader != nil { err = r.reader.Close() r.reader = nil return err } return nil } func (r *decrpytedReader) nextPart() (io.ReadCloser, error) { location := r.parts[r.ranges[r.pos].PartNo].Location start := r.ranges[r.pos].Start end := r.ranges[r.pos].End salt := r.parts[r.ranges[r.pos].PartNo].Salt cipher, _ := crypt.NewCipher(r.encryptionKey, salt) return cipher.DecryptDataSeek(r.ctx, func(ctx context.Context, underlyingOffset, underlyingLimit int64) (io.ReadCloser, error) { var end int64 if underlyingLimit >= 0 { end = min(r.parts[r.ranges[r.pos].PartNo].Size-1, underlyingOffset+underlyingLimit-1) } return newTGReader(r.ctx, r.client, location, underlyingOffset, end) }, start, end-start+1) }