apigen/lib/processGoServerOutput.go

232 lines
4.3 KiB
Go

package lib
import (
"bytes"
_ "embed"
"fmt"
"os"
)
func processGoServerOutput(f string) error {
buf := &bytes.Buffer{}
//W := func(s string, p ...interface{}) {
// buf.WriteString(fmt.Sprintf(s, p...))
//}
WNL := func(s string, p ...interface{}) {
buf.WriteString(fmt.Sprintf(s+"\n", p...))
}
ResImplType := func(v *APIParamType) string {
ret := ""
if !v.IsArray || v.Ispointer {
ret = ret + "&"
}
ret += v.Typename + "{}"
return ret
}
WNL("package %s", api.Namespace)
WNL(`import (
"context"
"encoding/json"
"strings"
"net/http"
"errors"
"reflect"
"strconv"
)`)
for k := range api.UsedImportsFunctions {
WNL(`import "%s"`, k)
}
WNL(`func handleTag(s string, r *http.Request) string {
parts := strings.Split(s, ":")
where := "Q"
key := ""
if len(parts) == 1 {
key = parts[0]
} else {
where = parts[0]
key = parts[1]
}
switch where {
case "Q":
return r.URL.Query().Get(key)
case "H":
return r.Header.Get(key)
case "P":
switch key {
case "*":
return r.URL.Path
case "last":
pps := strings.Split(r.URL.Path, "/")
return pps[len(pps)-1]
case "len":
pps := strings.Split(r.URL.Path, "/")
return strconv.Itoa(len(pps))
default:
pps := strings.Split(r.URL.Path, "/")
n, _ := strconv.Atoi(key)
if n < len(pps) {
return pps[n]
}
return ""
}
}
return ""
}
func convert(s string, tpname string) interface{} {
switch tpname {
case "string":
return s
case "int":
v, _ := strconv.Atoi(s)
return v
case "int8":
v, _ := strconv.Atoi(s)
return int8(v)
case "int16":
v, _ := strconv.Atoi(s)
return int16(v)
case "int32":
v, _ := strconv.Atoi(s)
return int32(v)
case "int64":
v, _ := strconv.Atoi(s)
return int64(v)
case "uint":
v, _ := strconv.Atoi(s)
return uint(v)
case "float32":
v, _ := strconv.Atoi(s)
return float32(v)
case "float64":
v, _ := strconv.Atoi(s)
return float64(v)
case "bool":
return s == "true" || s == "1" || s == "Y"
}
return nil
}
func Map(r *http.Request, in interface{}) error {
tp := reflect.TypeOf(in)
vl := reflect.ValueOf(in)
if tp.Kind() == reflect.Ptr {
tp = tp.Elem()
vl = vl.Elem()
}
if tp.Kind() != reflect.Struct {
return errors.New("Type is not struct")
}
for i := 0; i < tp.NumField(); i++ {
k, ok := tp.Field(i).Tag.Lookup("in")
if ok {
str := handleTag(k, r)
v := convert(str, tp.Field(i).Type.Name())
strv := reflect.ValueOf(v)
vl.Field(i).Set(strv)
}
}
return nil
}
`)
WNL(`type API struct {
Mux *http.ServeMux
Perms map[string]string
}
func (a *API) GetPerm(r *http.Request) string {
return a.Perms[r.Method+"_"+strings.Split(r.RequestURI, "?")[0]]
}
`)
for _, v := range api.Methods {
WNL(`func h_%s(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ctx = context.WithValue(r.Context(), "REQ", r)
ctx = context.WithValue(ctx, "RES", w)`, v.Name)
WNL(" req := %s", ResImplType(v.ReqType))
WNL(` err:=Map(r,req)
if err != nil {
http.Error(w, err.Error(), 500)
return
}`)
WNL(` if r.Method!=http.MethodGet && r.Method!=http.MethodHead {`)
if v.ReqType.Ispointer || v.ReqType.IsArray {
WNL(" err := json.NewDecoder(r.Body).Decode(req)")
} else {
WNL(" err := json.NewDecoder(r.Body).Decode(&req)")
}
WNL(` if err != nil {
http.Error(w, err.Error(), 500)
return
}
}`)
WNL(` res, err := %s(ctx,req)`, v.Name)
WNL(` if err != nil {
http.Error(w, err.Error(), 500)
return
}
w.Header().Add("Content-Type","Application/json")
err=json.NewEncoder(w).Encode(res)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
}`)
}
WNL(`func Init() *API{
mux := &http.ServeMux{}
ret := &API{
Mux: mux,
Perms: make(map[string]string),
}`)
for _, v := range api.Methods {
if v.Perm != "" {
WNL(` ret.Perms["%s_%s"]="%s"`, v.Verb, v.Path, v.Perm)
}
}
for _, v := range api.SortedPaths {
WNL(` mux.HandleFunc("%s",func(w http.ResponseWriter, r *http.Request) {
switch r.Method {`, v.Path)
for _, v1 := range v.SortedVerbs {
WNL(` case "%s":`, v1.Method.Verb)
if v1.Method.Raw {
WNL(` %s(w,r)`, v1.Method.Name)
} else {
WNL(` h_%s(w,r)`, v1.Method.Name)
}
}
WNL(` default:
http.Error(w,"Method not allowed",500)
}`)
WNL(` })`)
}
WNL(` return ret
}`)
return os.WriteFile(f, buf.Bytes(), 0600)
}