Merge pull request #13 from foomo/release/0.12.0

Release/0.12.0
This commit is contained in:
Stefan Martinov 2018-11-26 15:06:53 +01:00 committed by GitHub
commit 4d200100cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 469 additions and 161 deletions

View File

@ -1,11 +1,13 @@
.PHONY: demo
demo:
.PHONY: generate
generate:
rm -vf demo/output/*
rm -vf demo/output-commonjs/*
go run cmd/gotsrpc/gotsrpc.go demo/config.yml
go run cmd/gotsrpc/gotsrpc.go -skipgotsrpc demo/config-commonjs.yml
tsc --outFile cmd/demo/demo.js demo/demo.ts
tsc --outFile cmd/demo/demo.js demo/demo.ts
.PHONY: demo
demo: generate
cd cmd/demo && go run demo.go
.PHONY: install

View File

@ -29,7 +29,7 @@ gotsrpc gotsrpc.yml
Will generate client and server side go and TypeScript code. Have fun!
## config expamples
## config examples
### commonjs

View File

@ -1,50 +1,93 @@
package gotsrpc
import (
"encoding/json"
"bytes"
"fmt"
"github.com/pkg/errors"
"github.com/ugorji/go/codec"
"io"
"io/ioutil"
"net/http"
"strings"
)
// ClientTransport to use for calls
var ClientTransport = &http.Transport{}
// CallClient calls a method on the remove service
func CallClient(url string, endpoint string, method string, args []interface{}, reply []interface{}) error {
// Marshall args
jsonArgs := []string{}
for _, value := range args {
jsonArg, err := json.Marshal(value)
if err != nil {
return err
}
jsonArgs = append(jsonArgs, string(jsonArg))
var _ Client = &bufferedClient{}
type Client interface {
Call(url string, endpoint string, method string, args []interface{}, reply []interface{}) (err error)
}
func NewClient(httpClient *http.Client) Client {
if httpClient == nil {
httpClient = http.DefaultClient
}
return &bufferedClient{client: httpClient}
}
func newRequest(url string, contentType string, reader io.Reader) (r *http.Request, err error) {
request, errRequest := http.NewRequest("POST", url, reader)
if errRequest != nil {
return nil, errors.Wrap(errRequest, "could not create a request")
}
request.Header.Set("Content-Type", contentType)
request.Header.Set("Accept", contentType)
return request, nil
}
type bufferedClient struct {
client *http.Client
}
// CallClient calls a method on the remove service
func (c *bufferedClient) Call(url string, endpoint string, method string, args []interface{}, reply []interface{}) (err error) {
// Marshall args
b := new(bytes.Buffer)
errEncode := codec.NewEncoder(b, msgpackHandle).Encode(args)
if errEncode != nil {
return errors.Wrap(errEncode, "could not encode argument")
}
// Create request
request := "[" + strings.Join(jsonArgs, ",") + "]"
// Create post url
postURL := fmt.Sprintf("%s%s/%s", url, endpoint, method)
// Post
client := &http.Client{Transport: ClientTransport}
resp, err := client.Post(postURL, "application/json", strings.NewReader(request))
if err != nil {
return err
request, errRequest := newRequest(postURL, msgpackContentType, b)
if errRequest != nil {
return errRequest
}
defer resp.Body.Close()
// Read in body
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
resp, errDo := c.client.Do(request)
if errDo != nil {
return errors.Wrap(err, "could not execute request")
}
// Check status
if resp.StatusCode != http.StatusOK {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
return fmt.Errorf("%s: %s", resp.Status, string(body))
}
// Unmarshal reply
if err := json.Unmarshal(body, &reply); err != nil {
return err
var errDecode error
switch resp.Header.Get("Content-Type") {
case msgpackContentType:
errDecode = codec.NewDecoder(resp.Body, msgpackHandle).Decode(reply)
case jsonContentType:
errDecode = codec.NewDecoder(resp.Body, jsonHandle).Decode(reply)
default:
errDecode = codec.NewDecoder(resp.Body, jsonHandle).Decode(reply)
}
return nil
// Unmarshal reply
if errDecode != nil {
return errors.Wrap(errDecode, "could not decode response from client")
}
return err
}

View File

@ -1,6 +1,7 @@
package demo
import nstd "github.com/foomo/gotsrpc/demo/nested"
//go:generate codecgen -o values.generated.go demo_complex.go
type Address struct {
City string `json:"city,omitempty"`
@ -31,7 +32,11 @@ type Person struct {
DNA []byte
}
func (d *Demo) ExtractAddress(person *Person) (addr *Address, e *Err) {
if person == nil {
return nil, nil
}
if person.AddressPtr != nil {
return person.AddressPtr, nil
}
@ -46,7 +51,7 @@ func (d *Demo) MapCrap() (crap map[string][]int) {
return map[string][]int{}
}
func (d *Demo) Nest() *nstd.Nested {
func (d *Demo) Nest() []*nstd.Nested {
return nil
}

View File

@ -1,4 +1,5 @@
// Code generated by gotsrpc https://github.com/foomo/gotsrpc DO NOT EDIT.
// Code generated by gotsrpc https://github.com/foomo/gotsrpc - DO NOT EDIT.
package demo
import (
@ -146,7 +147,7 @@ type (
DemoNestRequest struct {
}
DemoNestResponse struct {
RetNest_0 *nested.Nested
RetNest_0 []*nested.Nested
}
DemoTestScalarInPlaceRequest struct {

View File

@ -1,4 +1,5 @@
// Code generated by gotsrpc https://github.com/foomo/gotsrpc DO NOT EDIT.
// Code generated by gotsrpc https://github.com/foomo/gotsrpc - DO NOT EDIT.
package demo
import (
@ -22,17 +23,17 @@ func NewFooGoRPCClient(addr string, tlsConfig *tls.Config) *FooGoRPCClient {
return client
}
func (goTSRPCClientInstance *FooGoRPCClient) Start() {
goTSRPCClientInstance.Client.Start()
func (tsc *FooGoRPCClient) Start() {
tsc.Client.Start()
}
func (goTSRPCClientInstance *FooGoRPCClient) Stop() {
goTSRPCClientInstance.Client.Stop()
func (tsc *FooGoRPCClient) Stop() {
tsc.Client.Stop()
}
func (goTSRPCClientInstance *FooGoRPCClient) Hello(number int64) (retHello_0 int, clientErr error) {
func (tsc *FooGoRPCClient) Hello(number int64) (retHello_0 int, clientErr error) {
req := FooHelloRequest{Number: number}
rpcCallRes, rpcCallErr := goTSRPCClientInstance.Client.Call(req)
rpcCallRes, rpcCallErr := tsc.Client.Call(req)
if rpcCallErr != nil {
clientErr = rpcCallErr
return
@ -55,17 +56,17 @@ func NewDemoGoRPCClient(addr string, tlsConfig *tls.Config) *DemoGoRPCClient {
return client
}
func (goTSRPCClientInstance *DemoGoRPCClient) Start() {
goTSRPCClientInstance.Client.Start()
func (tsc *DemoGoRPCClient) Start() {
tsc.Client.Start()
}
func (goTSRPCClientInstance *DemoGoRPCClient) Stop() {
goTSRPCClientInstance.Client.Stop()
func (tsc *DemoGoRPCClient) Stop() {
tsc.Client.Stop()
}
func (goTSRPCClientInstance *DemoGoRPCClient) ExtractAddress(person *Person) (addr *Address, e *Err, clientErr error) {
func (tsc *DemoGoRPCClient) ExtractAddress(person *Person) (addr *Address, e *Err, clientErr error) {
req := DemoExtractAddressRequest{Person: person}
rpcCallRes, rpcCallErr := goTSRPCClientInstance.Client.Call(req)
rpcCallRes, rpcCallErr := tsc.Client.Call(req)
if rpcCallErr != nil {
clientErr = rpcCallErr
return
@ -74,9 +75,9 @@ func (goTSRPCClientInstance *DemoGoRPCClient) ExtractAddress(person *Person) (ad
return response.Addr, response.E, nil
}
func (goTSRPCClientInstance *DemoGoRPCClient) GiveMeAScalar() (amount nested.Amount, wahr nested.True, hier ScalarInPlace, clientErr error) {
func (tsc *DemoGoRPCClient) GiveMeAScalar() (amount nested.Amount, wahr nested.True, hier ScalarInPlace, clientErr error) {
req := DemoGiveMeAScalarRequest{}
rpcCallRes, rpcCallErr := goTSRPCClientInstance.Client.Call(req)
rpcCallRes, rpcCallErr := tsc.Client.Call(req)
if rpcCallErr != nil {
clientErr = rpcCallErr
return
@ -85,9 +86,9 @@ func (goTSRPCClientInstance *DemoGoRPCClient) GiveMeAScalar() (amount nested.Amo
return response.Amount, response.Wahr, response.Hier, nil
}
func (goTSRPCClientInstance *DemoGoRPCClient) Hello(name string) (retHello_0 string, retHello_1 *Err, clientErr error) {
func (tsc *DemoGoRPCClient) Hello(name string) (retHello_0 string, retHello_1 *Err, clientErr error) {
req := DemoHelloRequest{Name: name}
rpcCallRes, rpcCallErr := goTSRPCClientInstance.Client.Call(req)
rpcCallRes, rpcCallErr := tsc.Client.Call(req)
if rpcCallErr != nil {
clientErr = rpcCallErr
return
@ -96,9 +97,9 @@ func (goTSRPCClientInstance *DemoGoRPCClient) Hello(name string) (retHello_0 str
return response.RetHello_0, response.RetHello_1, nil
}
func (goTSRPCClientInstance *DemoGoRPCClient) HelloInterface(anything interface{}, anythingMap map[string]interface{}, anythingSlice []interface{}) (clientErr error) {
func (tsc *DemoGoRPCClient) HelloInterface(anything interface{}, anythingMap map[string]interface{}, anythingSlice []interface{}) (clientErr error) {
req := DemoHelloInterfaceRequest{Anything: anything, AnythingMap: anythingMap, AnythingSlice: anythingSlice}
_, rpcCallErr := goTSRPCClientInstance.Client.Call(req)
_, rpcCallErr := tsc.Client.Call(req)
if rpcCallErr != nil {
clientErr = rpcCallErr
return
@ -106,9 +107,9 @@ func (goTSRPCClientInstance *DemoGoRPCClient) HelloInterface(anything interface{
return nil
}
func (goTSRPCClientInstance *DemoGoRPCClient) HelloScalarError() (err *ScalarError, clientErr error) {
func (tsc *DemoGoRPCClient) HelloScalarError() (err *ScalarError, clientErr error) {
req := DemoHelloScalarErrorRequest{}
rpcCallRes, rpcCallErr := goTSRPCClientInstance.Client.Call(req)
rpcCallRes, rpcCallErr := tsc.Client.Call(req)
if rpcCallErr != nil {
clientErr = rpcCallErr
return
@ -117,9 +118,9 @@ func (goTSRPCClientInstance *DemoGoRPCClient) HelloScalarError() (err *ScalarErr
return response.Err, nil
}
func (goTSRPCClientInstance *DemoGoRPCClient) MapCrap() (crap map[string][]int, clientErr error) {
func (tsc *DemoGoRPCClient) MapCrap() (crap map[string][]int, clientErr error) {
req := DemoMapCrapRequest{}
rpcCallRes, rpcCallErr := goTSRPCClientInstance.Client.Call(req)
rpcCallRes, rpcCallErr := tsc.Client.Call(req)
if rpcCallErr != nil {
clientErr = rpcCallErr
return
@ -128,9 +129,9 @@ func (goTSRPCClientInstance *DemoGoRPCClient) MapCrap() (crap map[string][]int,
return response.Crap, nil
}
func (goTSRPCClientInstance *DemoGoRPCClient) Nest() (retNest_0 *nested.Nested, clientErr error) {
func (tsc *DemoGoRPCClient) Nest() (retNest_0 []*nested.Nested, clientErr error) {
req := DemoNestRequest{}
rpcCallRes, rpcCallErr := goTSRPCClientInstance.Client.Call(req)
rpcCallRes, rpcCallErr := tsc.Client.Call(req)
if rpcCallErr != nil {
clientErr = rpcCallErr
return
@ -139,9 +140,9 @@ func (goTSRPCClientInstance *DemoGoRPCClient) Nest() (retNest_0 *nested.Nested,
return response.RetNest_0, nil
}
func (goTSRPCClientInstance *DemoGoRPCClient) TestScalarInPlace() (retTestScalarInPlace_0 ScalarInPlace, clientErr error) {
func (tsc *DemoGoRPCClient) TestScalarInPlace() (retTestScalarInPlace_0 ScalarInPlace, clientErr error) {
req := DemoTestScalarInPlaceRequest{}
rpcCallRes, rpcCallErr := goTSRPCClientInstance.Client.Call(req)
rpcCallRes, rpcCallErr := tsc.Client.Call(req)
if rpcCallErr != nil {
clientErr = rpcCallErr
return

View File

@ -1,4 +1,5 @@
// Code generated by gotsrpc https://github.com/foomo/gotsrpc DO NOT EDIT.
// Code generated by gotsrpc https://github.com/foomo/gotsrpc - DO NOT EDIT.
package demo
import (

View File

@ -1,4 +1,5 @@
// Code generated by gotsrpc https://github.com/foomo/gotsrpc DO NOT EDIT.
// Code generated by gotsrpc https://github.com/foomo/gotsrpc - DO NOT EDIT.
package demo
import (
@ -6,97 +7,124 @@ import (
nested "github.com/foomo/gotsrpc/demo/nested"
)
type FooGoTSRPCClient struct {
URL string
EndPoint string
type FooGoTSRPCClient interface {
Hello(number int64) (retHello_0 int, clientErr error)
}
func NewDefaultFooGoTSRPCClient(url string) *FooGoTSRPCClient {
type tsrpcFooGoTSRPCClient struct {
URL string
EndPoint string
Client gotsrpc.Client
}
func NewDefaultFooGoTSRPCClient(url string) FooGoTSRPCClient {
return NewFooGoTSRPCClient(url, "/service/foo")
}
func NewFooGoTSRPCClient(url string, endpoint string) *FooGoTSRPCClient {
return &FooGoTSRPCClient{
func NewFooGoTSRPCClient(url string, endpoint string) FooGoTSRPCClient {
return &tsrpcFooGoTSRPCClient{
URL: url,
EndPoint: endpoint,
Client: gotsrpc.NewClient(nil),
}
}
func (goTSRPCClientInstance *FooGoTSRPCClient) Hello(number int64) (retHello_0 int, clientErr error) {
func (tsc *tsrpcFooGoTSRPCClient) SetClient(client gotsrpc.Client) {
tsc.Client = client
}
func (tsc *tsrpcFooGoTSRPCClient) Hello(number int64) (retHello_0 int, clientErr error) {
args := []interface{}{number}
reply := []interface{}{&retHello_0}
clientErr = gotsrpc.CallClient(goTSRPCClientInstance.URL, goTSRPCClientInstance.EndPoint, "Hello", args, reply)
clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "Hello", args, reply)
return
}
type DemoGoTSRPCClient struct {
URL string
EndPoint string
type DemoGoTSRPCClient interface {
ExtractAddress(person *Person) (addr *Address, e *Err, clientErr error)
GiveMeAScalar() (amount nested.Amount, wahr nested.True, hier ScalarInPlace, clientErr error)
Hello(name string) (retHello_0 string, retHello_1 *Err, clientErr error)
HelloInterface(anything interface{}, anythingMap map[string]interface{}, anythingSlice []interface{}) (clientErr error)
HelloScalarError() (err *ScalarError, clientErr error)
MapCrap() (crap map[string][]int, clientErr error)
Nest() (retNest_0 []*nested.Nested, clientErr error)
TestScalarInPlace() (retTestScalarInPlace_0 ScalarInPlace, clientErr error)
}
func NewDefaultDemoGoTSRPCClient(url string) *DemoGoTSRPCClient {
var _ DemoGoTSRPCClient = &tsrpcDemoGoTSRPCClient{}
type tsrpcDemoGoTSRPCClient struct {
URL string
EndPoint string
Client gotsrpc.Client
}
func NewDefaultDemoGoTSRPCClient(url string) DemoGoTSRPCClient {
return NewDemoGoTSRPCClient(url, "/service/demo")
}
func NewDemoGoTSRPCClient(url string, endpoint string) *DemoGoTSRPCClient {
return &DemoGoTSRPCClient{
func NewDemoGoTSRPCClient(url string, endpoint string) DemoGoTSRPCClient {
return &tsrpcDemoGoTSRPCClient{
URL: url,
EndPoint: endpoint,
Client: gotsrpc.NewClient(nil),
}
}
func (goTSRPCClientInstance *DemoGoTSRPCClient) ExtractAddress(person *Person) (addr *Address, e *Err, clientErr error) {
func (tsc *tsrpcDemoGoTSRPCClient) SetClient(client gotsrpc.Client) {
tsc.Client = client
}
func (tsc *tsrpcDemoGoTSRPCClient) ExtractAddress(person *Person) (addr *Address, e *Err, clientErr error) {
args := []interface{}{person}
reply := []interface{}{&addr, &e}
clientErr = gotsrpc.CallClient(goTSRPCClientInstance.URL, goTSRPCClientInstance.EndPoint, "ExtractAddress", args, reply)
clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "ExtractAddress", args, reply)
return
}
func (goTSRPCClientInstance *DemoGoTSRPCClient) GiveMeAScalar() (amount nested.Amount, wahr nested.True, hier ScalarInPlace, clientErr error) {
func (tsc *tsrpcDemoGoTSRPCClient) GiveMeAScalar() (amount nested.Amount, wahr nested.True, hier ScalarInPlace, clientErr error) {
args := []interface{}{}
reply := []interface{}{&amount, &wahr, &hier}
clientErr = gotsrpc.CallClient(goTSRPCClientInstance.URL, goTSRPCClientInstance.EndPoint, "GiveMeAScalar", args, reply)
clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "GiveMeAScalar", args, reply)
return
}
func (goTSRPCClientInstance *DemoGoTSRPCClient) Hello(name string) (retHello_0 string, retHello_1 *Err, clientErr error) {
func (tsc *tsrpcDemoGoTSRPCClient) Hello(name string) (retHello_0 string, retHello_1 *Err, clientErr error) {
args := []interface{}{name}
reply := []interface{}{&retHello_0, &retHello_1}
clientErr = gotsrpc.CallClient(goTSRPCClientInstance.URL, goTSRPCClientInstance.EndPoint, "Hello", args, reply)
clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "Hello", args, reply)
return
}
func (goTSRPCClientInstance *DemoGoTSRPCClient) HelloInterface(anything interface{}, anythingMap map[string]interface{}, anythingSlice []interface{}) (clientErr error) {
func (tsc *tsrpcDemoGoTSRPCClient) HelloInterface(anything interface{}, anythingMap map[string]interface{}, anythingSlice []interface{}) (clientErr error) {
args := []interface{}{anything, anythingMap, anythingSlice}
reply := []interface{}{}
clientErr = gotsrpc.CallClient(goTSRPCClientInstance.URL, goTSRPCClientInstance.EndPoint, "HelloInterface", args, reply)
clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "HelloInterface", args, reply)
return
}
func (goTSRPCClientInstance *DemoGoTSRPCClient) HelloScalarError() (err *ScalarError, clientErr error) {
func (tsc *tsrpcDemoGoTSRPCClient) HelloScalarError() (err *ScalarError, clientErr error) {
args := []interface{}{}
reply := []interface{}{&err}
clientErr = gotsrpc.CallClient(goTSRPCClientInstance.URL, goTSRPCClientInstance.EndPoint, "HelloScalarError", args, reply)
clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "HelloScalarError", args, reply)
return
}
func (goTSRPCClientInstance *DemoGoTSRPCClient) MapCrap() (crap map[string][]int, clientErr error) {
func (tsc *tsrpcDemoGoTSRPCClient) MapCrap() (crap map[string][]int, clientErr error) {
args := []interface{}{}
reply := []interface{}{&crap}
clientErr = gotsrpc.CallClient(goTSRPCClientInstance.URL, goTSRPCClientInstance.EndPoint, "MapCrap", args, reply)
clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "MapCrap", args, reply)
return
}
func (goTSRPCClientInstance *DemoGoTSRPCClient) Nest() (retNest_0 *nested.Nested, clientErr error) {
func (tsc *tsrpcDemoGoTSRPCClient) Nest() (retNest_0 []*nested.Nested, clientErr error) {
args := []interface{}{}
reply := []interface{}{&retNest_0}
clientErr = gotsrpc.CallClient(goTSRPCClientInstance.URL, goTSRPCClientInstance.EndPoint, "Nest", args, reply)
clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "Nest", args, reply)
return
}
func (goTSRPCClientInstance *DemoGoTSRPCClient) TestScalarInPlace() (retTestScalarInPlace_0 ScalarInPlace, clientErr error) {
func (tsc *tsrpcDemoGoTSRPCClient) TestScalarInPlace() (retTestScalarInPlace_0 ScalarInPlace, clientErr error) {
args := []interface{}{}
reply := []interface{}{&retTestScalarInPlace_0}
clientErr = gotsrpc.CallClient(goTSRPCClientInstance.URL, goTSRPCClientInstance.EndPoint, "TestScalarInPlace", args, reply)
clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "TestScalarInPlace", args, reply)
return
}

130
demo/gotsrpcclient_test.go Normal file
View File

@ -0,0 +1,130 @@
package demo
import (
"fmt"
"github.com/foomo/gotsrpc/demo/nested"
"github.com/stretchr/testify/assert"
"math/rand"
"net/http/httptest"
"net/url"
"strconv"
"testing"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
func RandStringRunes(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}
var (
client DemoGoTSRPCClient
server *httptest.Server
)
func setup() {
server = httptest.NewServer(NewDefaultDemoGoTSRPCProxy(&Demo{}, []string{}))
serverUrl, _ := url.Parse(server.URL)
client = NewDefaultDemoGoTSRPCClient(serverUrl.String())
}
func teardown() {
server.Close()
}
func TestDefault(t *testing.T) {
setup()
defer teardown()
resp, errServer, errClient := client.Hello("stefan")
assert.NoError(t, errClient)
assert.Nil(t, errServer)
fmt.Println(resp)
}
func benchmarkRequests(b *testing.B, count int) {
setup()
defer teardown()
person := GeneratePerson(count)
b.ResetTimer()
for n := 0; n < b.N; n++ {
client.ExtractAddress(person)
}
}
func BenchmarkRequest1(b *testing.B) { benchmarkRequests(b, 1) }
func BenchmarkRequest10(b *testing.B) { benchmarkRequests(b, 10) }
func BenchmarkRequest100(b *testing.B) { benchmarkRequests(b, 100) }
func BenchmarkRequest1000(b *testing.B) { benchmarkRequests(b, 1000) }
func BenchmarkRequest10000(b *testing.B) { benchmarkRequests(b, 10000) }
func BenchmarkRequest100000(b *testing.B) { benchmarkRequests(b, 100000) }
func GeneratePerson(count int) *Person {
person := &Person{}
person.AddressPtr = GenerateAddress()
person.Addresses = map[string]*Address{}
for i := 0; i < count; i++ {
person.Addresses[strconv.Itoa(i)] = GenerateAddress()
}
return person
}
func GenerateAddress() *Address {
gen := func() string{
return RandStringRunes(32)
}
genarr := func(count int) (ret []string) {
ret = make([]string, count)
for i := 0; i < count; i++ {
ret[i] = gen()
}
return
}
return &Address{
City: gen(),
Signs: genarr(100),
SecretServerCrap: false,
PeoplePtr: nil,
ArrayOfMaps: nil,
ArrayArrayAddress: nil,
People: nil,
MapCrap: nil,
NestedPtr: &nested.Nested{
Name: gen(),
SuperNestedString: struct {
Ha int64
}{
Ha: 011,
},
SuperNestedPtr: &struct {
Bla string
}{
Bla: gen(),
},
},
NestedStruct: nested.Nested{
Name: gen(),
SuperNestedString: struct {
Ha int64
}{
Ha: 0,
},
SuperNestedPtr: &struct {
Bla string
}{
Bla: gen(),
},
},
}
}

View File

@ -29,7 +29,7 @@ export class DemoClient {
mapCrap(success:(crap:{[index:string]:number[]}) => void, err:(request:XMLHttpRequest, e?:Error) => void) {
this.transport(this.endPoint, "MapCrap", [], success, err);
}
nest(success:(ret:github_com_foomo_gotsrpc_demo_nested.Nested) => void, err:(request:XMLHttpRequest, e?:Error) => void) {
nest(success:(ret:github_com_foomo_gotsrpc_demo_nested.Nested[]) => void, err:(request:XMLHttpRequest, e?:Error) => void) {
this.transport(this.endPoint, "Nest", [], success, err);
}
testScalarInPlace(success:(ret:string) => void, err:(request:XMLHttpRequest, e?:Error) => void) {

View File

@ -54,7 +54,7 @@ module GoTSRPC.Demo {
mapCrap(success:(crap:{[index:string]:number[]}) => void, err:(request:XMLHttpRequest, e?:Error) => void) {
this.transport(this.endPoint, "MapCrap", [], success, err);
}
nest(success:(ret:GoTSRPC.Demo.Nested.Nested) => void, err:(request:XMLHttpRequest, e?:Error) => void) {
nest(success:(ret:GoTSRPC.Demo.Nested.Nested[]) => void, err:(request:XMLHttpRequest, e?:Error) => void) {
this.transport(this.endPoint, "Nest", [], success, err);
}
testScalarInPlace(success:(ret:string) => void, err:(request:XMLHttpRequest, e?:Error) => void) {

11
glide.lock generated
View File

@ -1,5 +1,5 @@
hash: 249ea428695a3cfe9f583980181fb650d69d107954538d0684342754f61c0c68
updated: 2017-10-12T16:13:47.627906627+02:00
hash: 629adb2b190665615fa6558666181d5fb97f23adecccfe1675ff0dec498207ec
updated: 2018-11-22T15:17:52.360766+01:00
imports:
- name: github.com/beorn7/perks
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
@ -30,14 +30,19 @@ imports:
- name: github.com/prometheus/procfs
version: abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
- name: github.com/stretchr/testify
version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0
version: f35b8ab0b5a2cef36673838d662e249dd9c94686
subpackages:
- assert
- name: github.com/ugorji/go
version: b4c50a2b199d93b13dc15e78929cfb23bfdf21ab
subpackages:
- codec
- name: github.com/valyala/gorpc
version: 908281bef77441f2d0ec1792189b4032a1dace0c
- name: golang.org/x/tools
version: e4b401d06e5ee9f990011dc4f24cd24162131565
subpackages:
- go/ast/astutil
- imports
- name: gopkg.in/yaml.v2
version: a5b47d31c556af34a302ce5d659e6fea44d90de0

View File

@ -1,5 +1,6 @@
package: github.com/foomo/gotsrpc
import:
- package: github.com/pkg/errors
- package: github.com/prometheus/client_golang
version: ~0.8.0
subpackages:
@ -11,3 +12,7 @@ import:
- package: golang.org/x/tools
subpackages:
- imports
- package: github.com/ugorji/go
version: ^1.1.1
subpackages:
- codec

116
go.go
View File

@ -340,6 +340,46 @@ func renderTSRPCServiceProxies(services ServiceList, fullPackageName string, pac
return nil
}
type goMethod struct {
name string
params []string
args []string
rets []string
returns []string
}
func newMethodSignature(method *Method, aliases map[string]string, fullPackageName string) goMethod {
var args []string
var params []string
for _, a := range goMethodArgsWithoutHTTPContextRelatedArgs(method) {
args = append(args, a.Name)
params = append(params, a.Name+" "+a.Value.goType(aliases, fullPackageName))
}
var rets []string
var returns []string
for i, r := range method.Return {
name := r.Name
if len(name) == 0 {
name = fmt.Sprintf("ret%s_%d", method.Name, i)
}
rets = append(rets, "&"+name)
returns = append(returns, name+" "+r.Value.goType(aliases, fullPackageName))
}
returns = append(returns, "clientErr error")
return goMethod{
name: method.Name,
params: params,
args: args,
rets: rets,
returns: returns,
}
}
func (ms *goMethod) renderSignature() string {
return ms.name + `(` + strings.Join(ms.params, ", ") + `) (` + strings.Join(ms.returns, ", ") + `)`
}
func renderTSRPCServiceClients(services ServiceList, fullPackageName string, packageName string, config *config.Target, g *code) error {
aliases := map[string]string{
"github.com/foomo/gotsrpc": "gotsrpc",
@ -366,46 +406,49 @@ func renderTSRPCServiceClients(services ServiceList, fullPackageName string, pac
continue
}
clientName := service.Name + "GoTSRPCClient"
interfaceName := service.Name + "GoTSRPCClient"
clientName := "tsrpc" + interfaceName
//Render Interface
g.l(`type ` + interfaceName + ` interface { `)
for _, method := range service.Methods {
ms := newMethodSignature(method, aliases, fullPackageName)
g.l(ms.renderSignature())
}
g.l(`} `)
//Render Constructors
g.l(`
type ` + clientName + ` struct {
URL string
EndPoint string
Client gotsrpc.Client
}
func NewDefault` + clientName + `(url string) *` + clientName + ` {
return New` + clientName + `(url, "` + service.Endpoint + `")
func NewDefault` + interfaceName + `(url string) ` + interfaceName + ` {
return New` + interfaceName + `(url, "` + service.Endpoint + `")
}
func New` + clientName + `(url string, endpoint string) *` + clientName + ` {
func New` + interfaceName + `(url string, endpoint string) ` + interfaceName + ` {
return &` + clientName + `{
URL: url,
EndPoint: endpoint,
Client: gotsrpc.NewClient(nil),
}
}
`)
}`)
//Render Methods
g.l(`
func (tsc *` + clientName + `) SetClient(client gotsrpc.Client) {
tsc.Client = client
}`)
for _, method := range service.Methods {
args := []string{}
params := []string{}
for _, a := range goMethodArgsWithoutHTTPContextRelatedArgs(method) {
args = append(args, a.Name)
params = append(params, a.Name+" "+a.Value.goType(aliases, fullPackageName))
}
rets := []string{}
returns := []string{}
for i, r := range method.Return {
name := r.Name
if len(name) == 0 {
name = fmt.Sprintf("ret%s_%d", method.Name, i)
}
rets = append(rets, "&"+name)
returns = append(returns, name+" "+r.Value.goType(aliases, fullPackageName))
}
returns = append(returns, "clientErr error")
g.l(`func (goTSRPCClientInstance *` + clientName + `) ` + method.Name + `(` + strings.Join(params, ", ") + `) (` + strings.Join(returns, ", ") + `) {`)
g.l(`args := []interface{}{` + strings.Join(args, ", ") + `}`)
g.l(`reply := []interface{}{` + strings.Join(rets, ", ") + `}`)
g.l(`clientErr = gotsrpc.CallClient(goTSRPCClientInstance.URL, goTSRPCClientInstance.EndPoint, "` + method.Name + `", args, reply)`)
ms := newMethodSignature(method, aliases, fullPackageName)
g.l(`func (tsc *` + clientName + `) ` + ms.renderSignature() + ` {`)
g.l(`args := []interface{}{` + strings.Join(ms.args, ", ") + `}`)
g.l(`reply := []interface{}{` + strings.Join(ms.rets, ", ") + `}`)
g.l(`clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "` + method.Name + `", args, reply)`)
g.l(`return`)
g.l(`}`)
g.nl()
@ -602,6 +645,7 @@ func renderGoRPCServiceClients(services ServiceList, fullPackageName string, pac
if !config.IsGoRPC(service.Name) {
continue
}
clientName := service.Name + "GoRPCClient"
// Client type
g.l(`
@ -621,12 +665,12 @@ func renderGoRPCServiceClients(services ServiceList, fullPackageName string, pac
return client
}
func (goTSRPCClientInstance *` + clientName + `) Start() {
goTSRPCClientInstance.Client.Start()
func (tsc *` + clientName + `) Start() {
tsc.Client.Start()
}
func (goTSRPCClientInstance *` + clientName + `) Stop() {
goTSRPCClientInstance.Client.Stop()
func (tsc *` + clientName + `) Stop() {
tsc.Client.Stop()
}
`)
g.nl()
@ -649,12 +693,12 @@ func renderGoRPCServiceClients(services ServiceList, fullPackageName string, pac
returns = append(returns, name+" "+r.Value.goType(aliases, fullPackageName))
}
returns = append(returns, "clientErr error")
g.l(`func (goTSRPCClientInstance *` + clientName + `) ` + method.Name + `(` + strings.Join(params, ", ") + `) (` + strings.Join(returns, ", ") + `) {`)
g.l(`func (tsc *` + clientName + `) ` + method.Name + `(` + strings.Join(params, ", ") + `) (` + strings.Join(returns, ", ") + `) {`)
g.l(`req := ` + service.Name + method.Name + `Request{` + strings.Join(args, ", ") + `}`)
if len(rets) > 0 {
g.l(`rpcCallRes, rpcCallErr := goTSRPCClientInstance.Client.Call(req)`)
g.l(`rpcCallRes, rpcCallErr := tsc.Client.Call(req)`)
} else {
g.l(`_, rpcCallErr := goTSRPCClientInstance.Client.Call(req)`)
g.l(`_, rpcCallErr := tsc.Client.Call(req)`)
}
g.l(`if rpcCallErr != nil {`)
g.l(`clientErr = rpcCallErr`)
@ -733,8 +777,10 @@ func renderImports(aliases map[string]string, packageName string) string {
imports += alias + " \"" + importPath + "\"\n"
}
return `
// Code generated by gotsrpc https://github.com/foomo/gotsrpc DO NOT EDIT.
// Code generated by gotsrpc https://github.com/foomo/gotsrpc - DO NOT EDIT.
package ` + packageName + `
import (
` + imports + `
)

View File

@ -3,12 +3,12 @@ package gotsrpc
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/pkg/errors"
"github.com/ugorji/go/codec"
"go/ast"
"go/parser"
"go/token"
"io/ioutil"
"net/http"
"path"
"sort"
@ -39,18 +39,20 @@ func ErrorMethodNotAllowed(w http.ResponseWriter) {
func LoadArgs(args interface{}, callStats *CallStats, r *http.Request) error {
start := time.Now()
body, err := ioutil.ReadAll(r.Body)
if err != nil {
return err
var errDecode error
switch r.Header.Get("Content-Type") {
case msgpackContentType:
errDecode = codec.NewDecoder(r.Body, msgpackHandle).Decode(args)
default:
errDecode = codec.NewDecoder(r.Body, jsonHandle).Decode(args)
}
errLoad := loadArgs(&args, body)
if errLoad != nil {
return errLoad
if errDecode != nil {
return errors.Wrap(errDecode, "could not decode arguments")
}
if callStats != nil {
callStats.Unmarshalling = time.Now().Sub(start)
callStats.RequestSize = len(body)
callStats.RequestSize = int(r.ContentLength)
}
return nil
}
@ -81,30 +83,33 @@ func ClearStats(r *http.Request) {
// Reply despite the fact, that this is a public method - do not call it, it will be called by generated code
func Reply(response []interface{}, stats *CallStats, r *http.Request, w http.ResponseWriter) {
writer := newResponseWriterWithLength(w)
serializationStart := time.Now()
jsonBytes, err := json.Marshal(response)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("could not serialize response"))
var errEncode error
switch r.Header.Get("Accept") {
case msgpackContentType:
writer.Header().Set("Content-Type", msgpackContentType)
errEncode = codec.NewEncoder(writer, msgpackHandle).Encode(response)
case jsonContentType:
writer.Header().Set("Content-Type", jsonContentType)
errEncode = codec.NewEncoder(writer, jsonHandle).Encode(response)
default:
writer.Header().Set("Content-Type", jsonContentType)
errEncode = codec.NewEncoder(writer, jsonHandle).Encode(response)
}
if errEncode != nil {
fmt.Println(errEncode)
http.Error(w, "could not encode data to accepted format", http.StatusInternalServerError)
return
}
if stats != nil {
stats.ResponseSize = len(jsonBytes)
stats.ResponseSize = writer.length
stats.Marshalling = time.Now().Sub(serializationStart)
}
//r = r.WithContext(ctx)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(jsonBytes)
//fmt.Println("replied with stats", stats, "on", ctx)
}
func jsonDump(v interface{}) {
jsonBytes, err := json.MarshalIndent(v, "", " ")
if err != nil {
fmt.Println("an error occured", err)
}
fmt.Println(string(jsonBytes))
//writer.WriteHeader(http.StatusOK)
}
func parseDir(goPaths []string, packageName string) (map[string]*ast.Package, error) {

36
transport.go Normal file
View File

@ -0,0 +1,36 @@
package gotsrpc
import (
"github.com/ugorji/go/codec"
"net/http"
)
var (
msgpackHandle = &codec.MsgpackHandle{}
msgpackContentType = "application/msgpack; charset=utf-8"
)
var (
jsonHandle = &codec.JsonHandle{}
jsonContentType = "application/json; charset=utf-8"
)
type responseWriterWithLength struct {
http.ResponseWriter
length int
}
func newResponseWriterWithLength(w http.ResponseWriter) *responseWriterWithLength {
return &responseWriterWithLength{w, 0}
}
func (w *responseWriterWithLength) Write(b []byte) (n int, err error) {
n, err = w.ResponseWriter.Write(b)
w.length += n
return
}
func (w *responseWriterWithLength) Length() int {
return w.length
}