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) }