package gotsrpc import ( "fmt" "strings" ) func (v *Value) isHTTPResponseWriter() bool { return v.StructType != nil && v.StructType.Name == "ResponseWriter" && v.StructType.Package == "http" } func (v *Value) isHTTPRequest() bool { return v.IsPtr && v.StructType != nil && v.StructType.Name == "Request" && v.StructType.Package == "http" } 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 allowOrigin []string service *` + service.Name + ` } func New` + proxyName + `(service *` + service.Name + `, endpoint string, allowOrigin []string) *` + proxyName + ` { return &` + proxyName + `{ EndPoint: endpoint, allowOrigin : allowOrigin, service: service, } } // ServeHTTP exposes your service func (p *` + proxyName + `) ServeHTTP(w http.ResponseWriter, r *http.Request) { for _, origin := range p.allowOrigin { w.Header().Add("Access-Control-Allow-Origin", origin) } 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{} isSessionRequest := false if len(method.Args) > 0 { args := []string{} for argI, arg := range method.Args { if argI == 0 && arg.Value.isHTTPResponseWriter() { trace("skipping first arg is a http.ResponseWriter") continue } if argI == 1 && arg.Value.isHTTPRequest() { trace("skipping second arg is a *http.Request") isSessionRequest = true continue } 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, ", ") + " := ") } if isSessionRequest { callArgs = append([]string{"w", "r"}, callArgs...) } 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 }