2022-04-30 00:04:38 +08:00
|
|
|
package bot
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"io"
|
|
|
|
"mime/multipart"
|
|
|
|
"reflect"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/go-telegram/bot/models"
|
|
|
|
)
|
|
|
|
|
2024-07-18 22:37:31 +08:00
|
|
|
type inputMedia interface {
|
|
|
|
MarshalInputMedia() ([]byte, error)
|
|
|
|
Attachment() io.Reader
|
|
|
|
GetMedia() string
|
|
|
|
}
|
|
|
|
|
2022-05-02 21:58:40 +08:00
|
|
|
type customMarshal interface {
|
|
|
|
MarshalCustom() ([]byte, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
var customMarshalInterface = reflect.TypeOf(new(customMarshal)).Elem()
|
2024-07-18 22:37:31 +08:00
|
|
|
var inputMediaInterface = reflect.TypeOf(new(inputMedia)).Elem()
|
2022-04-30 00:04:38 +08:00
|
|
|
|
|
|
|
// buildRequestForm builds form-data for request
|
|
|
|
// if params contains InputFile of type InputFileUpload, it will be added to form-data ad upload file. Also, for InputMedia attachments
|
2023-02-10 18:01:01 +08:00
|
|
|
func buildRequestForm(form *multipart.Writer, params any) (int, error) {
|
2022-04-30 00:04:38 +08:00
|
|
|
v := reflect.ValueOf(params).Elem()
|
|
|
|
|
2023-02-10 18:01:01 +08:00
|
|
|
var fieldsCount int
|
|
|
|
|
2022-04-30 00:04:38 +08:00
|
|
|
for i := 0; i < v.NumField(); i++ {
|
|
|
|
jsonTag := v.Type().Field(i).Tag.Get("json")
|
|
|
|
if jsonTag == "-" || jsonTag == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
fieldName := strings.Split(jsonTag, ",")[0]
|
|
|
|
omitempty := strings.Contains(jsonTag, ",omitempty")
|
|
|
|
|
|
|
|
if omitempty && v.Field(i).IsZero() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-05-02 20:53:14 +08:00
|
|
|
// check fields by interface
|
2022-05-02 21:58:40 +08:00
|
|
|
if v.Field(i).Type().Implements(customMarshalInterface) {
|
|
|
|
err := addFormFieldCustomMarshal(form, fieldName, v.Field(i).Interface().(customMarshal))
|
2022-05-02 20:53:14 +08:00
|
|
|
if err != nil {
|
2023-02-10 18:01:01 +08:00
|
|
|
return 0, err
|
2022-05-02 20:53:14 +08:00
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
2022-05-02 21:58:40 +08:00
|
|
|
if v.Field(i).Type().Implements(inputMediaInterface) {
|
2024-07-18 22:37:31 +08:00
|
|
|
err := addFormFieldInputMedia(form, fieldName, v.Field(i).Interface().(inputMedia))
|
2022-05-02 21:25:45 +08:00
|
|
|
if err != nil {
|
2023-02-10 18:01:01 +08:00
|
|
|
return 0, err
|
2022-05-02 21:25:45 +08:00
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-05-02 20:53:14 +08:00
|
|
|
var err error
|
2022-04-30 00:04:38 +08:00
|
|
|
|
2022-05-02 20:53:14 +08:00
|
|
|
// check fields by type
|
2022-04-30 00:04:38 +08:00
|
|
|
switch vv := v.Field(i).Interface().(type) {
|
|
|
|
case string:
|
2022-05-02 20:53:14 +08:00
|
|
|
err = addFormFieldString(form, fieldName, vv)
|
2022-04-30 00:04:38 +08:00
|
|
|
case *models.InputFileUpload:
|
2022-05-02 20:53:14 +08:00
|
|
|
err = addFormFieldInputFileUpload(form, fieldName, vv)
|
2022-04-30 00:04:38 +08:00
|
|
|
case *models.InputFileString:
|
2022-05-02 20:53:14 +08:00
|
|
|
err = addFormFieldString(form, fieldName, vv.Data)
|
2022-04-30 00:04:38 +08:00
|
|
|
case []models.InputMedia:
|
2024-07-18 22:37:31 +08:00
|
|
|
var ss []inputMedia
|
|
|
|
for _, m := range vv {
|
|
|
|
ss = append(ss, m)
|
|
|
|
}
|
|
|
|
err = addFormFieldInputMediaSlice(form, fieldName, ss)
|
|
|
|
case []models.InputPaidMedia:
|
|
|
|
var ss []inputMedia
|
|
|
|
for _, m := range vv {
|
|
|
|
ss = append(ss, m)
|
|
|
|
}
|
|
|
|
err = addFormFieldInputMediaSlice(form, fieldName, ss)
|
2022-05-02 20:53:14 +08:00
|
|
|
case []models.InlineQueryResult:
|
|
|
|
err = addFormFieldInlineQueryResultSlice(form, fieldName, vv)
|
2022-04-30 00:04:38 +08:00
|
|
|
default:
|
2022-05-02 20:53:14 +08:00
|
|
|
err = addFormFieldDefault(form, fieldName, v.Field(i).Interface())
|
2022-04-30 00:04:38 +08:00
|
|
|
}
|
2022-05-02 20:53:14 +08:00
|
|
|
if err != nil {
|
2023-02-10 18:01:01 +08:00
|
|
|
return 0, err
|
2022-04-30 00:04:38 +08:00
|
|
|
}
|
2023-02-10 18:01:01 +08:00
|
|
|
|
|
|
|
fieldsCount++
|
2022-05-02 20:53:14 +08:00
|
|
|
}
|
|
|
|
|
2023-02-10 18:01:01 +08:00
|
|
|
return fieldsCount, nil
|
2022-05-02 20:53:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func addFormFieldInputFileUpload(form *multipart.Writer, fieldName string, value *models.InputFileUpload) error {
|
|
|
|
w, errCreateField := form.CreateFormFile(fieldName, value.Filename)
|
|
|
|
if errCreateField != nil {
|
|
|
|
return errCreateField
|
|
|
|
}
|
|
|
|
_, errCopy := io.Copy(w, value.Data)
|
|
|
|
return errCopy
|
|
|
|
}
|
2022-04-30 00:04:38 +08:00
|
|
|
|
2024-07-18 22:37:31 +08:00
|
|
|
func addFormFieldInputMediaItem(form *multipart.Writer, value inputMedia) ([]byte, error) {
|
2022-05-02 20:53:14 +08:00
|
|
|
if strings.HasPrefix(value.GetMedia(), "attach://") {
|
|
|
|
filename := strings.TrimPrefix(value.GetMedia(), "attach://")
|
|
|
|
mediaAttachmentField, errCreateMediaAttachmentField := form.CreateFormFile(filename, filename)
|
|
|
|
if errCreateMediaAttachmentField != nil {
|
|
|
|
return nil, errCreateMediaAttachmentField
|
|
|
|
}
|
|
|
|
_, errCopy := io.Copy(mediaAttachmentField, value.Attachment())
|
2022-04-30 00:04:38 +08:00
|
|
|
if errCopy != nil {
|
2022-05-02 20:53:14 +08:00
|
|
|
return nil, errCopy
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return value.MarshalInputMedia()
|
|
|
|
}
|
|
|
|
|
2022-05-02 21:58:40 +08:00
|
|
|
func addFormFieldCustomMarshal(form *multipart.Writer, fieldName string, value customMarshal) error {
|
|
|
|
line, errEncode := value.MarshalCustom()
|
|
|
|
if errEncode != nil {
|
|
|
|
return errEncode
|
|
|
|
}
|
|
|
|
w, errCreateField := form.CreateFormField(fieldName)
|
|
|
|
if errCreateField != nil {
|
|
|
|
return errCreateField
|
|
|
|
}
|
|
|
|
_, errCopy := io.Copy(w, bytes.NewReader(line))
|
|
|
|
return errCopy
|
|
|
|
}
|
|
|
|
|
2024-07-18 22:37:31 +08:00
|
|
|
func addFormFieldInputMedia(form *multipart.Writer, fieldName string, value inputMedia) error {
|
2022-05-02 20:53:14 +08:00
|
|
|
line, err := addFormFieldInputMediaItem(form, value)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
w, errCreateField := form.CreateFormField(fieldName)
|
|
|
|
if errCreateField != nil {
|
|
|
|
return errCreateField
|
|
|
|
}
|
|
|
|
_, errCopy := io.Copy(w, bytes.NewReader(line))
|
|
|
|
return errCopy
|
|
|
|
}
|
|
|
|
|
2024-07-18 22:37:31 +08:00
|
|
|
func addFormFieldInputMediaSlice(form *multipart.Writer, fieldName string, value []inputMedia) error {
|
2022-05-02 20:53:14 +08:00
|
|
|
var lines []string
|
|
|
|
for _, media := range value {
|
|
|
|
line, err := addFormFieldInputMediaItem(form, media)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
lines = append(lines, string(line))
|
|
|
|
}
|
|
|
|
|
|
|
|
w, errCreateField := form.CreateFormField(fieldName)
|
|
|
|
if errCreateField != nil {
|
|
|
|
return errCreateField
|
|
|
|
}
|
|
|
|
_, errCopy := io.Copy(w, strings.NewReader("["+strings.Join(lines, ",")+"]"))
|
|
|
|
return errCopy
|
|
|
|
}
|
|
|
|
|
|
|
|
func addFormFieldInlineQueryResultSlice(form *multipart.Writer, fieldName string, value []models.InlineQueryResult) error {
|
|
|
|
var lines []string
|
|
|
|
for _, media := range value {
|
2022-05-02 21:58:40 +08:00
|
|
|
line, errEncode := media.MarshalCustom()
|
2022-05-02 20:53:14 +08:00
|
|
|
if errEncode != nil {
|
|
|
|
return errEncode
|
2022-04-30 00:04:38 +08:00
|
|
|
}
|
2022-05-02 20:53:14 +08:00
|
|
|
lines = append(lines, string(line))
|
2022-04-30 00:04:38 +08:00
|
|
|
}
|
|
|
|
|
2022-05-02 20:53:14 +08:00
|
|
|
w, errCreateField := form.CreateFormField(fieldName)
|
|
|
|
if errCreateField != nil {
|
|
|
|
return errCreateField
|
2022-04-30 00:04:38 +08:00
|
|
|
}
|
2022-05-02 20:53:14 +08:00
|
|
|
_, errCopy := io.Copy(w, strings.NewReader("["+strings.Join(lines, ",")+"]"))
|
|
|
|
return errCopy
|
|
|
|
}
|
2022-04-30 00:04:38 +08:00
|
|
|
|
2022-05-02 20:53:14 +08:00
|
|
|
func addFormFieldDefault(form *multipart.Writer, fieldName string, value any) error {
|
|
|
|
d, errMarshal := json.Marshal(value)
|
|
|
|
if errMarshal != nil {
|
|
|
|
return errMarshal
|
2022-04-30 00:04:38 +08:00
|
|
|
}
|
2022-05-02 20:53:14 +08:00
|
|
|
d = bytes.Trim(d, "\"") // for strings values
|
|
|
|
w, errCreateField := form.CreateFormField(fieldName)
|
|
|
|
if errCreateField != nil {
|
|
|
|
return errCreateField
|
|
|
|
}
|
|
|
|
_, errCopy := io.Copy(w, bytes.NewReader(d))
|
|
|
|
return errCopy
|
|
|
|
}
|
2022-04-30 00:04:38 +08:00
|
|
|
|
2022-05-02 20:53:14 +08:00
|
|
|
func addFormFieldString(form *multipart.Writer, fieldName string, value string) error {
|
|
|
|
w, errCreateField := form.CreateFormField(fieldName)
|
|
|
|
if errCreateField != nil {
|
|
|
|
return errCreateField
|
|
|
|
}
|
|
|
|
_, errCopy := io.Copy(w, strings.NewReader(value))
|
|
|
|
return errCopy
|
2022-04-30 00:04:38 +08:00
|
|
|
}
|