Added gocli output (untested)
parent
a18faee98e
commit
539cdc478e
|
@ -1,3 +1,4 @@
|
||||||
gofname: test/goapi/api.go
|
gofname: test/goapi/api.go
|
||||||
goimpldir: test/goapi
|
goimpldir: test/goapi
|
||||||
tsfname: test/tscli/api.ts
|
tsfname: test/tscli/api.ts
|
||||||
|
goclifname: test/gocli/apicli.go
|
||||||
|
|
|
@ -10,6 +10,7 @@ type Config struct {
|
||||||
Gofname string `yaml:"gofname"`
|
Gofname string `yaml:"gofname"`
|
||||||
Goimpldir string `yaml:"goimpldir"`
|
Goimpldir string `yaml:"goimpldir"`
|
||||||
Tsfname string `json:"tsfname"`
|
Tsfname string `json:"tsfname"`
|
||||||
|
Goclifname string `json:"goclifname"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var config Config
|
var config Config
|
||||||
|
|
275
main.go
275
main.go
|
@ -1,17 +1,12 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"dc"
|
|
||||||
"fmt"
|
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -159,275 +154,6 @@ func addFunction(a *ast.FuncDecl) {
|
||||||
api.Methods[a.Name.Name] = &fn
|
api.Methods[a.Name.Name] = &fn
|
||||||
}
|
}
|
||||||
|
|
||||||
func processGoServerOutput(api *API) {
|
|
||||||
|
|
||||||
APIParamTypeToString := func(t *APIParamType) string {
|
|
||||||
ret := ""
|
|
||||||
if t.Ispointer {
|
|
||||||
ret = ret + "&"
|
|
||||||
}
|
|
||||||
ret = ret + t.Typename
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
b := bytes.Buffer{}
|
|
||||||
|
|
||||||
f := config.Gofname
|
|
||||||
|
|
||||||
os.Remove(f)
|
|
||||||
b.WriteString(fmt.Sprintf(`package %s
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
`, packageName))
|
|
||||||
|
|
||||||
b.WriteString(`
|
|
||||||
|
|
||||||
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]]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func Init() API{
|
|
||||||
mux := &http.ServeMux{}
|
|
||||||
|
|
||||||
ret := API{
|
|
||||||
Mux: mux,
|
|
||||||
Perms: make(map[string]string),
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
for _, m := range api.Methods {
|
|
||||||
if m.Perm != "" {
|
|
||||||
b.WriteString(fmt.Sprintf(`
|
|
||||||
ret.Perms["%s_%s"]="%s"
|
|
||||||
`, m.Verb, m.Path, m.Perm))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.WriteString("\n\n")
|
|
||||||
|
|
||||||
for p, mv := range httpMapper {
|
|
||||||
|
|
||||||
b.WriteString(fmt.Sprintf(" mux.HandleFunc(\"%s\",func(w http.ResponseWriter, r *http.Request) {\n", strings.Replace(p, "//", "/", -1)))
|
|
||||||
b.WriteString(" switch r.Method{\n")
|
|
||||||
|
|
||||||
for v, id := range mv {
|
|
||||||
|
|
||||||
b.WriteString(fmt.Sprintf(" case \"%s\":", v))
|
|
||||||
if api.Methods[id].Raw {
|
|
||||||
b.WriteString(fmt.Sprintf(" %s(w , r)\n", id))
|
|
||||||
} else {
|
|
||||||
b.WriteString(fmt.Sprintf(" h_%s(w , r)\n", id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.WriteString(" default:")
|
|
||||||
b.WriteString(" http.Error(w,\"Method not allowed\",500)")
|
|
||||||
|
|
||||||
b.WriteString(" }\n")
|
|
||||||
b.WriteString("})\n")
|
|
||||||
}
|
|
||||||
b.WriteString("return ret\n }\n")
|
|
||||||
|
|
||||||
for k, m := range api.Methods {
|
|
||||||
if !m.Raw {
|
|
||||||
b.WriteString(fmt.Sprintf("\n func h_%s(w http.ResponseWriter, r *http.Request) {\n", k))
|
|
||||||
|
|
||||||
b.WriteString(fmt.Sprintf(
|
|
||||||
`
|
|
||||||
ctx := r.Context()
|
|
||||||
ctx = context.WithValue(r.Context(), "REQ", r)
|
|
||||||
ctx = context.WithValue(ctx, "RES", w)
|
|
||||||
req := %s{}
|
|
||||||
if r.Method!=http.MethodGet && r.Method!=http.MethodHead {
|
|
||||||
err := json.NewDecoder(r.Body).Decode(&req)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), 500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := %s(ctx,req)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
`, APIParamTypeToString(m.ReqType), k))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err := ioutil.WriteFile(f, b.Bytes(), 0600)
|
|
||||||
dc.Err(err)
|
|
||||||
cmd := exec.Command("/bin/sh", "-c", "go fmt "+f)
|
|
||||||
bs, err := cmd.Output()
|
|
||||||
//dc.Err(err)
|
|
||||||
dc.Log(string(bs))
|
|
||||||
}
|
|
||||||
func processTSClientOutput(f string, api *API) {
|
|
||||||
b := bytes.Buffer{}
|
|
||||||
if f == "" {
|
|
||||||
f = config.Tsfname
|
|
||||||
}
|
|
||||||
|
|
||||||
b.WriteString("//#region Base\n")
|
|
||||||
b.WriteString(fmt.Sprintf(`
|
|
||||||
|
|
||||||
var apibase="%s";
|
|
||||||
|
|
||||||
export function SetAPIBase(s:string){
|
|
||||||
apibase=s;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetAPIBase(): string{
|
|
||||||
return apibase;
|
|
||||||
}
|
|
||||||
|
|
||||||
let REGEX_DATE = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)(Z|([+\-])(\d{2}):(\d{2}))$/
|
|
||||||
|
|
||||||
type HTMLMethod = "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "TRACE"
|
|
||||||
|
|
||||||
async function Invoke(path: string, method: HTMLMethod, body?: any): Promise<Response> {
|
|
||||||
let jbody = undefined
|
|
||||||
let init = {method: method, mode: "cors", credentials: "include", withCredentials: true}
|
|
||||||
if (!!body) {
|
|
||||||
let jbody = JSON.stringify(body)
|
|
||||||
//@ts-ignore
|
|
||||||
init.body = jbody
|
|
||||||
}
|
|
||||||
if (apibase.endsWith("/") && path.startsWith("/")) {
|
|
||||||
path = path.substr(1, path.length)
|
|
||||||
}
|
|
||||||
let fpath = (apibase + path)
|
|
||||||
//@ts-ignore
|
|
||||||
let res = await fetch(fpath, init)
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
async function InvokeJSON(path: string, method: HTMLMethod, body?: any): Promise<any> {
|
|
||||||
|
|
||||||
let txt = await InvokeTxt(path, method, body)
|
|
||||||
if (txt == "") {
|
|
||||||
txt = "{}"
|
|
||||||
}
|
|
||||||
let ret = JSON.parse(txt, (k: string, v: string) => {
|
|
||||||
if (REGEX_DATE.exec(v)) {
|
|
||||||
return new Date(v)
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
})
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
async function InvokeTxt(path: string, method: HTMLMethod, body?: any): Promise<string> {
|
|
||||||
//@ts-ignore
|
|
||||||
let res = await Invoke(path, method, body)
|
|
||||||
|
|
||||||
let txt = await res.text()
|
|
||||||
|
|
||||||
if (res.status < 200 || res.status >= 400) {
|
|
||||||
// webix.alert("API Error:" + res.status + "\n" + txt)
|
|
||||||
console.error("API Error:" + res.status + "\n" + txt)
|
|
||||||
let e = new Error(txt)
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
|
|
||||||
return txt
|
|
||||||
}
|
|
||||||
|
|
||||||
async function InvokeOk(path: string, method: HTMLMethod, body?: any): Promise<boolean> {
|
|
||||||
|
|
||||||
//@ts-ignore
|
|
||||||
let res = await Invoke(path, method, body)
|
|
||||||
|
|
||||||
let txt = await res.text()
|
|
||||||
if (res.status >= 400) {
|
|
||||||
console.error("API Error:" + res.status + "\n" + txt)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
`, api.BasePath))
|
|
||||||
b.WriteString("//#endregion\n\n")
|
|
||||||
b.WriteString("//#region Types\n")
|
|
||||||
for k, v := range api.Types {
|
|
||||||
if v.Desc != "" {
|
|
||||||
b.WriteString(fmt.Sprintf("/**\n%s*/\n", v.Desc))
|
|
||||||
}
|
|
||||||
|
|
||||||
b.WriteString(fmt.Sprintf("export interface %s {\n", k))
|
|
||||||
|
|
||||||
for kf, f := range v.Fields {
|
|
||||||
ftype, ok := tstypemapper[f.Type]
|
|
||||||
if !ok {
|
|
||||||
ftype = f.Type
|
|
||||||
}
|
|
||||||
if f.Array {
|
|
||||||
ftype = ftype + "[]"
|
|
||||||
} else if f.Map {
|
|
||||||
fm, ok := tstypemapper[f.Mapkey]
|
|
||||||
if !ok {
|
|
||||||
fm = f.Mapkey
|
|
||||||
}
|
|
||||||
fv, ok := tstypemapper[f.Mapval]
|
|
||||||
if !ok {
|
|
||||||
fv = f.Mapval
|
|
||||||
}
|
|
||||||
ftype = "{[s:" + fm + "]:" + fv + "}"
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.Desc != "" {
|
|
||||||
b.WriteString(fmt.Sprintf("\t/**\n%s*/\n", f.Desc))
|
|
||||||
}
|
|
||||||
b.WriteString(fmt.Sprintf("\t%s:%s\n", strings.ToLower(kf), ftype))
|
|
||||||
}
|
|
||||||
|
|
||||||
b.WriteString(fmt.Sprintf("}\n\n"))
|
|
||||||
}
|
|
||||||
b.WriteString("//#endregion\n\n")
|
|
||||||
b.WriteString("//#region Methods\n")
|
|
||||||
for k, m := range api.Methods {
|
|
||||||
if m.Desc != "" {
|
|
||||||
b.WriteString(fmt.Sprintf("/**\n%s*/\n", m.Desc))
|
|
||||||
}
|
|
||||||
//if m.Raw {
|
|
||||||
// {
|
|
||||||
// b.WriteString(fmt.Sprintf("export async function API_%s(req:any):Promise<any>{\n", k, m.ReqType))
|
|
||||||
// b.WriteString(fmt.Sprintf("\treturn InvokeJSON(\"%s\",\"%s\",req)\n", m.Path, m.Verb))
|
|
||||||
// b.WriteString(fmt.Sprintf("}\n\n"))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//} else {
|
|
||||||
b.WriteString(fmt.Sprintf("export async function %s(req:%s):Promise<%s>{\n", k, m.ReqType.Typename, m.ResType.Typename))
|
|
||||||
b.WriteString(fmt.Sprintf("\treturn InvokeJSON(\"%s\",\"%s\",req)\n", m.Path, m.Verb))
|
|
||||||
b.WriteString(fmt.Sprintf("}\n\n"))
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
|
||||||
b.WriteString("//#endregion\n")
|
|
||||||
|
|
||||||
err := ioutil.WriteFile(f, b.Bytes(), 0600)
|
|
||||||
dc.Err(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
//func processHTTPTestOutput(f string, api *API) {
|
//func processHTTPTestOutput(f string, api *API) {
|
||||||
//
|
//
|
||||||
// for k, m := range api.Methods {
|
// for k, m := range api.Methods {
|
||||||
|
@ -464,6 +190,7 @@ func process(api *API) {
|
||||||
mapHttp(api)
|
mapHttp(api)
|
||||||
processGoServerOutput(api)
|
processGoServerOutput(api)
|
||||||
processTSClientOutput("", api)
|
processTSClientOutput("", api)
|
||||||
|
processGoClientOutput(api)
|
||||||
}
|
}
|
||||||
|
|
||||||
func load() {
|
func load() {
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"dc"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func processGoClientOutput(api *API) {
|
||||||
|
b := bytes.Buffer{}
|
||||||
|
f := config.Goclifname
|
||||||
|
fparts := strings.Split(f, "/")
|
||||||
|
pkg := fparts[len(fparts)-2]
|
||||||
|
|
||||||
|
b.WriteString(fmt.Sprintf(`package %s
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Basepath string = ""
|
||||||
|
var Host string = ""
|
||||||
|
var ExtraHeaders map[string]string = make(map[string]string)
|
||||||
|
|
||||||
|
func invoke(m string, path string, bodyo interface{}) (*json.Decoder, error) {
|
||||||
|
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(b).Encode(bodyo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
body := bytes.NewReader(b.Bytes())
|
||||||
|
|
||||||
|
req, err := http.NewRequest(m, Host+Basepath+path, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-type", "application/json")
|
||||||
|
for k, v := range ExtraHeaders {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
cli := http.Client{}
|
||||||
|
res, err := cli.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret := json.NewDecoder(res.Body)
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Some() (*struct{}, error) {
|
||||||
|
dec, err := invoke("a", "/c/d", struct{}{})
|
||||||
|
ret := &struct{}{}
|
||||||
|
dec.Decode(ret)
|
||||||
|
return ret, err
|
||||||
|
|
||||||
|
}
|
||||||
|
`, pkg))
|
||||||
|
|
||||||
|
for k, v := range api.Types {
|
||||||
|
|
||||||
|
b.WriteString(fmt.Sprintf("type %s struct {\n", k))
|
||||||
|
|
||||||
|
for kf, f := range v.Fields {
|
||||||
|
|
||||||
|
ftype := f.Type
|
||||||
|
|
||||||
|
if f.Array {
|
||||||
|
ftype = "[]" + ftype
|
||||||
|
} else if f.Map {
|
||||||
|
fm := f.Mapkey
|
||||||
|
fv := f.Mapval
|
||||||
|
ftype = "map[" + fm + "]" + fv
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteString(fmt.Sprintf("\t%s %s `json:\"%s\"` \n", strings.ToUpper(kf[:1])+strings.ToLower(kf[1:]), ftype, strings.ToLower(kf)))
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteString(fmt.Sprintf("}\n\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, m := range api.Methods {
|
||||||
|
|
||||||
|
b.WriteString(fmt.Sprintf("func %s(req *%s) (res *%s, err error){\n", k, m.ReqType.Typename, m.ResType.Typename))
|
||||||
|
b.WriteString(fmt.Sprintf(` dec, err := invoke("%s", "%s", req)
|
||||||
|
ret := &%s{}
|
||||||
|
err = dec.Decode(ret)
|
||||||
|
if err != nil{
|
||||||
|
return nil,err
|
||||||
|
}
|
||||||
|
return ret, err
|
||||||
|
}`, m.Verb, m.Path, m.ResType.Typename))
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
err := ioutil.WriteFile(f, b.Bytes(), 0600)
|
||||||
|
dc.Err(err)
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"dc"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func processGoServerOutput(api *API) {
|
||||||
|
|
||||||
|
APIParamTypeToString := func(t *APIParamType) string {
|
||||||
|
ret := ""
|
||||||
|
if t.Ispointer {
|
||||||
|
ret = ret + "&"
|
||||||
|
}
|
||||||
|
ret = ret + t.Typename
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
b := bytes.Buffer{}
|
||||||
|
|
||||||
|
f := config.Gofname
|
||||||
|
|
||||||
|
os.Remove(f)
|
||||||
|
b.WriteString(fmt.Sprintf(`package %s
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
`, packageName))
|
||||||
|
|
||||||
|
b.WriteString(`
|
||||||
|
|
||||||
|
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]]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func Init() API{
|
||||||
|
mux := &http.ServeMux{}
|
||||||
|
|
||||||
|
ret := API{
|
||||||
|
Mux: mux,
|
||||||
|
Perms: make(map[string]string),
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
for _, m := range api.Methods {
|
||||||
|
if m.Perm != "" {
|
||||||
|
b.WriteString(fmt.Sprintf(`
|
||||||
|
ret.Perms["%s_%s"]="%s"
|
||||||
|
`, m.Verb, m.Path, m.Perm))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteString("\n\n")
|
||||||
|
|
||||||
|
for p, mv := range httpMapper {
|
||||||
|
|
||||||
|
b.WriteString(fmt.Sprintf(" mux.HandleFunc(\"%s\",func(w http.ResponseWriter, r *http.Request) {\n", strings.Replace(p, "//", "/", -1)))
|
||||||
|
b.WriteString(" switch r.Method{\n")
|
||||||
|
|
||||||
|
for v, id := range mv {
|
||||||
|
|
||||||
|
b.WriteString(fmt.Sprintf(" case \"%s\":", v))
|
||||||
|
if api.Methods[id].Raw {
|
||||||
|
b.WriteString(fmt.Sprintf(" %s(w , r)\n", id))
|
||||||
|
} else {
|
||||||
|
b.WriteString(fmt.Sprintf(" h_%s(w , r)\n", id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.WriteString(" default:")
|
||||||
|
b.WriteString(" http.Error(w,\"Method not allowed\",500)")
|
||||||
|
|
||||||
|
b.WriteString(" }\n")
|
||||||
|
b.WriteString("})\n")
|
||||||
|
}
|
||||||
|
b.WriteString("return ret\n }\n")
|
||||||
|
|
||||||
|
for k, m := range api.Methods {
|
||||||
|
if !m.Raw {
|
||||||
|
b.WriteString(fmt.Sprintf("\n func h_%s(w http.ResponseWriter, r *http.Request) {\n", k))
|
||||||
|
|
||||||
|
b.WriteString(fmt.Sprintf(
|
||||||
|
`
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = context.WithValue(r.Context(), "REQ", r)
|
||||||
|
ctx = context.WithValue(ctx, "RES", w)
|
||||||
|
req := %s{}
|
||||||
|
if r.Method!=http.MethodGet && r.Method!=http.MethodHead {
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := %s(ctx,req)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`, APIParamTypeToString(m.ReqType), k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := ioutil.WriteFile(f, b.Bytes(), 0600)
|
||||||
|
dc.Err(err)
|
||||||
|
cmd := exec.Command("/bin/sh", "-c", "go fmt "+f)
|
||||||
|
bs, err := cmd.Output()
|
||||||
|
//dc.Err(err)
|
||||||
|
dc.Log(string(bs))
|
||||||
|
}
|
|
@ -0,0 +1,158 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"dc"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func processTSClientOutput(f string, api *API) {
|
||||||
|
b := bytes.Buffer{}
|
||||||
|
if f == "" {
|
||||||
|
f = config.Tsfname
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteString("//#region Base\n")
|
||||||
|
b.WriteString(fmt.Sprintf(`
|
||||||
|
|
||||||
|
var apibase="%s";
|
||||||
|
|
||||||
|
export function SetAPIBase(s:string){
|
||||||
|
apibase=s;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GetAPIBase(): string{
|
||||||
|
return apibase;
|
||||||
|
}
|
||||||
|
|
||||||
|
let REGEX_DATE = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)(Z|([+\-])(\d{2}):(\d{2}))$/
|
||||||
|
|
||||||
|
type HTMLMethod = "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "TRACE"
|
||||||
|
|
||||||
|
async function Invoke(path: string, method: HTMLMethod, body?: any): Promise<Response> {
|
||||||
|
let jbody = undefined
|
||||||
|
let init = {method: method, mode: "cors", credentials: "include", withCredentials: true}
|
||||||
|
if (!!body) {
|
||||||
|
let jbody = JSON.stringify(body)
|
||||||
|
//@ts-ignore
|
||||||
|
init.body = jbody
|
||||||
|
}
|
||||||
|
if (apibase.endsWith("/") && path.startsWith("/")) {
|
||||||
|
path = path.substr(1, path.length)
|
||||||
|
}
|
||||||
|
let fpath = (apibase + path)
|
||||||
|
//@ts-ignore
|
||||||
|
let res = await fetch(fpath, init)
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
async function InvokeJSON(path: string, method: HTMLMethod, body?: any): Promise<any> {
|
||||||
|
|
||||||
|
let txt = await InvokeTxt(path, method, body)
|
||||||
|
if (txt == "") {
|
||||||
|
txt = "{}"
|
||||||
|
}
|
||||||
|
let ret = JSON.parse(txt, (k: string, v: string) => {
|
||||||
|
if (REGEX_DATE.exec(v)) {
|
||||||
|
return new Date(v)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
})
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
async function InvokeTxt(path: string, method: HTMLMethod, body?: any): Promise<string> {
|
||||||
|
//@ts-ignore
|
||||||
|
let res = await Invoke(path, method, body)
|
||||||
|
|
||||||
|
let txt = await res.text()
|
||||||
|
|
||||||
|
if (res.status < 200 || res.status >= 400) {
|
||||||
|
// webix.alert("API Error:" + res.status + "\n" + txt)
|
||||||
|
console.error("API Error:" + res.status + "\n" + txt)
|
||||||
|
let e = new Error(txt)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
return txt
|
||||||
|
}
|
||||||
|
|
||||||
|
async function InvokeOk(path: string, method: HTMLMethod, body?: any): Promise<boolean> {
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
let res = await Invoke(path, method, body)
|
||||||
|
|
||||||
|
let txt = await res.text()
|
||||||
|
if (res.status >= 400) {
|
||||||
|
console.error("API Error:" + res.status + "\n" + txt)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
`, api.BasePath))
|
||||||
|
b.WriteString("//#endregion\n\n")
|
||||||
|
b.WriteString("//#region Types\n")
|
||||||
|
for k, v := range api.Types {
|
||||||
|
if v.Desc != "" {
|
||||||
|
b.WriteString(fmt.Sprintf("/**\n%s*/\n", v.Desc))
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteString(fmt.Sprintf("export interface %s {\n", k))
|
||||||
|
|
||||||
|
for kf, f := range v.Fields {
|
||||||
|
ftype, ok := tstypemapper[f.Type]
|
||||||
|
if !ok {
|
||||||
|
ftype = f.Type
|
||||||
|
}
|
||||||
|
if f.Array {
|
||||||
|
ftype = ftype + "[]"
|
||||||
|
} else if f.Map {
|
||||||
|
fm, ok := tstypemapper[f.Mapkey]
|
||||||
|
if !ok {
|
||||||
|
fm = f.Mapkey
|
||||||
|
}
|
||||||
|
fv, ok := tstypemapper[f.Mapval]
|
||||||
|
if !ok {
|
||||||
|
fv = f.Mapval
|
||||||
|
}
|
||||||
|
ftype = "{[s:" + fm + "]:" + fv + "}"
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.Desc != "" {
|
||||||
|
b.WriteString(fmt.Sprintf("\t/**\n%s*/\n", f.Desc))
|
||||||
|
}
|
||||||
|
b.WriteString(fmt.Sprintf("\t%s:%s\n", strings.ToLower(kf), ftype))
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteString(fmt.Sprintf("}\n\n"))
|
||||||
|
}
|
||||||
|
b.WriteString("//#endregion\n\n")
|
||||||
|
b.WriteString("//#region Methods\n")
|
||||||
|
for k, m := range api.Methods {
|
||||||
|
if m.Desc != "" {
|
||||||
|
b.WriteString(fmt.Sprintf("/**\n%s*/\n", m.Desc))
|
||||||
|
}
|
||||||
|
//if m.Raw {
|
||||||
|
// {
|
||||||
|
// b.WriteString(fmt.Sprintf("export async function API_%s(req:any):Promise<any>{\n", k, m.ReqType))
|
||||||
|
// b.WriteString(fmt.Sprintf("\treturn InvokeJSON(\"%s\",\"%s\",req)\n", m.Path, m.Verb))
|
||||||
|
// b.WriteString(fmt.Sprintf("}\n\n"))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//} else {
|
||||||
|
b.WriteString(fmt.Sprintf("export async function %s(req:%s):Promise<%s>{\n", k, m.ReqType.Typename, m.ResType.Typename))
|
||||||
|
b.WriteString(fmt.Sprintf("\treturn InvokeJSON(\"%s\",\"%s\",req)\n", m.Path, m.Verb))
|
||||||
|
b.WriteString(fmt.Sprintf("}\n\n"))
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
|
b.WriteString("//#endregion\n")
|
||||||
|
|
||||||
|
err := ioutil.WriteFile(f, b.Bytes(), 0600)
|
||||||
|
dc.Err(err)
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ func Init() API {
|
||||||
Perms: make(map[string]string),
|
Perms: make(map[string]string),
|
||||||
}
|
}
|
||||||
|
|
||||||
mux.HandleFunc("", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/someapi", func(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case "POST":
|
case "POST":
|
||||||
h_SomeAPI(w, r)
|
h_SomeAPI(w, r)
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
/*@API*/
|
/*@API*/
|
||||||
type ARequestStruct struct {
|
type ARequestStruct struct {
|
||||||
A *string
|
A *string `json:"a"`
|
||||||
B int64
|
B int64
|
||||||
C time.Time
|
C time.Time
|
||||||
D *string
|
D *string
|
||||||
|
@ -23,7 +23,7 @@ type AResponseStruct struct {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@API
|
@API
|
||||||
PATH: /someapi
|
@PATH: /someapi
|
||||||
*/
|
*/
|
||||||
func SomeAPI(ctx context.Context, a *ARequestStruct) (*AResponseStruct, error) {
|
func SomeAPI(ctx context.Context, a *ARequestStruct) (*AResponseStruct, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
package gocli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Basepath string = ""
|
||||||
|
var Host string = ""
|
||||||
|
var ExtraHeaders map[string]string = make(map[string]string)
|
||||||
|
|
||||||
|
func invoke(m string, path string, bodyo interface{}) (*json.Decoder, error) {
|
||||||
|
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
err := json.NewEncoder(b).Encode(bodyo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
body := bytes.NewReader(b.Bytes())
|
||||||
|
|
||||||
|
req, err := http.NewRequest(m, Host+Basepath+path, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-type", "application/json")
|
||||||
|
for k, v := range ExtraHeaders {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
cli := http.Client{}
|
||||||
|
res, err := cli.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret := json.NewDecoder(res.Body)
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Some() (*struct{}, error) {
|
||||||
|
dec, err := invoke("a", "/c/d", struct{}{})
|
||||||
|
ret := &struct{}{}
|
||||||
|
dec.Decode(ret)
|
||||||
|
return ret, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type ARequestStruct struct {
|
||||||
|
A string `json:"a"`
|
||||||
|
B int64 `json:"b"`
|
||||||
|
C time.Time `json:"c"`
|
||||||
|
D string `json:"d"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AResponseStruct struct {
|
||||||
|
A string `json:"a"`
|
||||||
|
B int64 `json:"b"`
|
||||||
|
C time.Time `json:"c"`
|
||||||
|
D string `json:"d"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func SomeAPI(req *ARequestStruct) (res *AResponseStruct, err error) {
|
||||||
|
dec, err := invoke("POST", "/someapi", req)
|
||||||
|
ret := &AResponseStruct{}
|
||||||
|
err = dec.Decode(ret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ret, err
|
||||||
|
}
|
|
@ -82,10 +82,10 @@ async function InvokeOk(path: string, method: HTMLMethod, body?: any): Promise<b
|
||||||
|
|
||||||
//#region Types
|
//#region Types
|
||||||
export interface ARequestStruct {
|
export interface ARequestStruct {
|
||||||
c:Date
|
|
||||||
d:string
|
|
||||||
a:string
|
a:string
|
||||||
b:number
|
b:number
|
||||||
|
c:Date
|
||||||
|
d:string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AResponseStruct {
|
export interface AResponseStruct {
|
||||||
|
@ -101,7 +101,7 @@ export interface AResponseStruct {
|
||||||
/**
|
/**
|
||||||
SomeAPI*/
|
SomeAPI*/
|
||||||
export async function SomeAPI(req:ARequestStruct):Promise<AResponseStruct>{
|
export async function SomeAPI(req:ARequestStruct):Promise<AResponseStruct>{
|
||||||
return InvokeJSON("","POST",req)
|
return InvokeJSON("/someapi","POST",req)
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
Loading…
Reference in New Issue