You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
3.7 KiB
123 lines
3.7 KiB
package message |
|
|
|
import ( |
|
"context" |
|
"io" |
|
"io/fs" |
|
|
|
"go.uber.org/atomic" |
|
|
|
"github.com/gotd/td/telegram/uploader" |
|
"github.com/gotd/td/telegram/uploader/source" |
|
"github.com/gotd/td/tg" |
|
) |
|
|
|
// Uploader is an abstraction for Telegram file uploader. |
|
type Uploader interface { |
|
FromFile(ctx context.Context, f uploader.File) (tg.InputFileClass, error) |
|
FromPath(ctx context.Context, path string) (tg.InputFileClass, error) |
|
FromFS(ctx context.Context, filesystem fs.FS, path string) (tg.InputFileClass, error) |
|
FromReader(ctx context.Context, name string, f io.Reader) (tg.InputFileClass, error) |
|
FromBytes(ctx context.Context, name string, b []byte) (tg.InputFileClass, error) |
|
FromURL(ctx context.Context, rawURL string) (tg.InputFileClass, error) |
|
FromSource(ctx context.Context, src source.Source, rawURL string) (tg.InputFileClass, error) |
|
} |
|
|
|
type uploadBuilder struct { |
|
upload Uploader |
|
} |
|
|
|
// UploadOption is a UploadBuilder creation option. |
|
type UploadOption interface { |
|
apply(ctx context.Context, b uploadBuilder) (tg.InputFileClass, error) |
|
} |
|
|
|
// uploadOptionFunc is a functional adapter for UploadOption. |
|
type uploadOptionFunc func(ctx context.Context, b uploadBuilder) (tg.InputFileClass, error) |
|
|
|
func (f uploadOptionFunc) apply(ctx context.Context, b uploadBuilder) (tg.InputFileClass, error) { |
|
return f(ctx, b) |
|
} |
|
|
|
type fileCache atomic.Value |
|
|
|
func (r *fileCache) Store(result tg.InputFileClass) { |
|
r.Value.Store(result) |
|
} |
|
|
|
func (r *fileCache) Load() (result tg.InputFileClass, ok bool) { |
|
result, ok = r.Value.Load().(tg.InputFileClass) |
|
return |
|
} |
|
|
|
// FilePromise is a upload file promise. |
|
type FilePromise = func(ctx context.Context, b Uploader) (tg.InputFileClass, error) |
|
|
|
// Upload creates new upload options using given promise. |
|
func Upload(promise FilePromise) UploadOption { |
|
once := &fileCache{} |
|
return uploadOptionFunc(func(ctx context.Context, b uploadBuilder) (r tg.InputFileClass, err error) { |
|
if v, ok := once.Load(); ok { |
|
return v, nil |
|
} |
|
defer func() { |
|
if err == nil && r != nil { |
|
once.Store(r) |
|
} |
|
}() |
|
|
|
return promise(ctx, b.upload) |
|
}) |
|
} |
|
|
|
// FromFile uploads given File. |
|
// NB: FromFile does not close given file. |
|
func FromFile(f uploader.File) UploadOption { |
|
return Upload(func(ctx context.Context, b Uploader) (tg.InputFileClass, error) { |
|
return b.FromFile(ctx, f) |
|
}) |
|
} |
|
|
|
// FromPath uploads file from given path. |
|
func FromPath(path string) UploadOption { |
|
return Upload(func(ctx context.Context, b Uploader) (tg.InputFileClass, error) { |
|
return b.FromPath(ctx, path) |
|
}) |
|
} |
|
|
|
// FromFS uploads file from given path using given fs.FS. |
|
func FromFS(filesystem fs.FS, path string) UploadOption { |
|
return Upload(func(ctx context.Context, b Uploader) (tg.InputFileClass, error) { |
|
return b.FromFS(ctx, filesystem, path) |
|
}) |
|
} |
|
|
|
// FromReader uploads file from given io.Reader. |
|
// NB: totally stream should not exceed the limit for |
|
// small files (10 MB as docs says, may be a bit bigger). |
|
func FromReader(name string, r io.Reader) UploadOption { |
|
return Upload(func(ctx context.Context, b Uploader) (tg.InputFileClass, error) { |
|
return b.FromReader(ctx, name, r) |
|
}) |
|
} |
|
|
|
// FromBytes uploads file from given byte slice. |
|
func FromBytes(name string, data []byte) UploadOption { |
|
return Upload(func(ctx context.Context, b Uploader) (tg.InputFileClass, error) { |
|
return b.FromBytes(ctx, name, data) |
|
}) |
|
} |
|
|
|
// FromURL uploads file from given URL. |
|
func FromURL(rawURL string) UploadOption { |
|
return Upload(func(ctx context.Context, b Uploader) (tg.InputFileClass, error) { |
|
return b.FromURL(ctx, rawURL) |
|
}) |
|
} |
|
|
|
// FromSource uploads file from given URL using given Source. |
|
func FromSource(src source.Source, rawURL string) UploadOption { |
|
return Upload(func(ctx context.Context, b Uploader) (tg.InputFileClass, error) { |
|
return b.FromSource(ctx, src, rawURL) |
|
}) |
|
}
|
|
|