Simplified
This commit is contained in:
+81
-101
@@ -1,6 +1,7 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/fatih/structtag"
|
||||
"go/ast"
|
||||
@@ -117,118 +118,89 @@ func addStruct(a *ast.GenDecl) {
|
||||
api.Types[tp.Name] = &tp
|
||||
}
|
||||
|
||||
func addFunction(a *ast.FuncDecl) {
|
||||
func addFunction(a *ast.FuncDecl) error {
|
||||
md := manageComments(a.Doc)
|
||||
|
||||
if md["API"] == "" {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
llog("Adding Fuction: %s => %#v", a.Name, md)
|
||||
reqType := &APIParamType{}
|
||||
resType := &APIParamType{}
|
||||
|
||||
if len(a.Type.Params.List) > 1 {
|
||||
switch x := a.Type.Params.List[1].Type.(type) {
|
||||
case *ast.StarExpr:
|
||||
reqType.Ispointer = true
|
||||
switch y := x.X.(type) {
|
||||
case *ast.Ident:
|
||||
reqType.Typename = y.Name
|
||||
case *ast.SelectorExpr:
|
||||
api.UsedImportsFunctions[y.X.(*ast.Ident).Name] = api.Imports[y.X.(*ast.Ident).Name]
|
||||
reqType.Typename = y.X.(*ast.Ident).Name + "." + y.Sel.Name
|
||||
}
|
||||
case *ast.ArrayType:
|
||||
reqType.IsArray = true
|
||||
switch y := x.Elt.(type) {
|
||||
case *ast.Ident:
|
||||
reqType.Typename = y.Name
|
||||
case *ast.SelectorExpr:
|
||||
api.UsedImportsFunctions[y.X.(*ast.Ident).Name] = api.Imports[y.X.(*ast.Ident).Name]
|
||||
reqType.Typename = y.X.(*ast.Ident).Name + "." + y.Sel.Name
|
||||
case *ast.StarExpr:
|
||||
reqType.Ispointer = true
|
||||
switch z := y.X.(type) {
|
||||
case *ast.Ident:
|
||||
reqType.Typename = z.Name
|
||||
case *ast.SelectorExpr:
|
||||
api.UsedImportsFunctions[z.X.(*ast.Ident).Name] = api.Imports[z.X.(*ast.Ident).Name]
|
||||
reqType.Typename = z.X.(*ast.Ident).Name + "." + z.Sel.Name
|
||||
}
|
||||
}
|
||||
case *ast.Ident:
|
||||
reqType.Typename = x.Name
|
||||
case *ast.SelectorExpr:
|
||||
api.UsedImportsFunctions[x.X.(*ast.Ident).Name] = api.Imports[x.X.(*ast.Ident).Name]
|
||||
reqType.Typename = x.X.(*ast.Ident).Name + "." + x.Sel.Name
|
||||
}
|
||||
if len(a.Type.Params.List) != 2 {
|
||||
return errors.New(fmt.Sprintf("Function %s does not have 2 IN parameters (context and pointer to req struct)", a.Name.Name))
|
||||
}
|
||||
|
||||
if a.Type.Results != nil && len(a.Type.Results.List) > 0 {
|
||||
|
||||
switch x := a.Type.Results.List[0].Type.(type) {
|
||||
case *ast.StarExpr:
|
||||
resType.Ispointer = true
|
||||
switch y := x.X.(type) {
|
||||
case *ast.Ident:
|
||||
resType.Typename = y.Name
|
||||
case *ast.SelectorExpr:
|
||||
api.UsedImportsFunctions[y.X.(*ast.Ident).Name] = api.Imports[y.X.(*ast.Ident).Name]
|
||||
resType.Typename = y.X.(*ast.Ident).Name + "." + y.Sel.Name
|
||||
}
|
||||
case *ast.ArrayType:
|
||||
resType.IsArray = true
|
||||
switch y := x.Elt.(type) {
|
||||
case *ast.Ident:
|
||||
resType.Typename = y.Name
|
||||
case *ast.SelectorExpr:
|
||||
api.UsedImportsFunctions[y.X.(*ast.Ident).Name] = api.Imports[y.X.(*ast.Ident).Name]
|
||||
resType.Typename = y.X.(*ast.Ident).Name + "." + y.Sel.Name
|
||||
case *ast.StarExpr:
|
||||
resType.Ispointer = true
|
||||
switch z := y.X.(type) {
|
||||
case *ast.Ident:
|
||||
resType.Typename = z.Name
|
||||
case *ast.SelectorExpr:
|
||||
api.UsedImportsFunctions[z.X.(*ast.Ident).Name] = api.Imports[z.X.(*ast.Ident).Name]
|
||||
resType.Typename = z.X.(*ast.Ident).Name + "." + z.Sel.Name
|
||||
}
|
||||
}
|
||||
case *ast.Ident:
|
||||
resType.Typename = x.Name
|
||||
case *ast.SelectorExpr:
|
||||
api.UsedImportsFunctions[x.X.(*ast.Ident).Name] = api.Imports[x.X.(*ast.Ident).Name]
|
||||
resType.Typename = x.X.(*ast.Ident).Name + "." + x.Sel.Name
|
||||
|
||||
}
|
||||
|
||||
if md["RAW"] == "true" {
|
||||
reqType.Typename = md["REQ"]
|
||||
resType.Typename = md["RES"]
|
||||
}
|
||||
|
||||
verb := md["VERB"]
|
||||
if verb == "" {
|
||||
verb = http.MethodPost
|
||||
}
|
||||
fn := APIMethod{
|
||||
Name: a.Name.Name,
|
||||
Desc: a.Name.Name,
|
||||
Verb: verb,
|
||||
Path: md["PATH"],
|
||||
Perm: md["PERM"],
|
||||
ReqType: reqType,
|
||||
ResType: resType,
|
||||
}
|
||||
|
||||
if fn.Path == "" {
|
||||
fn.Path = "/" + strings.Replace(strings.ToLower(a.Name.Name), "_", "/", -1)
|
||||
}
|
||||
|
||||
api.Methods[a.Name.Name] = &fn
|
||||
if len(a.Type.Results.List) != 2 {
|
||||
return errors.New(fmt.Sprintf("Function %s does not have 2 OUT parameters (pointer to res struct and err)", a.Name.Name))
|
||||
}
|
||||
if a.Type.Results.List[1].Type.(*ast.Ident).Name != "error" {
|
||||
return errors.New(fmt.Sprintf("Function %s does not have error as 2nd OUT parameter", a.Name.Name))
|
||||
}
|
||||
|
||||
p0tp := a.Type.Params.List[0].Type.(*ast.SelectorExpr)
|
||||
if p0tp.X.(*ast.Ident).Name != "context" && p0tp.Sel.Name != "Context" {
|
||||
return errors.New(fmt.Sprintf("Function %s, param 1 is not of type context.Context", a.Name))
|
||||
}
|
||||
|
||||
switch x := a.Type.Params.List[1].Type.(type) {
|
||||
case *ast.StarExpr:
|
||||
reqType.Ispointer = true
|
||||
switch y := x.X.(type) {
|
||||
case *ast.Ident:
|
||||
reqType.Typename = y.Name
|
||||
case *ast.SelectorExpr:
|
||||
api.UsedImportsFunctions[y.X.(*ast.Ident).Name] = api.Imports[y.X.(*ast.Ident).Name]
|
||||
reqType.Typename = y.X.(*ast.Ident).Name + "." + y.Sel.Name
|
||||
}
|
||||
default:
|
||||
return errors.New(fmt.Sprintf("Function %s does not have 2 IN parameters (context and pointer to req struct)", a.Name.Name))
|
||||
|
||||
}
|
||||
|
||||
switch x := a.Type.Results.List[0].Type.(type) {
|
||||
case *ast.StarExpr:
|
||||
resType.Ispointer = true
|
||||
switch y := x.X.(type) {
|
||||
case *ast.Ident:
|
||||
resType.Typename = y.Name
|
||||
case *ast.SelectorExpr:
|
||||
api.UsedImportsFunctions[y.X.(*ast.Ident).Name] = api.Imports[y.X.(*ast.Ident).Name]
|
||||
resType.Typename = y.X.(*ast.Ident).Name + "." + y.Sel.Name
|
||||
}
|
||||
default:
|
||||
return errors.New(fmt.Sprintf("Function %s does not have 2 OUT parameters (pointer to res struct and err)", a.Name.Name))
|
||||
|
||||
}
|
||||
|
||||
if md["RAW"] == "true" {
|
||||
reqType.Typename = md["REQ"]
|
||||
resType.Typename = md["RES"]
|
||||
}
|
||||
|
||||
verb := md["VERB"]
|
||||
if verb == "" {
|
||||
verb = http.MethodPost
|
||||
}
|
||||
fn := APIMethod{
|
||||
Name: a.Name.Name,
|
||||
Desc: a.Name.Name,
|
||||
Verb: verb,
|
||||
Path: md["PATH"],
|
||||
Perm: md["PERM"],
|
||||
ReqType: reqType,
|
||||
ResType: resType,
|
||||
}
|
||||
|
||||
if fn.Path == "" {
|
||||
fn.Path = "/" + strings.Replace(strings.ToLower(a.Name.Name), "_", "/", -1)
|
||||
}
|
||||
|
||||
api.Methods[a.Name.Name] = &fn
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func load(src string) error {
|
||||
@@ -255,6 +227,11 @@ func load(src string) error {
|
||||
// Print the AST.
|
||||
ast.Inspect(v, func(n ast.Node) bool {
|
||||
|
||||
//tp := reflect.TypeOf(n)
|
||||
//if tp != nil {
|
||||
// log.Printf("Type: %#v", tp.String())
|
||||
//}
|
||||
|
||||
switch x := n.(type) {
|
||||
|
||||
case *ast.GenDecl:
|
||||
@@ -278,7 +255,10 @@ func load(src string) error {
|
||||
case *ast.File:
|
||||
manageCommentsGroups(x.Comments)
|
||||
case *ast.FuncDecl:
|
||||
addFunction(x)
|
||||
err = addFunction(x)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
llog("Adding fn: %s", x.Name)
|
||||
case *ast.ValueSpec:
|
||||
if x.Names[0].Name == "BASEPATH" {
|
||||
@@ -341,5 +321,5 @@ func load(src string) error {
|
||||
|
||||
api.Namespace = packageName
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
+148
-40
@@ -27,16 +27,117 @@ func processGoServerOutput(f string) error {
|
||||
|
||||
WNL("package %s", api.Namespace)
|
||||
WNL(`import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"net/http"
|
||||
)`)
|
||||
"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
|
||||
@@ -47,41 +148,6 @@ func (a *API) GetPerm(r *http.Request) string {
|
||||
}
|
||||
`)
|
||||
|
||||
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
|
||||
}`)
|
||||
|
||||
for _, v := range api.Methods {
|
||||
WNL(`func h_%s(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
@@ -90,6 +156,12 @@ func (a *API) GetPerm(r *http.Request) string {
|
||||
|
||||
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 {
|
||||
@@ -119,5 +191,41 @@ func (a *API) GetPerm(r *http.Request) string {
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user