feat: update handling of servers & clients

This commit is contained in:
Stefan Martinov 2018-11-30 15:13:04 +01:00
parent d93b987eaf
commit 8cee3c7df9
7 changed files with 83 additions and 64 deletions

View File

@ -18,13 +18,12 @@ var _ Client = &bufferedClient{}
type Client interface { type Client interface {
Call(url string, endpoint string, method string, args []interface{}, reply []interface{}) (err error) Call(url string, endpoint string, method string, args []interface{}, reply []interface{}) (err error)
SetEncoding(encoding ClientEncoding)
SetHttpClient(client *http.Client)
} }
func NewClient(httpClient *http.Client) Client { func NewClient() Client {
if httpClient == nil { return &bufferedClient{client: http.DefaultClient, handle: getHandleForEncoding(EncodingMsgpack)}
httpClient = http.DefaultClient
}
return &bufferedClient{client: httpClient}
} }
func newRequest(url string, contentType string, reader io.Reader) (r *http.Request, err error) { func newRequest(url string, contentType string, reader io.Reader) (r *http.Request, err error) {
@ -32,21 +31,31 @@ func newRequest(url string, contentType string, reader io.Reader) (r *http.Reque
if errRequest != nil { if errRequest != nil {
return nil, errors.Wrap(errRequest, "could not create a request") return nil, errors.Wrap(errRequest, "could not create a request")
} }
request.Header.Set("Content-Type", contentType) request.Header.Set("Content-Type", contentType)
request.Header.Set("Accept", contentType) request.Header.Set("Accept", contentType)
return request, nil return request, nil
} }
type bufferedClient struct { type bufferedClient struct {
client *http.Client client *http.Client
handle *clientHandle
}
func (c *bufferedClient) SetEncoding(encoding ClientEncoding) {
c.handle = getHandleForEncoding(encoding)
}
func (c *bufferedClient) SetHttpClient(client *http.Client) {
c.client = client
} }
// CallClient calls a method on the remove service // CallClient calls a method on the remove service
func (c *bufferedClient) Call(url string, endpoint string, method string, args []interface{}, reply []interface{}) (err error) { func (c *bufferedClient) Call(url string, endpoint string, method string, args []interface{}, reply []interface{}) (err error) {
// Marshall args // Marshall args
b := new(bytes.Buffer) b := new(bytes.Buffer)
errEncode := codec.NewEncoder(b, msgpackHandle).Encode(args) errEncode := codec.NewEncoder(b, c.handle.handle).Encode(args)
if errEncode != nil { if errEncode != nil {
return errors.Wrap(errEncode, "could not encode argument") return errors.Wrap(errEncode, "could not encode argument")
} }
@ -56,7 +65,7 @@ func (c *bufferedClient) Call(url string, endpoint string, method string, args [
postURL := fmt.Sprintf("%s%s/%s", url, endpoint, method) postURL := fmt.Sprintf("%s%s/%s", url, endpoint, method)
// Post // Post
request, errRequest := newRequest(postURL, msgpackContentType, b) request, errRequest := newRequest(postURL, c.handle.contentType, b)
if errRequest != nil { if errRequest != nil {
return errRequest return errRequest
} }
@ -77,14 +86,8 @@ func (c *bufferedClient) Call(url string, endpoint string, method string, args [
} }
var errDecode error var errDecode error
switch resp.Header.Get("Content-Type") { responseHandle := getHandlerForContentType(resp.Header.Get("Content-Type")).handle
case msgpackContentType: errDecode = codec.NewDecoder(resp.Body, responseHandle).Decode(reply)
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)
}
// Unmarshal reply // Unmarshal reply
if errDecode != nil { if errDecode != nil {

View File

@ -11,7 +11,7 @@ import (
time "time" time "time"
gotsrpc "github.com/foomo/gotsrpc" gotsrpc "github.com/foomo/gotsrpc"
nested "github.com/foomo/gotsrpc/demo/nested" github_com_foomo_gotsrpc_demo_nested "github.com/foomo/gotsrpc/demo/nested"
gorpc "github.com/valyala/gorpc" gorpc "github.com/valyala/gorpc"
) )
@ -111,8 +111,8 @@ type (
DemoGiveMeAScalarRequest struct { DemoGiveMeAScalarRequest struct {
} }
DemoGiveMeAScalarResponse struct { DemoGiveMeAScalarResponse struct {
Amount nested.Amount Amount github_com_foomo_gotsrpc_demo_nested.Amount
Wahr nested.True Wahr github_com_foomo_gotsrpc_demo_nested.True
Hier ScalarInPlace Hier ScalarInPlace
} }
@ -147,7 +147,7 @@ type (
DemoNestRequest struct { DemoNestRequest struct {
} }
DemoNestResponse struct { DemoNestResponse struct {
RetNest_0 []*nested.Nested RetNest_0 []*github_com_foomo_gotsrpc_demo_nested.Nested
} }
DemoTestScalarInPlaceRequest struct { DemoTestScalarInPlaceRequest struct {

View File

@ -5,7 +5,7 @@ package demo
import ( import (
tls "crypto/tls" tls "crypto/tls"
nested "github.com/foomo/gotsrpc/demo/nested" github_com_foomo_gotsrpc_demo_nested "github.com/foomo/gotsrpc/demo/nested"
gorpc "github.com/valyala/gorpc" gorpc "github.com/valyala/gorpc"
) )
@ -75,7 +75,7 @@ func (tsc *DemoGoRPCClient) ExtractAddress(person *Person) (addr *Address, e *Er
return response.Addr, response.E, nil return response.Addr, response.E, nil
} }
func (tsc *DemoGoRPCClient) GiveMeAScalar() (amount nested.Amount, wahr nested.True, hier ScalarInPlace, clientErr error) { func (tsc *DemoGoRPCClient) GiveMeAScalar() (amount github_com_foomo_gotsrpc_demo_nested.Amount, wahr github_com_foomo_gotsrpc_demo_nested.True, hier ScalarInPlace, clientErr error) {
req := DemoGiveMeAScalarRequest{} req := DemoGiveMeAScalarRequest{}
rpcCallRes, rpcCallErr := tsc.Client.Call(req) rpcCallRes, rpcCallErr := tsc.Client.Call(req)
if rpcCallErr != nil { if rpcCallErr != nil {
@ -129,7 +129,7 @@ func (tsc *DemoGoRPCClient) MapCrap() (crap map[string][]int, clientErr error) {
return response.Crap, nil return response.Crap, nil
} }
func (tsc *DemoGoRPCClient) Nest() (retNest_0 []*nested.Nested, clientErr error) { func (tsc *DemoGoRPCClient) Nest() (retNest_0 []*github_com_foomo_gotsrpc_demo_nested.Nested, clientErr error) {
req := DemoNestRequest{} req := DemoNestRequest{}
rpcCallRes, rpcCallErr := tsc.Client.Call(req) rpcCallRes, rpcCallErr := tsc.Client.Call(req)
if rpcCallErr != nil { if rpcCallErr != nil {

View File

@ -4,7 +4,7 @@ package demo
import ( import (
gotsrpc "github.com/foomo/gotsrpc" gotsrpc "github.com/foomo/gotsrpc"
nested "github.com/foomo/gotsrpc/demo/nested" github_com_foomo_gotsrpc_demo_nested "github.com/foomo/gotsrpc/demo/nested"
) )
type FooGoTSRPCClient interface { type FooGoTSRPCClient interface {
@ -25,7 +25,7 @@ func NewFooGoTSRPCClient(url string, endpoint string) FooGoTSRPCClient {
return &tsrpcFooGoTSRPCClient{ return &tsrpcFooGoTSRPCClient{
URL: url, URL: url,
EndPoint: endpoint, EndPoint: endpoint,
Client: gotsrpc.NewClient(nil), Client: gotsrpc.NewClient(),
} }
} }
@ -41,17 +41,15 @@ func (tsc *tsrpcFooGoTSRPCClient) Hello(number int64) (retHello_0 int, clientErr
type DemoGoTSRPCClient interface { type DemoGoTSRPCClient interface {
ExtractAddress(person *Person) (addr *Address, e *Err, clientErr error) ExtractAddress(person *Person) (addr *Address, e *Err, clientErr error)
GiveMeAScalar() (amount nested.Amount, wahr nested.True, hier ScalarInPlace, clientErr error) GiveMeAScalar() (amount github_com_foomo_gotsrpc_demo_nested.Amount, wahr github_com_foomo_gotsrpc_demo_nested.True, hier ScalarInPlace, clientErr error)
Hello(name string) (retHello_0 string, retHello_1 *Err, clientErr error) Hello(name string) (retHello_0 string, retHello_1 *Err, clientErr error)
HelloInterface(anything interface{}, anythingMap map[string]interface{}, anythingSlice []interface{}) (clientErr error) HelloInterface(anything interface{}, anythingMap map[string]interface{}, anythingSlice []interface{}) (clientErr error)
HelloScalarError() (err *ScalarError, clientErr error) HelloScalarError() (err *ScalarError, clientErr error)
MapCrap() (crap map[string][]int, clientErr error) MapCrap() (crap map[string][]int, clientErr error)
Nest() (retNest_0 []*nested.Nested, clientErr error) Nest() (retNest_0 []*github_com_foomo_gotsrpc_demo_nested.Nested, clientErr error)
TestScalarInPlace() (retTestScalarInPlace_0 ScalarInPlace, clientErr error) TestScalarInPlace() (retTestScalarInPlace_0 ScalarInPlace, clientErr error)
} }
var _ DemoGoTSRPCClient = &tsrpcDemoGoTSRPCClient{}
type tsrpcDemoGoTSRPCClient struct { type tsrpcDemoGoTSRPCClient struct {
URL string URL string
EndPoint string EndPoint string
@ -66,7 +64,7 @@ func NewDemoGoTSRPCClient(url string, endpoint string) DemoGoTSRPCClient {
return &tsrpcDemoGoTSRPCClient{ return &tsrpcDemoGoTSRPCClient{
URL: url, URL: url,
EndPoint: endpoint, EndPoint: endpoint,
Client: gotsrpc.NewClient(nil), Client: gotsrpc.NewClient(),
} }
} }
@ -80,7 +78,7 @@ func (tsc *tsrpcDemoGoTSRPCClient) ExtractAddress(person *Person) (addr *Address
return return
} }
func (tsc *tsrpcDemoGoTSRPCClient) GiveMeAScalar() (amount nested.Amount, wahr nested.True, hier ScalarInPlace, clientErr error) { func (tsc *tsrpcDemoGoTSRPCClient) GiveMeAScalar() (amount github_com_foomo_gotsrpc_demo_nested.Amount, wahr github_com_foomo_gotsrpc_demo_nested.True, hier ScalarInPlace, clientErr error) {
args := []interface{}{} args := []interface{}{}
reply := []interface{}{&amount, &wahr, &hier} reply := []interface{}{&amount, &wahr, &hier}
clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "GiveMeAScalar", args, reply) clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "GiveMeAScalar", args, reply)
@ -115,7 +113,7 @@ func (tsc *tsrpcDemoGoTSRPCClient) MapCrap() (crap map[string][]int, clientErr e
return return
} }
func (tsc *tsrpcDemoGoTSRPCClient) Nest() (retNest_0 []*nested.Nested, clientErr error) { func (tsc *tsrpcDemoGoTSRPCClient) Nest() (retNest_0 []*github_com_foomo_gotsrpc_demo_nested.Nested, clientErr error) {
args := []interface{}{} args := []interface{}{}
reply := []interface{}{&retNest_0} reply := []interface{}{&retNest_0}
clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "Nest", args, reply) clientErr = tsc.Client.Call(tsc.URL, tsc.EndPoint, "Nest", args, reply)

2
go.go
View File

@ -433,7 +433,7 @@ func renderTSRPCServiceClients(services ServiceList, fullPackageName string, pac
return &` + clientName + `{ return &` + clientName + `{
URL: url, URL: url,
EndPoint: endpoint, EndPoint: endpoint,
Client: gotsrpc.NewClient(nil), Client: gotsrpc.NewClient(),
} }
}`) }`)

View File

@ -39,15 +39,9 @@ func ErrorMethodNotAllowed(w http.ResponseWriter) {
func LoadArgs(args interface{}, callStats *CallStats, r *http.Request) error { func LoadArgs(args interface{}, callStats *CallStats, r *http.Request) error {
start := time.Now() start := time.Now()
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)
}
if errDecode != nil { handle := getHandlerForContentType(r.Header.Get("Content-Type")).handle
if errDecode := codec.NewDecoder(r.Body, handle).Decode(args); errDecode != nil {
return errors.Wrap(errDecode, "could not decode arguments") return errors.Wrap(errDecode, "could not decode arguments")
} }
if callStats != nil { if callStats != nil {
@ -85,21 +79,12 @@ func ClearStats(r *http.Request) {
func Reply(response []interface{}, stats *CallStats, r *http.Request, w http.ResponseWriter) { func Reply(response []interface{}, stats *CallStats, r *http.Request, w http.ResponseWriter) {
writer := newResponseWriterWithLength(w) writer := newResponseWriterWithLength(w)
serializationStart := time.Now() serializationStart := time.Now()
var errEncode error
switch r.Header.Get("Accept") { clientHandle := getHandlerForContentType(r.Header.Get("Content-Type"))
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 { writer.Header().Set("Content-Type", clientHandle.contentType)
if errEncode := codec.NewEncoder(writer, clientHandle.handle).Encode(response); errEncode != nil {
fmt.Println(errEncode) fmt.Println(errEncode)
http.Error(w, "could not encode data to accepted format", http.StatusInternalServerError) http.Error(w, "could not encode data to accepted format", http.StatusInternalServerError)
return return
@ -109,7 +94,6 @@ func Reply(response []interface{}, stats *CallStats, r *http.Request, w http.Res
stats.ResponseSize = writer.length stats.ResponseSize = writer.length
stats.Marshalling = time.Now().Sub(serializationStart) stats.Marshalling = time.Now().Sub(serializationStart)
} }
//writer.WriteHeader(http.StatusOK)
} }
func parseDir(goPaths []string, packageName string) (map[string]*ast.Package, error) { func parseDir(goPaths []string, packageName string) (map[string]*ast.Package, error) {

View File

@ -6,19 +6,53 @@ import (
"github.com/ugorji/go/codec" "github.com/ugorji/go/codec"
) )
var ( type ClientEncoding int
msgpackHandle = &codec.MsgpackHandle{
RawToString: true, const (
} EncodingMsgpack = ClientEncoding(0)
msgpackContentType = "application/msgpack; charset=utf-8" EncodingJson = ClientEncoding(1)
) )
var ( type clientHandle struct {
jsonHandle = &codec.JsonHandle{ handle codec.Handle
MapKeyAsString: true, contentType string
}
var msgpackClientHandle = &clientHandle{
handle: &codec.MsgpackHandle{
RawToString: true,
},
contentType: "application/msgpack; charset=utf-8",
}
var jsonClientHandle = &clientHandle{
handle: &codec.JsonHandle{
MapKeyAsString: true,
},
contentType: "application/json; charset=utf-8",
}
func getHandleForEncoding(encoding ClientEncoding) *clientHandle {
switch encoding {
case EncodingMsgpack:
return msgpackClientHandle
case EncodingJson:
return jsonClientHandle
default:
return jsonClientHandle
}
}
func getHandlerForContentType(contentType string) *clientHandle {
switch contentType {
case msgpackClientHandle.contentType:
return msgpackClientHandle
case jsonClientHandle.contentType:
return jsonClientHandle
default:
return jsonClientHandle
}
} }
jsonContentType = "application/json; charset=utf-8"
)
type responseWriterWithLength struct { type responseWriterWithLength struct {
http.ResponseWriter http.ResponseWriter