Skip to content

Commit

Permalink
Compile-time inputfile validation (#163)
Browse files Browse the repository at this point in the history
* Cleanup and improve inputfile interfaces

* Update sample bots to work with new typesafe inputfile logic

* Media should be of type inputfileorstring

* fix lint

* Make sure thumbnails cannot be strings

* Improve inputfile logic to properly handle values json value marshalling

* Add missing thumbnail logic to certain inputmedia types and improve
error messages

* remove unnecessary InputString type which turned out to be unnecessary

* regenerate after merge
  • Loading branch information
PaulSonOfLars authored Jul 1, 2024
1 parent 4a42cea commit a8e2c08
Show file tree
Hide file tree
Showing 11 changed files with 382 additions and 641 deletions.
2 changes: 1 addition & 1 deletion bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (bot *Bot) UseMiddleware(mw func(client BotClient) BotClient) *Bot {

var ErrNilBotClient = errors.New("nil BotClient")

func (bot *Bot) Request(method string, params map[string]string, data map[string]NamedReader, opts *RequestOpts) (json.RawMessage, error) {
func (bot *Bot) Request(method string, params map[string]string, data map[string]FileReader, opts *RequestOpts) (json.RawMessage, error) {
if bot.BotClient == nil {
return nil, ErrNilBotClient
}
Expand Down
94 changes: 94 additions & 0 deletions file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package gotgbot

import (
"encoding/json"
"errors"
"io"
)

// InputFile (https://core.telegram.org/bots/api#inputfile)
//
// This object represents the contents of a file to be uploaded.
// Must be posted using multipart/form-data in the usual way that files are uploaded via the browser.
type InputFile interface {
InputFileOrString
justFiles()
}

// InputFileOrString (https://core.telegram.org/bots/api#inputfile)
//
// This object represents the contents of a file to be uploaded, or a publicly accessible URL to be reused.
// Files must be posted using multipart/form-data in the usual way that files are uploaded via the browser.
type InputFileOrString interface {
Attach(name string, data map[string]FileReader) error
getValue() string
}

var (
_ InputFileOrString = &FileReader{}
_ InputFile = &FileReader{}
)

type FileReader struct {
Name string
Data io.Reader

value string
}

func (f *FileReader) MarshalJSON() ([]byte, error) {
return json.Marshal(f.getValue())
}

var ErrAttachmentKeyAlreadyExists = errors.New("key already exists")

func (f *FileReader) justFiles() {}

func (f *FileReader) Attach(key string, data map[string]FileReader) error {
if f.Data == nil {
// if no data, this must be a string; nothing to "attach".
return nil
}

if _, ok := data[key]; ok {
return ErrAttachmentKeyAlreadyExists
}
f.value = "attach://" + key
data[key] = *f
return nil
}

// getValue returns the file attach reference for the relevant multipart form.
// Make sure to only call getValue after having called Attach(), to ensure any files have been included.
func (f *FileReader) getValue() string {
return f.value
}

// InputFileByURL is used to send a file on the internet via a publicly accessible HTTP URL.
func InputFileByURL(url string) InputFileOrString {
return &FileReader{value: url}
}

// InputFileByID is used to send a file that is already present on telegram's servers, using its telegram file_id.
func InputFileByID(fileID string) InputFileOrString {
return &FileReader{value: fileID}
}

// InputFileByReader is used to send a file by a reader interface; such as a filehandle from os.Open(), or from a byte
// buffer.
//
// For example:
//
// f, err := os.Open("some_file.go")
// if err != nil {
// return fmt.Errorf("failed to open file: %w", err)
// }
//
// m, err := b.SendDocument(<chat_id>, gotgbot.InputFileByReader("source.go", f), nil)
//
// Or
//
// m, err := b.SendDocument(<chat_id>, gotgbot.InputFileByReader("file.txt", strings.NewReader("Some file contents")), nil)
func InputFileByReader(name string, r io.Reader) InputFile {
return &FileReader{Name: name, Data: r}
}
Loading

0 comments on commit a8e2c08

Please sign in to comment.