package downloader
import (
"context"
"io"
"os"
"path/filepath"
"github.com/go-faster/errors"
"go.uber.org/multierr"
"github.com/gotd/td/tg"
)
type Builder struct {
downloader *Downloader
schema schema
hashes []tg .FileHash
verify bool
threads int
}
func newBuilder (downloader *Downloader , schema schema ) *Builder {
return &Builder {
schema : schema ,
threads : 1 ,
downloader : downloader ,
}
}
func (b *Builder ) WithThreads (threads int ) *Builder {
if threads > 0 {
b .threads = threads
}
return b
}
func (b *Builder ) WithRetryHandler (handler RetryHandler ) *Builder {
switch s := b .schema .(type ) {
case master :
s .retryHandler = handler
b .schema = s
case web :
s .retryHandler = handler
b .schema = s
case *cdn :
s .retryHandler = handler
}
return b
}
func (b *Builder ) WithVerify (verify bool ) *Builder {
b .verify = verify
return b
}
func (b *Builder ) prepareMaster (m master , allowCDN bool ) *Builder {
clone := *b
masterSchema := m
masterSchema .allowCDN = allowCDN
clone .schema = masterSchema
clone .hashes = nil
return &clone
}
func (b *Builder ) prepareCDNPath (m master , provider CDNProvider ) *Builder {
m .allowCDN = true
clone := *b
verifyCDNInline := !clone .verify
clone .hashes = nil
clone .schema = newCDNSchema (
m ,
provider ,
b .downloader .pool ,
int64 (b .threads ),
verifyCDNInline ,
m .retryHandler ,
)
return &clone
}
func (b *Builder ) shouldAllowCDN () bool {
if b .downloader .allowCDN == nil {
return false
}
return *b .downloader .allowCDN
}
func closeSchema (s schema ) func () error {
if closer , ok := s .(interface { Close () error }); ok {
return closer .Close
}
return nil
}
func (b *Builder ) prepare () (_ *Builder , closeCDN func () error , err error ) {
m , ok := b .schema .(master )
if !ok {
return b , closeSchema (b .schema ), nil
}
if !b .shouldAllowCDN () {
prepared := b .prepareMaster (m , false )
return prepared , closeSchema (prepared .schema ), nil
}
provider , hasProvider := m .client .(CDNProvider )
if !hasProvider {
prepared := b .prepareMaster (m , false )
return prepared , closeSchema (prepared .schema ), nil
}
prepared := b .prepareCDNPath (m , provider )
return prepared , closeSchema (prepared .schema ), nil
}
func (b *Builder ) reader () *reader {
if b .verify {
return verifiedReader (b .schema , newVerifier (b .schema , b .hashes ...))
}
return plainReader (b .schema , b .downloader .partSize )
}
func (b *Builder ) Stream (ctx context .Context , output io .Writer ) (_ tg .StorageFileTypeClass , err error ) {
prepared , closeCDN , err := b .prepare ()
if err != nil {
return nil , err
}
defer func () {
if closeCDN != nil {
multierr .AppendInto (&err , closeCDN ())
}
}()
typ , runErr := prepared .downloader .stream (ctx , prepared .reader (), output )
return typ , runErr
}
func (b *Builder ) Parallel (ctx context .Context , output io .WriterAt ) (_ tg .StorageFileTypeClass , err error ) {
prepared , closeCDN , err := b .prepare ()
if err != nil {
return nil , err
}
defer func () {
if closeCDN != nil {
multierr .AppendInto (&err , closeCDN ())
}
}()
typ , runErr := prepared .downloader .parallel (ctx , prepared .reader (), prepared .threads , output )
return typ , runErr
}
func (b *Builder ) ToPath (ctx context .Context , path string ) (_ tg .StorageFileTypeClass , err error ) {
f , err := os .Create (filepath .Clean (path ))
if err != nil {
return nil , errors .Wrap (err , "create output file" )
}
defer func () {
multierr .AppendInto (&err , f .Close ())
}()
typ , runErr := b .Parallel (ctx , f )
return typ , runErr
}
The pages are generated with Golds v0.8.4 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .