132 lines
3.1 KiB
Go
132 lines
3.1 KiB
Go
package laniakea
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"mime/multipart"
|
|
"reflect"
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func Encode[T any](w *multipart.Writer, req T) error {
|
|
v := reflect.ValueOf(req)
|
|
if v.Kind() == reflect.Ptr {
|
|
v = v.Elem()
|
|
}
|
|
|
|
if v.Kind() != reflect.Struct {
|
|
return fmt.Errorf("req must be a struct")
|
|
}
|
|
|
|
t := v.Type()
|
|
for i := 0; i < v.NumField(); i++ {
|
|
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"), ",")
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
var (
|
|
fw io.Writer
|
|
err error
|
|
)
|
|
switch field.Kind() {
|
|
case reflect.String:
|
|
if field.String() != "" {
|
|
fw, err = w.CreateFormField(fieldName)
|
|
if err == nil {
|
|
_, err = fw.Write([]byte(field.String()))
|
|
}
|
|
}
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
fw, err = w.CreateFormField(fieldName)
|
|
if err == nil {
|
|
_, err = fw.Write([]byte(strconv.FormatInt(field.Int(), 10)))
|
|
}
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
fw, err = w.CreateFormField(fieldName)
|
|
if err == nil {
|
|
_, err = fw.Write([]byte(strconv.FormatUint(field.Uint(), 10)))
|
|
}
|
|
case reflect.Float32, reflect.Float64:
|
|
fw, err = w.CreateFormField(fieldName)
|
|
if err == nil {
|
|
_, err = fw.Write([]byte(strconv.FormatFloat(field.Float(), 'f', -1, 64)))
|
|
}
|
|
case reflect.Bool:
|
|
fw, err = w.CreateFormField(fieldName)
|
|
if err == nil {
|
|
_, err = fw.Write([]byte(strconv.FormatBool(field.Bool())))
|
|
}
|
|
|
|
case reflect.Slice:
|
|
if field.Type().Elem().Kind() == reflect.Uint8 && !field.IsNil() {
|
|
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)
|
|
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)))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|