mirror of
https://github.com/foomo/gotsrpc.git
synced 2025-10-16 12:35:35 +00:00
further developing program, completing layout
This commit is contained in:
parent
6e5aa7a265
commit
fd22d49b56
87
cmd/gotsrpc/gotsrpc.go
Normal file
87
cmd/gotsrpc/gotsrpc.go
Normal file
@ -0,0 +1,87 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/foomo/gotsrpc"
|
||||
)
|
||||
|
||||
func jsonDump(v interface{}) {
|
||||
jsonBytes, err := json.MarshalIndent(v, "", " ")
|
||||
fmt.Println(err, string(jsonBytes))
|
||||
}
|
||||
func usage() {
|
||||
fmt.Println("Usage")
|
||||
fmt.Println(os.Args[0], " --ts-module MyTS.Module.Name my.server/my/package ServiceA [ ServiceB, ... ]")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
func main() {
|
||||
flagTsModule := flag.String("ts-module", "", "TypeScript target module")
|
||||
|
||||
flag.Parse()
|
||||
if len(*flagTsModule) == 0 {
|
||||
fmt.Println("missing ts module")
|
||||
}
|
||||
|
||||
args := flag.Args()
|
||||
if len(args) < 2 {
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
gotsrpc.ReaderTrace = true
|
||||
goPath := os.Getenv("GOPATH")
|
||||
|
||||
if len(goPath) == 0 {
|
||||
fmt.Println("GOPATH not set")
|
||||
os.Exit(1)
|
||||
}
|
||||
longPackageName := args[0]
|
||||
longPackageNameParts := strings.Split(longPackageName, "/")
|
||||
goFilename := path.Join(goPath, "src", longPackageName, "gotsrpc.go")
|
||||
|
||||
packageName := longPackageNameParts[len(longPackageNameParts)-1]
|
||||
services, structs, err := gotsrpc.Read(goPath, longPackageName, args[1:])
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("an error occured", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
jsonDump(services)
|
||||
jsonDump(structs)
|
||||
|
||||
ts, err := gotsrpc.RenderTypeScript(services, structs, *flagTsModule)
|
||||
if err != nil {
|
||||
fmt.Println("could not generate ts code", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
fmt.Println(ts)
|
||||
|
||||
gocode, goerr := gotsrpc.RenderGo(services, packageName)
|
||||
if goerr != nil {
|
||||
fmt.Println("could not generate go code", goerr)
|
||||
os.Exit(4)
|
||||
}
|
||||
|
||||
formattedGoBytes, formattingError := format.Source([]byte(gocode))
|
||||
if formattingError == nil {
|
||||
gocode = string(formattedGoBytes)
|
||||
} else {
|
||||
fmt.Println("could not format go code", formattingError)
|
||||
}
|
||||
|
||||
writeErr := ioutil.WriteFile(goFilename, []byte(gocode), 0644)
|
||||
if writeErr != nil {
|
||||
fmt.Println("could not write go source to file", writeErr)
|
||||
os.Exit(5)
|
||||
|
||||
}
|
||||
fmt.Println(goFilename, gocode)
|
||||
//gotsrpc.ReadFile("/Users/jan/go/src/github.com/foomo/gotsrpc/demo/demo.go", []string{"Service"})
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/foomo/gotsrpc"
|
||||
)
|
||||
|
||||
func jsonDump(v interface{}) {
|
||||
jsonBytes, err := json.MarshalIndent(v, "", " ")
|
||||
fmt.Println(err, string(jsonBytes))
|
||||
}
|
||||
func main() {
|
||||
//fmt.Println("hello", os.Args[1])
|
||||
gotsrpc.ReaderTrace = true
|
||||
//gotsrpc.Read(os.Args[1], os.Args[2:])
|
||||
//gotsrpc.ReadFile("/Users/jan/go/src/github.com/foomo/gotsrpc/demo/demo.go", []string{"Service"})
|
||||
goPath := os.Getenv("GOPATH")
|
||||
|
||||
if len(goPath) == 0 {
|
||||
fmt.Println("GOPATH not set")
|
||||
os.Exit(1)
|
||||
}
|
||||
jsonDump(os.Args[2:])
|
||||
services, err := gotsrpc.ReadServicesInPackage(goPath, os.Args[1], os.Args[2:])
|
||||
if err != nil {
|
||||
fmt.Println("an error occured", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
jsonDump(services)
|
||||
|
||||
//gotsrpc.ReadFile("/Users/jan/go/src/github.com/foomo/gotsrpc/demo/demo.go", []string{"Service"})
|
||||
}
|
||||
41
code.go
Normal file
41
code.go
Normal file
@ -0,0 +1,41 @@
|
||||
package gotsrpc
|
||||
|
||||
import "strings"
|
||||
|
||||
type code struct {
|
||||
line string
|
||||
lines []string
|
||||
indent int
|
||||
}
|
||||
|
||||
func newCode() *code {
|
||||
return &code{
|
||||
line: "",
|
||||
lines: []string{},
|
||||
indent: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *code) ind(inc int) *code {
|
||||
c.indent += inc
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *code) nl() *code {
|
||||
c.lines = append(c.lines, strings.Repeat(" ", c.indent)+c.line)
|
||||
c.line = ""
|
||||
return c
|
||||
}
|
||||
func (c *code) l(line string) *code {
|
||||
c.app(line).nl()
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *code) app(str string) *code {
|
||||
c.line += str
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *code) string() string {
|
||||
return strings.Join(c.lines, "\n")
|
||||
}
|
||||
@ -3,8 +3,9 @@ package demo
|
||||
import nstd "github.com/foomo/gotsrpc/demo/nested"
|
||||
|
||||
type Address struct {
|
||||
City string `json:"city,omitempty"`
|
||||
SecretServerCrap bool `json:"-"`
|
||||
City string `json:"city,omitempty"`
|
||||
Signs []string `json:"signs,omitempty"`
|
||||
SecretServerCrap bool `json:"-"`
|
||||
PeoplePtr []*Person
|
||||
ArrayOfMaps []map[string]bool
|
||||
ArrayArrayAddress [][]*Address
|
||||
|
||||
@ -18,3 +18,7 @@ func (s *Service) Hello(name string) (reply string, err *Err) {
|
||||
func Sepp(bar bool) string {
|
||||
return "ich bin der sepp"
|
||||
}
|
||||
|
||||
func (s *Service) NothingInNothinOut() {
|
||||
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
// this file was auto generated by gotsrpc https://github.com/foomo/gotsrpc
|
||||
package demo
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/foomo/gotsrpc"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ServiceGoTSRPCProxy struct {
|
||||
@ -18,23 +18,37 @@ func NewServiceGoTSRPCProxy(service *Service, endpoint string) *ServiceGoTSRPCPr
|
||||
}
|
||||
}
|
||||
|
||||
func (sp *ServiceGoTSRPCProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// ServeHTTP exposes your service
|
||||
func (p *ServiceGoTSRPCProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
gotsrpc.ErrorMethodNotAllowed(w)
|
||||
return
|
||||
}
|
||||
switch gotsrpc.GetCalledFunc(r, sp.EndPoint) {
|
||||
case "Hello":
|
||||
args := []interface{}{""}
|
||||
var args []interface{}
|
||||
switch gotsrpc.GetCalledFunc(r, p.EndPoint) {
|
||||
case "ExtractAddress":
|
||||
args = []interface{}{&Person{}}
|
||||
err := gotsrpc.LoadArgs(args, r)
|
||||
if err != nil {
|
||||
gotsrpc.ErrorCouldNotLoadArgs(w)
|
||||
return
|
||||
}
|
||||
helloReply, helloErr := sp.service.Hello(args[0].(string))
|
||||
extractAddressRet, extractAddressRet_1 := p.service.ExtractAddress(args[0].(*Person))
|
||||
gotsrpc.Reply([]interface{}{extractAddressRet, extractAddressRet_1}, w)
|
||||
return
|
||||
case "Hello":
|
||||
args = []interface{}{""}
|
||||
err := gotsrpc.LoadArgs(args, r)
|
||||
if err != nil {
|
||||
gotsrpc.ErrorCouldNotLoadArgs(w)
|
||||
return
|
||||
}
|
||||
helloReply, helloErr := p.service.Hello(args[0].(string))
|
||||
gotsrpc.Reply([]interface{}{helloReply, helloErr}, w)
|
||||
return
|
||||
default:
|
||||
gotsrpc.ErrorFuncNotFound(w)
|
||||
case "NothingInNothinOut":
|
||||
p.service.NothingInNothinOut()
|
||||
gotsrpc.Reply([]interface{}{}, w)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
40
demo/gotsrpc_test.go
Normal file
40
demo/gotsrpc_test.go
Normal file
@ -0,0 +1,40 @@
|
||||
package demo_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/foomo/gotsrpc"
|
||||
)
|
||||
|
||||
type ServiceGoTSRPCProxy struct {
|
||||
EndPoint string
|
||||
service *Service
|
||||
}
|
||||
|
||||
func NewServiceGoTSRPCProxy(service *Service, endpoint string) *ServiceGoTSRPCProxy {
|
||||
return &ServiceGoTSRPCProxy{
|
||||
EndPoint: endpoint,
|
||||
service: service,
|
||||
}
|
||||
}
|
||||
|
||||
func (sp *ServiceGoTSRPCProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
gotsrpc.ErrorMethodNotAllowed(w)
|
||||
return
|
||||
}
|
||||
switch gotsrpc.GetCalledFunc(r, sp.EndPoint) {
|
||||
case "Hello":
|
||||
args := []interface{}{""}
|
||||
err := gotsrpc.LoadArgs(args, r)
|
||||
if err != nil {
|
||||
gotsrpc.ErrorCouldNotLoadArgs(w)
|
||||
return
|
||||
}
|
||||
helloReply, helloErr := sp.service.Hello(args[0].(string))
|
||||
gotsrpc.Reply([]interface{}{helloReply, helloErr}, w)
|
||||
return
|
||||
default:
|
||||
gotsrpc.ErrorFuncNotFound(w)
|
||||
}
|
||||
}
|
||||
20
demo/maps.js
Normal file
20
demo/maps.js
Normal file
@ -0,0 +1,20 @@
|
||||
var foo = {
|
||||
people: {
|
||||
bla: {
|
||||
audi: {
|
||||
color: "white",
|
||||
wheels: 1
|
||||
}
|
||||
}
|
||||
},
|
||||
cars: {
|
||||
audi: {
|
||||
color: "white",
|
||||
wheels: 1
|
||||
},
|
||||
blas: {
|
||||
color: "red",
|
||||
wheels: 23.1
|
||||
}
|
||||
}
|
||||
};
|
||||
38
demo/maps.ts
Normal file
38
demo/maps.ts
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
|
||||
interface CarMap {
|
||||
[index:string]:Car;
|
||||
}
|
||||
|
||||
interface Car {
|
||||
color:string;
|
||||
wheels:number;
|
||||
}
|
||||
|
||||
interface Complex {
|
||||
cars:CarMap;
|
||||
people:{[index:string]:{
|
||||
[index:string]:Car
|
||||
}};
|
||||
}
|
||||
|
||||
var foo : Complex = {
|
||||
people: {
|
||||
bla:{
|
||||
audi: {
|
||||
color: "white",
|
||||
wheels:1
|
||||
}
|
||||
}
|
||||
},
|
||||
cars: {
|
||||
audi: {
|
||||
color: "white",
|
||||
wheels:1
|
||||
},
|
||||
blas: {
|
||||
color:"red",
|
||||
wheels:23.1
|
||||
}
|
||||
}
|
||||
}
|
||||
168
go.go
Normal file
168
go.go
Normal file
@ -0,0 +1,168 @@
|
||||
package gotsrpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (v *Value) goType() (t string) {
|
||||
if v.IsPtr {
|
||||
t = "*"
|
||||
}
|
||||
switch true {
|
||||
case v.Array != nil:
|
||||
t += "[]" + v.Array.Value.goType()
|
||||
case len(v.GoScalarType) > 0:
|
||||
t += v.GoScalarType
|
||||
case v.StructType != nil:
|
||||
t += v.StructType.Name
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (v *Value) emptyLiteral() (e string) {
|
||||
e = ""
|
||||
if v.IsPtr {
|
||||
e += "&"
|
||||
}
|
||||
switch true {
|
||||
case len(v.GoScalarType) > 0:
|
||||
switch v.GoScalarType {
|
||||
case "string":
|
||||
e += "\"\""
|
||||
case "float":
|
||||
return "float(0.0)"
|
||||
case "float32":
|
||||
return "float32(0.0)"
|
||||
case "float64":
|
||||
return "float64(0.0)"
|
||||
case "int":
|
||||
return "int(0)"
|
||||
case "int32":
|
||||
return "int32(0)"
|
||||
case "int64":
|
||||
return "int64(0)"
|
||||
case "bool":
|
||||
return "false"
|
||||
}
|
||||
case v.Array != nil:
|
||||
e += "[]" + v.Array.Value.emptyLiteral() + "{}"
|
||||
case v.StructType != nil:
|
||||
e += v.StructType.Name + "{}"
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func lcfirst(str string) string {
|
||||
return strfirst(str, strings.ToLower)
|
||||
}
|
||||
|
||||
func ucfirst(str string) string {
|
||||
return strfirst(str, strings.ToUpper)
|
||||
}
|
||||
|
||||
func strfirst(str string, strfunc func(string) string) string {
|
||||
if len(str) == 0 {
|
||||
return ""
|
||||
} else if len(str) == 1 {
|
||||
return strfunc(str)
|
||||
}
|
||||
return strfunc(str[0:1]) + str[1:]
|
||||
|
||||
}
|
||||
|
||||
func renderServiceProxies(services []*Service, packageName string, g *code) error {
|
||||
|
||||
g.l(`
|
||||
// this file was auto generated by gotsrpc https://github.com/foomo/gotsrpc
|
||||
package ` + packageName + `
|
||||
import (
|
||||
"net/http"
|
||||
"github.com/foomo/gotsrpc"
|
||||
)
|
||||
`)
|
||||
for _, service := range services {
|
||||
proxyName := service.Name + "GoTSRPCProxy"
|
||||
g.l(`
|
||||
type ` + proxyName + ` struct {
|
||||
EndPoint string
|
||||
service *` + service.Name + `
|
||||
}
|
||||
|
||||
func New` + proxyName + `(service *` + service.Name + `, endpoint string) *` + proxyName + ` {
|
||||
return &` + proxyName + `{
|
||||
EndPoint: endpoint,
|
||||
service: service,
|
||||
}
|
||||
}
|
||||
|
||||
// ServeHTTP exposes your service
|
||||
func (p *` + proxyName + `) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
gotsrpc.ErrorMethodNotAllowed(w)
|
||||
return
|
||||
}
|
||||
var args []interface{}
|
||||
switch gotsrpc.GetCalledFunc(r, p.EndPoint) {`)
|
||||
|
||||
// indenting into switch cases
|
||||
g.ind(4)
|
||||
|
||||
for _, method := range service.Methods {
|
||||
// a case for each method
|
||||
g.l("case \"" + method.Name + "\":")
|
||||
g.ind(1)
|
||||
callArgs := []string{}
|
||||
if len(method.Args) > 0 {
|
||||
args := []string{}
|
||||
for argI, arg := range method.Args {
|
||||
args = append(args, arg.Value.emptyLiteral())
|
||||
callArgs = append(callArgs, fmt.Sprint("args[", argI, "].("+arg.Value.goType()+")"))
|
||||
}
|
||||
g.l("args = []interface{}{" + strings.Join(args, ", ") + "}")
|
||||
g.l("err := gotsrpc.LoadArgs(args, r)")
|
||||
g.l("if err != nil {")
|
||||
g.ind(1)
|
||||
g.l("gotsrpc.ErrorCouldNotLoadArgs(w)")
|
||||
g.l("return")
|
||||
g.ind(-1)
|
||||
g.l("}")
|
||||
|
||||
}
|
||||
returnValueNames := []string{}
|
||||
for retI, retField := range method.Return {
|
||||
retArgName := retField.Name
|
||||
if len(retArgName) == 0 {
|
||||
retArgName = "ret"
|
||||
if retI > 0 {
|
||||
retArgName += "_" + fmt.Sprint(retI)
|
||||
}
|
||||
}
|
||||
returnValueNames = append(returnValueNames, lcfirst(method.Name)+ucfirst(retArgName))
|
||||
}
|
||||
if len(returnValueNames) > 0 {
|
||||
g.app(strings.Join(returnValueNames, ", ") + " := ")
|
||||
}
|
||||
g.app("p.service." + method.Name + "(" + strings.Join(callArgs, ", ") + ")")
|
||||
g.nl()
|
||||
g.l("gotsrpc.Reply([]interface{}{" + strings.Join(returnValueNames, ", ") + "}, w)")
|
||||
g.l("return")
|
||||
g.ind(-1)
|
||||
}
|
||||
g.ind(-1).l("}") // close switch
|
||||
g.ind(-1).l("}") // close ServeHttp
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func RenderGo(services []*Service, packageName string) (gocode string, err error) {
|
||||
g := newCode()
|
||||
err = renderServiceProxies(services, packageName, g)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
gocode = g.string()
|
||||
return
|
||||
}
|
||||
15
model.go
15
model.go
@ -22,12 +22,13 @@ type StructType struct {
|
||||
}
|
||||
|
||||
type Value struct {
|
||||
ScalarType ScalarType `json:",omitempty"`
|
||||
StructType *StructType `json:",omitempty"`
|
||||
Struct *Struct `json:",omitempty"`
|
||||
Map *Map `json:",omitempty"`
|
||||
Array *Array `json:",omitempty"`
|
||||
IsPtr bool `json:",omitempty"`
|
||||
ScalarType ScalarType `json:",omitempty"`
|
||||
GoScalarType string `json:",omitempty"`
|
||||
StructType *StructType `json:",omitempty"`
|
||||
Struct *Struct `json:",omitempty"`
|
||||
Map *Map `json:",omitempty"`
|
||||
Array *Array `json:",omitempty"`
|
||||
IsPtr bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
type Array struct {
|
||||
@ -58,5 +59,5 @@ type Method struct {
|
||||
|
||||
type Struct struct {
|
||||
Name string
|
||||
Fields map[string]*Field
|
||||
Fields []*Field
|
||||
}
|
||||
|
||||
@ -7,7 +7,15 @@ import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func readServiceFile(file *ast.File, services map[string]*Service) error {
|
||||
func readServiceFile(file *ast.File, services []*Service) error {
|
||||
findService := func(serviceName string) (service *Service, ok bool) {
|
||||
for _, service := range services {
|
||||
if service.Name == serviceName {
|
||||
return service, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
for _, decl := range file.Decls {
|
||||
if reflect.ValueOf(decl).Type().String() == "*ast.FuncDecl" {
|
||||
funcDecl := decl.(*ast.FuncDecl)
|
||||
@ -21,13 +29,13 @@ func readServiceFile(file *ast.File, services map[string]*Service) error {
|
||||
ident := starExpr.X.(*ast.Ident)
|
||||
fmt.Println(" on sth:", ident.Name)
|
||||
|
||||
service, ok := services[ident.Name]
|
||||
service, ok := findService(ident.Name)
|
||||
|
||||
if ok {
|
||||
service.Methods = append(service.Methods, &Method{
|
||||
Name: funcDecl.Name.Name,
|
||||
Args: readFields(funcDecl.Type.Params.List),
|
||||
Return: readFields(funcDecl.Type.Results.List),
|
||||
Args: readFields(funcDecl.Type.Params),
|
||||
Return: readFields(funcDecl.Type.Results),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -41,9 +49,13 @@ func readServiceFile(file *ast.File, services map[string]*Service) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func readFields(astFields []*ast.Field) (fields []*Field) {
|
||||
func readFields(fieldList *ast.FieldList) (fields []*Field) {
|
||||
fields = []*Field{}
|
||||
for _, param := range astFields {
|
||||
if fieldList == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, param := range fieldList.List {
|
||||
name, value, _ := readField(param)
|
||||
fields = append(fields, &Field{
|
||||
Name: name,
|
||||
@ -54,13 +66,13 @@ func readFields(astFields []*ast.Field) (fields []*Field) {
|
||||
|
||||
}
|
||||
|
||||
func readServicesInPackage(pkg *ast.Package, serviceNames []string) (services map[string]*Service, err error) {
|
||||
services = map[string]*Service{}
|
||||
func readServicesInPackage(pkg *ast.Package, serviceNames []string) (services []*Service, err error) {
|
||||
services = []*Service{}
|
||||
for _, serviceName := range serviceNames {
|
||||
services[serviceName] = &Service{
|
||||
services = append(services, &Service{
|
||||
Name: serviceName,
|
||||
Methods: []*Method{},
|
||||
}
|
||||
})
|
||||
}
|
||||
for _, file := range pkg.Files {
|
||||
err = readServiceFile(file, services)
|
||||
@ -72,7 +84,7 @@ func readServicesInPackage(pkg *ast.Package, serviceNames []string) (services ma
|
||||
return
|
||||
}
|
||||
|
||||
func ReadServicesInPackage(goPath string, packageName string, serviceNames []string) (services map[string]*Service, err error) {
|
||||
func Read(goPath string, packageName string, serviceNames []string) (services []*Service, structs map[string]*Struct, err error) {
|
||||
if len(serviceNames) == 0 {
|
||||
err = errors.New("nothing to do service names are empty")
|
||||
return
|
||||
@ -81,5 +93,10 @@ func ReadServicesInPackage(goPath string, packageName string, serviceNames []str
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return readServicesInPackage(pkg, serviceNames)
|
||||
services, err = readServicesInPackage(pkg, serviceNames)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
structs, err = readStructs(pkg)
|
||||
return
|
||||
}
|
||||
|
||||
@ -9,6 +9,18 @@ import (
|
||||
|
||||
var ReaderTrace = false
|
||||
|
||||
func readStructs(pkg *ast.Package) (structs map[string]*Struct, err error) {
|
||||
structs = map[string]*Struct{}
|
||||
for _, file := range pkg.Files {
|
||||
//readFile(filename, file)
|
||||
err = extractStructs(file, structs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func trace(args ...interface{}) {
|
||||
if ReaderTrace {
|
||||
fmt.Println(args...)
|
||||
@ -58,15 +70,6 @@ func extractJSONInfo(tag string) *JSONInfo {
|
||||
}
|
||||
}
|
||||
|
||||
func ReadStructs(pkg *ast.Package, services []string) error {
|
||||
structs := map[string]*Struct{}
|
||||
for _, file := range pkg.Files {
|
||||
//readFile(filename, file)
|
||||
extractStructs(file, structs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getScalarFromAstIdent(ident *ast.Ident) ScalarType {
|
||||
switch ident.Name {
|
||||
case "string":
|
||||
@ -92,10 +95,13 @@ func getTypesFromAstType(ident *ast.Ident) (structType string, scalarType Scalar
|
||||
func readAstType(v *Value, fieldIdent *ast.Ident) {
|
||||
structType, scalarType := getTypesFromAstType(fieldIdent)
|
||||
v.ScalarType = scalarType
|
||||
|
||||
if len(structType) > 0 {
|
||||
v.StructType = &StructType{
|
||||
Name: structType,
|
||||
}
|
||||
} else {
|
||||
v.GoScalarType = fieldIdent.Name
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,8 +219,8 @@ func readField(astField *ast.Field) (name string, v *Value, jsonInfo *JSONInfo)
|
||||
return
|
||||
}
|
||||
|
||||
func readFieldList(fieldList []*ast.Field) (fields map[string]*Field) {
|
||||
fields = map[string]*Field{}
|
||||
func readFieldList(fieldList []*ast.Field) (fields []*Field) {
|
||||
fields = []*Field{}
|
||||
for _, field := range fieldList {
|
||||
name, value, jsonInfo := readField(field)
|
||||
|
||||
@ -223,17 +229,17 @@ func readFieldList(fieldList []*ast.Field) (fields map[string]*Field) {
|
||||
}
|
||||
|
||||
if value != nil {
|
||||
fields[name] = &Field{
|
||||
fields = append(fields, &Field{
|
||||
Name: name,
|
||||
Value: value,
|
||||
JSONInfo: jsonInfo,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func extractStructs(file *ast.File, structs map[string]*Struct) {
|
||||
func extractStructs(file *ast.File, structs map[string]*Struct) error {
|
||||
for _, imp := range file.Imports {
|
||||
fmt.Println("import", imp.Name, imp.Path)
|
||||
}
|
||||
@ -243,7 +249,7 @@ func extractStructs(file *ast.File, structs map[string]*Struct) {
|
||||
//ast.StructType
|
||||
structs[name] = &Struct{
|
||||
Name: name,
|
||||
Fields: map[string]*Field{},
|
||||
Fields: []*Field{},
|
||||
}
|
||||
if reflect.ValueOf(obj.Decl).Type().String() == "*ast.TypeSpec" {
|
||||
typeSpec := obj.Decl.(*ast.TypeSpec)
|
||||
@ -264,4 +270,5 @@ func extractStructs(file *ast.File, structs map[string]*Struct) {
|
||||
//fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", obj.Kind, obj)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
147
typescript.go
Normal file
147
typescript.go
Normal file
@ -0,0 +1,147 @@
|
||||
package gotsrpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (f *Field) tsName() string {
|
||||
n := f.Name
|
||||
if f.JSONInfo != nil && len(f.JSONInfo.Name) > 0 {
|
||||
n = f.JSONInfo.Name
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (v *Value) tsType() string {
|
||||
switch true {
|
||||
case v.IsPtr:
|
||||
if v.StructType != nil {
|
||||
if len(v.StructType.Package) > 0 {
|
||||
return v.StructType.Package + "." + v.StructType.Name
|
||||
}
|
||||
return v.StructType.Name
|
||||
}
|
||||
return string(v.ScalarType)
|
||||
case v.Array != nil:
|
||||
return v.Array.Value.tsType() + "[]"
|
||||
case len(v.ScalarType) > 0:
|
||||
return string(v.ScalarType)
|
||||
default:
|
||||
return "any"
|
||||
}
|
||||
}
|
||||
|
||||
func renderStruct(str *Struct, ts *code) error {
|
||||
ts.l("export interface " + str.Name + " {").ind(1)
|
||||
for _, f := range str.Fields {
|
||||
ts.app(f.tsName())
|
||||
if f.Value.IsPtr {
|
||||
ts.app("?")
|
||||
}
|
||||
ts.app(":" + f.Value.tsType())
|
||||
ts.app(";")
|
||||
ts.nl()
|
||||
}
|
||||
ts.ind(-1).l("}")
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
export class ServiceClient {
|
||||
static defaultInst = new ServiceClient()
|
||||
constructor(public endPoint:string = "/service") { }
|
||||
hello(name:string, success:(reply:string, err:Err) => void, err:(request:XMLHttpRequest) => void) {
|
||||
GoTSRPC.call(this.endPoint, "Hello", [name], success, err);
|
||||
}
|
||||
}
|
||||
*/
|
||||
func renderService(service *Service, ts *code) error {
|
||||
clientName := service.Name + "Client"
|
||||
ts.l("export class " + clientName + " {").ind(1).
|
||||
l("static defaultInst = new " + clientName + ";").
|
||||
l("constructor(public endPoint:string = \"/service\") { }")
|
||||
for _, method := range service.Methods {
|
||||
|
||||
ts.app(method.Name + "(")
|
||||
// actual args
|
||||
args := []string{}
|
||||
callArgs := []string{}
|
||||
|
||||
for _, arg := range method.Args {
|
||||
args = append(args, arg.tsName()+":"+arg.Value.tsType())
|
||||
callArgs = append(callArgs, arg.Name)
|
||||
}
|
||||
ts.app(strings.Join(args, ", "))
|
||||
// success callback
|
||||
retArgs := []string{}
|
||||
for index, retField := range method.Return {
|
||||
retArgName := retField.tsName()
|
||||
if len(retArgName) == 0 {
|
||||
retArgName = "ret"
|
||||
if index > 0 {
|
||||
retArgName += "_" + fmt.Sprint(index)
|
||||
}
|
||||
}
|
||||
retArgs = append(retArgs, retArgName+":"+retField.Value.tsType())
|
||||
}
|
||||
if len(args) > 0 {
|
||||
ts.app(", ")
|
||||
}
|
||||
ts.app("success(" + strings.Join(retArgs, ", ") + ") => void")
|
||||
ts.app(", err:(request:XMLHttpRequest) => void) {").nl()
|
||||
ts.ind(1)
|
||||
// generic framework call
|
||||
ts.l("GoTSRPC.call(this.endPoint, \"" + method.Name + "\"), [" + strings.Join(callArgs, ", ") + "], success, err);")
|
||||
ts.ind(-1)
|
||||
ts.app("}")
|
||||
ts.nl()
|
||||
}
|
||||
ts.ind(-1)
|
||||
ts.l("}")
|
||||
return nil
|
||||
}
|
||||
|
||||
func RenderTypeScript(services []*Service, structs map[string]*Struct, tsModuleName string) (typeScript string, err error) {
|
||||
ts := newCode()
|
||||
ts.l(`module GoTSRPC {
|
||||
export function call(endPoint:string, method:string, args:any[], success:any, err:any) {
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('POST', endPoint + "/" + encodeURIComponent(method), true);
|
||||
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
|
||||
request.send(JSON.stringify(args));
|
||||
request.onload = function() {
|
||||
if (request.status == 200) {
|
||||
var data = JSON.parse(request.responseText);
|
||||
success.apply(null, data);
|
||||
} else {
|
||||
err(request)
|
||||
}
|
||||
};
|
||||
request.onerror = function() {
|
||||
err(request);
|
||||
};
|
||||
}
|
||||
}`)
|
||||
|
||||
ts.l("module " + tsModuleName + " {")
|
||||
ts.ind(1)
|
||||
|
||||
for _, str := range structs {
|
||||
err = renderStruct(str, ts)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, service := range services {
|
||||
err = renderService(service, ts)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
ts.ind(-1)
|
||||
ts.l("}")
|
||||
typeScript = ts.string()
|
||||
return
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user