v1.0.0 beta 9

This commit is contained in:
2026-03-06 11:59:17 +03:00
parent 6cf3355a36
commit 9895edf966
19 changed files with 731 additions and 456 deletions

View File

@@ -1,7 +1,6 @@
package utils
import (
"encoding/json"
"fmt"
"io"
"mime/multipart"
@@ -26,33 +25,31 @@ func Encode[T any](w *multipart.Writer, req T) error {
field := v.Field(i)
fieldType := t.Field(i)
formTags := strings.Split(fieldType.Tag.Get("json"), ",")
fieldName := ""
if len(formTags) == 0 {
formTags = strings.Split(fieldType.Tag.Get("json"), ",")
jsonTag := fieldType.Tag.Get("json")
if jsonTag == "" {
jsonTag = fieldType.Name
}
if len(formTags) > 0 {
fieldName = formTags[0]
if fieldName == "-" {
continue
}
if slices.Index(formTags, "omitempty") >= 0 {
if field.IsZero() {
continue
}
}
} else {
fieldName = strings.ToLower(fieldType.Name)
parts := strings.Split(jsonTag, ",")
fieldName := parts[0]
if fieldName == "-" {
continue
}
// Handle omitempty
isEmpty := field.IsZero()
if slices.Contains(parts, "omitempty") && isEmpty {
continue
}
var (
fw io.Writer
err error
)
switch field.Kind() {
case reflect.String:
if field.String() != "" {
if !isEmpty {
fw, err = w.CreateFormField(fieldName)
if err == nil {
_, err = fw.Write([]byte(field.String()))
@@ -80,45 +77,47 @@ func Encode[T any](w *multipart.Writer, req T) error {
}
case reflect.Slice:
if field.Type().Elem().Kind() == reflect.Uint8 && !field.IsNil() {
// Handle []byte as file upload (e.g., thumbnail)
filename := fieldType.Tag.Get("filename")
if filename == "" {
filename = fieldName
}
ext := ""
filename = filename + ext
fw, err = w.CreateFormFile(fieldName, filename)
if err == nil {
_, err = fw.Write(field.Bytes())
}
} else if !field.IsNil() {
// Handle slice of primitive values (as multiple form fields with the same name)
// Handle []string, []int, etc. — send as multiple fields with same name
for j := 0; j < field.Len(); j++ {
elem := field.Index(j)
fw, err = w.CreateFormField(fieldName)
if err == nil {
switch elem.Kind() {
case reflect.String:
_, err = fw.Write([]byte(elem.String()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
_, err = fw.Write([]byte(strconv.FormatInt(elem.Int(), 10)))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
_, err = fw.Write([]byte(strconv.FormatUint(elem.Uint(), 10)))
}
if err != nil {
break
}
switch elem.Kind() {
case reflect.String:
_, err = fw.Write([]byte(elem.String()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
_, err = fw.Write([]byte(strconv.FormatInt(elem.Int(), 10)))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
_, err = fw.Write([]byte(strconv.FormatUint(elem.Uint(), 10)))
case reflect.Bool:
_, err = fw.Write([]byte(strconv.FormatBool(elem.Bool())))
case reflect.Float32, reflect.Float64:
_, err = fw.Write([]byte(strconv.FormatFloat(elem.Float(), 'f', -1, 64)))
}
if err != nil {
break
}
}
}
case reflect.Struct:
var jsonData []byte
jsonData, err = json.Marshal(field.Interface())
if err == nil {
fw, err = w.CreateFormField(fieldName)
if err == nil {
_, err = fw.Write(jsonData)
}
}
// Don't serialize structs as JSON — flatten them!
// Telegram doesn't support nested JSON in form-data.
// If you need nested data, use separate fields (e.g., ParseMode, CaptionEntities)
// This is a design choice — you should avoid nested structs in params.
return fmt.Errorf("nested structs are not supported in params — use flat fields")
}
if err != nil {