feat: better document sending handling with more general io.Reader interface to get the data.
This commit is contained in:
parent
23a34b0ed3
commit
e62ccf5780
6 changed files with 102 additions and 46 deletions
|
@ -337,10 +337,27 @@ var beh = tg.NewBehaviour().
|
||||||
c.Sendf2("You typed `%s`", str)
|
c.Sendf2("You typed `%s`", str)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
tg.NewCommand("image", "sends a sample image").
|
tg.NewCommand("cat", "sends a sample image of cat").
|
||||||
ActionFunc(func(c *tg.Context) {
|
ActionFunc(func(c *tg.Context) {
|
||||||
img := tg.NewFile("media/cat.jpg").Image().Caption("A cat!")
|
f, err := os.Open("media/cat.jpg")
|
||||||
c.Send(img)
|
if err != nil {
|
||||||
|
c.Sendf("err: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
photo := tg.NewFile(f).Photo().Name("cat.jpg").Caption("A cat!")
|
||||||
|
c.Send(photo)
|
||||||
|
}),
|
||||||
|
tg.NewCommand("document", "sends a sample text document").
|
||||||
|
ActionFunc(func(c *tg.Context) {
|
||||||
|
f, err := os.Open("media/hello.txt")
|
||||||
|
if err != nil {
|
||||||
|
c.Sendf("err: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
doc := tg.NewFile(f).Document().Name("hello.txt").Caption("The document")
|
||||||
|
c.Send(doc)
|
||||||
}),
|
}),
|
||||||
tg.NewCommand("botname", "get the bot name").
|
tg.NewCommand("botname", "get the bot name").
|
||||||
WithAction(tg.Func(func(c *tg.Context) {
|
WithAction(tg.Func(func(c *tg.Context) {
|
||||||
|
|
23
context.go
23
context.go
|
@ -156,7 +156,7 @@ func (c *Context) Send(v Sendable) (*Message, error) {
|
||||||
// Sends the formatted with fmt.Sprintf message to the user
|
// Sends the formatted with fmt.Sprintf message to the user
|
||||||
// using default Markdown parsing format.
|
// using default Markdown parsing format.
|
||||||
func (c *Context) Sendf(format string, v ...any) (*Message, error) {
|
func (c *Context) Sendf(format string, v ...any) (*Message, error) {
|
||||||
return c.Send(NewMessage(fmt.Sprintf(format, v...)))
|
return c.Send(NewMessage(format, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same as Sendf but uses Markdown 2 format for parsing.
|
// Same as Sendf but uses Markdown 2 format for parsing.
|
||||||
|
@ -372,10 +372,11 @@ func (c *Context) ReadString(pref string, args ...any) string {
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) GetFile(fileId FileId) (io.ReadCloser, error) {
|
// Returns the reader for specified file ID and path.
|
||||||
|
func (c *Context) GetFile(fileId FileId) (io.ReadCloser, string, error) {
|
||||||
file, err := c.Bot.Api.GetFile(tgbotapi.FileConfig{FileID:string(fileId)})
|
file, err := c.Bot.Api.GetFile(tgbotapi.FileConfig{FileID:string(fileId)})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
r, err := http.Get(fmt.Sprintf(
|
r, err := http.Get(fmt.Sprintf(
|
||||||
"https://api.telegram.org/file/bot%s/%s",
|
"https://api.telegram.org/file/bot%s/%s",
|
||||||
|
@ -383,27 +384,27 @@ func (c *Context) GetFile(fileId FileId) (io.ReadCloser, error) {
|
||||||
file.FilePath,
|
file.FilePath,
|
||||||
))
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
if r.StatusCode != 200 {
|
if r.StatusCode != 200 {
|
||||||
return nil, StatusCodeErr
|
return nil, "", StatusCodeErr
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.Body, nil
|
return r.Body, file.FilePath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) ReadFile(fileId FileId) ([]byte, error) {
|
func (c *Context) ReadFile(fileId FileId) ([]byte, string, error) {
|
||||||
file, err := c.GetFile(fileId)
|
file, pth, err := c.GetFile(fileId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
bts, err := io.ReadAll(file)
|
bts, err := io.ReadAll(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return bts, nil
|
return bts, pth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
75
file.go
75
file.go
|
@ -4,8 +4,8 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
//"os"
|
||||||
"path/filepath"
|
//"path/filepath"
|
||||||
|
|
||||||
"github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
"github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||||
)
|
)
|
||||||
|
@ -16,67 +16,96 @@ type FileType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NoFileType FileType = iota
|
NoFileType FileType = iota
|
||||||
ImageFileType
|
PhotoFileType
|
||||||
|
DocumentFileType
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
UnknownFileTypeErr = errors.New("unknown file type")
|
UnknownFileTypeErr = errors.New("unknown file type")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The type implements the structure to easily send
|
||||||
|
// files to the client.
|
||||||
type File struct {
|
type File struct {
|
||||||
*MessageCompo
|
*MessageCompo
|
||||||
path string
|
name string
|
||||||
|
reader io.Reader
|
||||||
|
upload bool
|
||||||
typ FileType
|
typ FileType
|
||||||
caption string
|
data, caption string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFile(path string) *File {
|
// Create the new file with the specified reader.
|
||||||
|
// By default it NeedsUpload is set to true.
|
||||||
|
func NewFile(reader io.Reader) *File {
|
||||||
ret := &File{}
|
ret := &File{}
|
||||||
|
|
||||||
ret.MessageCompo = NewMessage("")
|
ret.MessageCompo = NewMessage("")
|
||||||
ret.path = path
|
ret.reader = reader
|
||||||
|
ret.upload = true
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *File) Name(name string) *File {
|
||||||
|
f.name = name
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
func (f *File) withType(typ FileType) *File {
|
func (f *File) withType(typ FileType) *File {
|
||||||
f.typ = typ
|
f.typ = typ
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the file type.
|
||||||
func (f *File) Type() FileType {
|
func (f *File) Type() FileType {
|
||||||
return f.typ
|
return f.typ
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) Image() *File {
|
// Set the file type to PhotoFileType.
|
||||||
return f.withType(ImageFileType)
|
func (f *File) Photo() *File {
|
||||||
|
return f.withType(PhotoFileType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *File) Document() *File {
|
||||||
|
return f.withType(DocumentFileType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the file caption.
|
||||||
func (f *File) Caption(caption string) *File {
|
func (f *File) Caption(caption string) *File {
|
||||||
f.caption = caption
|
f.caption = caption
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specifiy whether the file needs to be uploaded to Telegram.
|
||||||
|
func (f *File) Upload(upload bool) *File {
|
||||||
|
f.upload = upload
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the data to return via SendData()
|
||||||
|
func (f *File) Data(data string) *File {
|
||||||
|
f.data = data
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
func (f *File) NeedsUpload() bool {
|
func (f *File) NeedsUpload() bool {
|
||||||
return true
|
return f.upload
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) UploadData() (string, io.Reader, error) {
|
func (f *File) UploadData() (string, io.Reader, error) {
|
||||||
rd, err := os.Open(f.path)
|
// Bufferizing the reader
|
||||||
if err != nil {
|
// to make it faster.
|
||||||
return "", nil, err
|
bufRd := bufio.NewReader(f.reader)
|
||||||
}
|
fileName := f.name
|
||||||
|
|
||||||
bufRd := bufio.NewReader(rd)
|
|
||||||
|
|
||||||
fileName := filepath.Base(f.path)
|
|
||||||
|
|
||||||
return fileName, bufRd, nil
|
return fileName, bufRd, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) SendData() string {
|
func (f *File) SendData() string {
|
||||||
return ""
|
return f.data
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) SendConfig(
|
func (f *File) SendConfig(
|
||||||
sid SessionId, bot *Bot,
|
sid SessionId, bot *Bot,
|
||||||
) (*SendConfig) {
|
) (*SendConfig) {
|
||||||
|
@ -84,11 +113,15 @@ func (f *File) SendConfig(
|
||||||
cid := sid.ToApi()
|
cid := sid.ToApi()
|
||||||
|
|
||||||
switch f.Type() {
|
switch f.Type() {
|
||||||
case ImageFileType:
|
case PhotoFileType:
|
||||||
photo := tgbotapi.NewPhoto(cid, f)
|
photo := tgbotapi.NewPhoto(cid, f)
|
||||||
photo.Caption = f.caption
|
photo.Caption = f.caption
|
||||||
|
|
||||||
config.Image = &photo
|
config.Photo = &photo
|
||||||
|
case DocumentFileType:
|
||||||
|
doc := tgbotapi.NewDocument(sid.ToApi(), f)
|
||||||
|
doc.Caption = f.caption
|
||||||
|
config.Document = &doc
|
||||||
default:
|
default:
|
||||||
panic(UnknownFileTypeErr)
|
panic(UnknownFileTypeErr)
|
||||||
}
|
}
|
||||||
|
|
3
media/hello.txt
Normal file
3
media/hello.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
Hello, World!
|
||||||
|
This is the text document!
|
||||||
|
|
16
send.go
16
send.go
|
@ -21,22 +21,16 @@ type Errorer interface {
|
||||||
// The type is used as an endpoint to send messages
|
// The type is used as an endpoint to send messages
|
||||||
// via bot.Send .
|
// via bot.Send .
|
||||||
type SendConfig struct {
|
type SendConfig struct {
|
||||||
// The name will be used to store
|
|
||||||
// the message in the map.
|
|
||||||
Name string
|
|
||||||
// Message with text and keyboard.
|
// Message with text and keyboard.
|
||||||
Message *tgbotapi.MessageConfig
|
Message *tgbotapi.MessageConfig
|
||||||
|
|
||||||
// The image to be sent.
|
// The image to be sent.
|
||||||
Image *tgbotapi.PhotoConfig
|
Photo *tgbotapi.PhotoConfig
|
||||||
|
Document *tgbotapi.DocumentConfig
|
||||||
Location *tgbotapi.LocationConfig
|
Location *tgbotapi.LocationConfig
|
||||||
Error error
|
Error error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *SendConfig) WithName(name string) *SendConfig {
|
|
||||||
cfg.Name = name
|
|
||||||
return cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
type MessageMap map[string] *Message
|
type MessageMap map[string] *Message
|
||||||
|
|
||||||
|
@ -45,10 +39,12 @@ func (config *SendConfig) ToApi() tgbotapi.Chattable {
|
||||||
switch {
|
switch {
|
||||||
case config.Message != nil :
|
case config.Message != nil :
|
||||||
return *(config.Message)
|
return *(config.Message)
|
||||||
case config.Image != nil :
|
case config.Photo != nil :
|
||||||
return *(config.Image)
|
return *(config.Photo)
|
||||||
case config.Location != nil :
|
case config.Location != nil :
|
||||||
return *(config.Location)
|
return *(config.Location)
|
||||||
|
case config.Document != nil :
|
||||||
|
return *(config.Document)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,13 +61,19 @@ func (updates *UpdateChan) Close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Update) HasDocument() bool {
|
func (u *Update) HasDocument() bool {
|
||||||
return u.Message != nil && u.Message.Document != nil
|
return u != nil &&
|
||||||
|
u.Message != nil &&
|
||||||
|
u.Message.Document != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Update) DocumentId() FileId {
|
func (u *Update) DocumentId() FileId {
|
||||||
return FileId(u.Update.Message.Document.FileID)
|
return FileId(u.Update.Message.Document.FileID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *Update) DocumentName() string {
|
||||||
|
return u.Message.Document.FileName
|
||||||
|
}
|
||||||
|
|
||||||
func (u *Update) HasPhotos() bool {
|
func (u *Update) HasPhotos() bool {
|
||||||
return u.Message != nil && u.Message.Photo != nil &&
|
return u.Message != nil && u.Message.Photo != nil &&
|
||||||
len(u.Message.Photo) != 0
|
len(u.Message.Photo) != 0
|
||||||
|
|
Loading…
Reference in a new issue