chat actions and file uploading; v0.3.7

This commit is contained in:
2026-02-04 11:13:26 +03:00
parent c71aad0c79
commit 913fa20e19
7 changed files with 360 additions and 29 deletions

131
multipart.go Normal file
View File

@@ -0,0 +1,131 @@
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
}