Working bidirectional streaming example
This commit is contained in:
parent
a5be9ca585
commit
3b295b16e7
@ -63,6 +63,7 @@ func newRpcPlusCodec(req *transport.Message, client transport.Client, c codec.Ne
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *rpcPlusCodec) WriteRequest(req *request, body interface{}) error {
|
func (c *rpcPlusCodec) WriteRequest(req *request, body interface{}) error {
|
||||||
|
c.buf.wbuf.Reset()
|
||||||
m := &codec.Message{
|
m := &codec.Message{
|
||||||
Id: req.Seq,
|
Id: req.Seq,
|
||||||
Target: req.Service,
|
Target: req.Service,
|
||||||
|
@ -50,7 +50,6 @@ func (r *rpcStream) Send(msg interface{}) error {
|
|||||||
r.err = err
|
r.err = err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,8 +54,9 @@ func call(i int) {
|
|||||||
fmt.Println("Call:", i, "rsp:", rsp.Msg)
|
fmt.Println("Call:", i, "rsp:", rsp.Msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func stream() {
|
func stream(i int) {
|
||||||
// Create new request to service go.micro.srv.example, method Example.Call
|
// Create new request to service go.micro.srv.example, method Example.Call
|
||||||
|
// Request can be empty as its actually ignored and merely used to call the handler
|
||||||
req := client.NewRequest("go.micro.srv.example", "Example.Stream", &example.StreamingRequest{})
|
req := client.NewRequest("go.micro.srv.example", "Example.Stream", &example.StreamingRequest{})
|
||||||
|
|
||||||
stream, err := client.Stream(context.Background(), req)
|
stream, err := client.Stream(context.Background(), req)
|
||||||
@ -63,7 +64,10 @@ func stream() {
|
|||||||
fmt.Println("err:", err)
|
fmt.Println("err:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if err := stream.Send(&example.StreamingRequest{Count: int64(i)}); err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
for stream.Error() == nil {
|
for stream.Error() == nil {
|
||||||
rsp := &example.StreamingResponse{}
|
rsp := &example.StreamingResponse{}
|
||||||
err := stream.Recv(rsp)
|
err := stream.Recv(rsp)
|
||||||
@ -84,6 +88,41 @@ func stream() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pingPong(i int) {
|
||||||
|
// Create new request to service go.micro.srv.example, method Example.Call
|
||||||
|
// Request can be empty as its actually ignored and merely used to call the handler
|
||||||
|
req := client.NewRequest("go.micro.srv.example", "Example.PingPong", &example.StreamingRequest{})
|
||||||
|
|
||||||
|
stream, err := client.Stream(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if err := stream.Send(&example.Ping{Stroke: int64(j)}); err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rsp := &example.Pong{}
|
||||||
|
err := stream.Recv(rsp)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("recv err", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Printf("Sent ping %v got pong %v\n", j, rsp.Stroke)
|
||||||
|
}
|
||||||
|
|
||||||
|
if stream.Error() != nil {
|
||||||
|
fmt.Println("stream err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := stream.Close(); err != nil {
|
||||||
|
fmt.Println("stream close err:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cmd.Init()
|
cmd.Init()
|
||||||
// fmt.Println("\n--- Call example ---\n")
|
// fmt.Println("\n--- Call example ---\n")
|
||||||
@ -91,8 +130,11 @@ func main() {
|
|||||||
// call(i)
|
// call(i)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
fmt.Println("\n--- Streamer example ---\n")
|
// fmt.Println("\n--- Streamer example ---\n")
|
||||||
stream()
|
// stream(10)
|
||||||
|
|
||||||
|
fmt.Println("\n--- Ping Pong example ---\n")
|
||||||
|
pingPong(10)
|
||||||
|
|
||||||
// fmt.Println("\n--- Publisher example ---\n")
|
// fmt.Println("\n--- Publisher example ---\n")
|
||||||
// pub()
|
// pub()
|
||||||
|
@ -42,3 +42,17 @@ func (e *Example) Stream(ctx context.Context, stream server.Streamer) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Example) PingPong(ctx context.Context, stream server.Streamer) error {
|
||||||
|
for {
|
||||||
|
req := &example.Ping{}
|
||||||
|
if err := stream.Recv(req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Infof("Got ping %v", req.Stroke)
|
||||||
|
if err := stream.Send(&example.Pong{Stroke: req.Stroke}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -14,6 +14,8 @@ It has these top-level messages:
|
|||||||
Response
|
Response
|
||||||
StreamingRequest
|
StreamingRequest
|
||||||
StreamingResponse
|
StreamingResponse
|
||||||
|
Ping
|
||||||
|
Pong
|
||||||
*/
|
*/
|
||||||
package go_micro_srv_example
|
package go_micro_srv_example
|
||||||
|
|
||||||
@ -77,12 +79,32 @@ func (m *StreamingResponse) String() string { return proto.CompactTex
|
|||||||
func (*StreamingResponse) ProtoMessage() {}
|
func (*StreamingResponse) ProtoMessage() {}
|
||||||
func (*StreamingResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
|
func (*StreamingResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
|
||||||
|
|
||||||
|
type Ping struct {
|
||||||
|
Stroke int64 `protobuf:"varint,1,opt,name=stroke" json:"stroke,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Ping) Reset() { *m = Ping{} }
|
||||||
|
func (m *Ping) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Ping) ProtoMessage() {}
|
||||||
|
func (*Ping) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
|
||||||
|
|
||||||
|
type Pong struct {
|
||||||
|
Stroke int64 `protobuf:"varint,1,opt,name=stroke" json:"stroke,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Pong) Reset() { *m = Pong{} }
|
||||||
|
func (m *Pong) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Pong) ProtoMessage() {}
|
||||||
|
func (*Pong) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
proto.RegisterType((*Message)(nil), "go.micro.srv.example.Message")
|
proto.RegisterType((*Message)(nil), "go.micro.srv.example.Message")
|
||||||
proto.RegisterType((*Request)(nil), "go.micro.srv.example.Request")
|
proto.RegisterType((*Request)(nil), "go.micro.srv.example.Request")
|
||||||
proto.RegisterType((*Response)(nil), "go.micro.srv.example.Response")
|
proto.RegisterType((*Response)(nil), "go.micro.srv.example.Response")
|
||||||
proto.RegisterType((*StreamingRequest)(nil), "go.micro.srv.example.StreamingRequest")
|
proto.RegisterType((*StreamingRequest)(nil), "go.micro.srv.example.StreamingRequest")
|
||||||
proto.RegisterType((*StreamingResponse)(nil), "go.micro.srv.example.StreamingResponse")
|
proto.RegisterType((*StreamingResponse)(nil), "go.micro.srv.example.StreamingResponse")
|
||||||
|
proto.RegisterType((*Ping)(nil), "go.micro.srv.example.Ping")
|
||||||
|
proto.RegisterType((*Pong)(nil), "go.micro.srv.example.Pong")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reference imports to suppress errors if they are not otherwise used.
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
@ -95,6 +117,7 @@ var _ server.Option
|
|||||||
type ExampleClient interface {
|
type ExampleClient interface {
|
||||||
Call(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
|
Call(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
|
||||||
Stream(ctx context.Context, in *StreamingRequest, opts ...client.CallOption) (Example_StreamClient, error)
|
Stream(ctx context.Context, in *StreamingRequest, opts ...client.CallOption) (Example_StreamClient, error)
|
||||||
|
PingPong(ctx context.Context, in *Ping, opts ...client.CallOption) (Example_PingPongClient, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type exampleClient struct {
|
type exampleClient struct {
|
||||||
@ -152,11 +175,44 @@ func (x *exampleStreamClient) RecvMsg() (*StreamingResponse, error) {
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *exampleClient) PingPong(ctx context.Context, in *Ping, opts ...client.CallOption) (Example_PingPongClient, error) {
|
||||||
|
req := c.c.NewRequest(c.serviceName, "Example.PingPong", in)
|
||||||
|
stream, err := c.c.Stream(ctx, req, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &examplePingPongClient{stream}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Example_PingPongClient interface {
|
||||||
|
SendMsg(*Ping) error
|
||||||
|
RecvMsg() (*Pong, error)
|
||||||
|
client.Streamer
|
||||||
|
}
|
||||||
|
|
||||||
|
type examplePingPongClient struct {
|
||||||
|
client.Streamer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *examplePingPongClient) SendMsg(m *Ping) error {
|
||||||
|
return x.Send(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *examplePingPongClient) RecvMsg() (*Pong, error) {
|
||||||
|
m := new(Pong)
|
||||||
|
err := x.Recv(m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Server API for Example service
|
// Server API for Example service
|
||||||
|
|
||||||
type ExampleHandler interface {
|
type ExampleHandler interface {
|
||||||
Call(context.Context, *Request, *Response) error
|
Call(context.Context, *Request, *Response) error
|
||||||
Stream(context.Context, func(*StreamingResponse) error) error
|
Stream(context.Context, func(*StreamingResponse) error) error
|
||||||
|
PingPong(context.Context, func(*Pong) error) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterExampleHandler(s server.Server, hdlr ExampleHandler) {
|
func RegisterExampleHandler(s server.Server, hdlr ExampleHandler) {
|
||||||
@ -164,20 +220,22 @@ func RegisterExampleHandler(s server.Server, hdlr ExampleHandler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fileDescriptor0 = []byte{
|
var fileDescriptor0 = []byte{
|
||||||
// 230 bytes of a gzipped FileDescriptorProto
|
// 270 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x90, 0xcd, 0x4a, 0xc5, 0x30,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x91, 0x5f, 0x4b, 0xc3, 0x30,
|
||||||
0x10, 0x85, 0x0d, 0xf7, 0x7a, 0xab, 0xa3, 0x82, 0x06, 0x51, 0x29, 0x28, 0x9a, 0x85, 0xba, 0x31,
|
0x14, 0xc5, 0x17, 0x56, 0xdb, 0x79, 0xfd, 0x83, 0x06, 0x99, 0x52, 0x50, 0x34, 0x0f, 0xba, 0x17,
|
||||||
0x15, 0xf5, 0x0d, 0x44, 0x5c, 0xb9, 0xa9, 0x6b, 0x17, 0xb1, 0x0c, 0xa1, 0xd0, 0x24, 0x35, 0x93,
|
0xd3, 0xa1, 0x7e, 0x03, 0x11, 0x7d, 0x11, 0x64, 0x3e, 0xfb, 0x10, 0xc7, 0x25, 0x0c, 0x9b, 0xa6,
|
||||||
0x16, 0x7d, 0x2c, 0xdf, 0x50, 0x48, 0xd3, 0xa2, 0x52, 0x71, 0x15, 0x98, 0xf3, 0x9d, 0x1f, 0x02,
|
0xe6, 0x66, 0x43, 0x3f, 0xbb, 0x2f, 0x6e, 0x69, 0x3b, 0xc6, 0xec, 0xf0, 0x29, 0x70, 0x7e, 0xe7,
|
||||||
0x77, 0xda, 0x5d, 0x99, 0xba, 0xf2, 0xae, 0xc0, 0x77, 0x65, 0xda, 0x06, 0xa9, 0x20, 0xf4, 0x3d,
|
0x5c, 0xce, 0x21, 0x70, 0xa7, 0xed, 0xb5, 0x99, 0x8c, 0x9d, 0xcd, 0xf0, 0x4b, 0x99, 0x32, 0x47,
|
||||||
0xfa, 0xa2, 0xf5, 0x2e, 0x4c, 0xd7, 0xf1, 0x95, 0xf1, 0xca, 0xf7, 0xb5, 0x93, 0xd1, 0x25, 0xc9,
|
0xca, 0x08, 0xdd, 0x0c, 0x5d, 0x56, 0x3a, 0xeb, 0x97, 0x6a, 0xf3, 0xca, 0xa0, 0xf2, 0x23, 0x6d,
|
||||||
0xf7, 0x32, 0x69, 0xe2, 0x00, 0xb2, 0x27, 0x24, 0x52, 0x1a, 0xf9, 0x16, 0x2c, 0x48, 0x7d, 0x1c,
|
0x65, 0x48, 0x49, 0x72, 0x33, 0x59, 0x33, 0xd1, 0x87, 0xe4, 0x19, 0x89, 0x94, 0x46, 0xbe, 0x03,
|
||||||
0xb1, 0x53, 0x76, 0xb9, 0x29, 0x0e, 0x21, 0x2b, 0xf1, 0xad, 0x43, 0x0a, 0x7c, 0x1b, 0x96, 0x56,
|
0x5d, 0x52, 0xdf, 0x27, 0xec, 0x9c, 0x0d, 0xb6, 0xc5, 0x31, 0x24, 0x23, 0xfc, 0x9c, 0x22, 0x79,
|
||||||
0x19, 0x9c, 0x84, 0x8d, 0x12, 0xa9, 0x75, 0x96, 0xa2, 0xc3, 0x90, 0x4e, 0xc2, 0x19, 0xec, 0x3e,
|
0xbe, 0x0b, 0x51, 0xa1, 0x0c, 0x2e, 0x41, 0x6f, 0x84, 0x54, 0xda, 0x82, 0x42, 0xc2, 0x90, 0xae,
|
||||||
0x07, 0x8f, 0xca, 0xd4, 0x56, 0x8f, 0xd6, 0x1d, 0x58, 0xaf, 0x5c, 0x67, 0x43, 0x44, 0x16, 0x42,
|
0xc1, 0x05, 0x1c, 0xbc, 0x7a, 0x87, 0xca, 0x4c, 0x0a, 0xdd, 0x44, 0xf7, 0x60, 0x6b, 0x6c, 0xa7,
|
||||||
0xc0, 0xde, 0x37, 0x24, 0x85, 0xfc, 0x64, 0x6e, 0x3e, 0x19, 0x64, 0x0f, 0xc3, 0x38, 0xfe, 0x08,
|
0x85, 0x0f, 0x96, 0xae, 0x10, 0x70, 0xb8, 0x62, 0xa9, 0x8f, 0xac, 0x79, 0xfa, 0x10, 0xbd, 0xcc,
|
||||||
0xcb, 0x7b, 0xd5, 0x34, 0xfc, 0x58, 0xce, 0x6d, 0x97, 0xa9, 0x25, 0x3f, 0xf9, 0x4b, 0x1e, 0x1a,
|
0x31, 0xdf, 0x87, 0x98, 0xbc, 0xb3, 0x1f, 0xb8, 0xa2, 0xdb, 0xbf, 0xfa, 0xcd, 0x0f, 0x83, 0xe4,
|
||||||
0xc4, 0x1a, 0x7f, 0x81, 0xd5, 0x50, 0xcc, 0xcf, 0xe7, 0xd9, 0xdf, 0xcb, 0xf3, 0x8b, 0x7f, 0xb9,
|
0xa1, 0x1a, 0xc3, 0x1f, 0x21, 0xba, 0x57, 0x79, 0xce, 0x4f, 0x65, 0xdb, 0x56, 0x59, 0xb7, 0x4a,
|
||||||
0x31, 0xfc, 0x9a, 0xbd, 0xae, 0xe2, 0x0f, 0xdf, 0x7e, 0x05, 0x00, 0x00, 0xff, 0xff, 0x63, 0x02,
|
0xcf, 0x36, 0xe1, 0xaa, 0x91, 0xe8, 0xf0, 0x37, 0x88, 0xab, 0xa2, 0xfc, 0xb2, 0xdd, 0xbb, 0xbe,
|
||||||
0xbf, 0x5f, 0x99, 0x01, 0x00, 0x00,
|
0x34, 0xbd, 0xfa, 0xd7, 0xd7, 0x1c, 0x1f, 0x32, 0xfe, 0x04, 0xbd, 0xc5, 0xc6, 0xb0, 0x27, 0x6d,
|
||||||
|
0x0f, 0x2e, 0x78, 0xba, 0x89, 0xcd, 0x73, 0xa2, 0x33, 0x60, 0x43, 0xf6, 0x1e, 0x87, 0xbf, 0xbd,
|
||||||
|
0xfd, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x53, 0xb5, 0xeb, 0x31, 0x13, 0x02, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ package go.micro.srv.example;
|
|||||||
service Example {
|
service Example {
|
||||||
rpc Call(Request) returns (Response) {}
|
rpc Call(Request) returns (Response) {}
|
||||||
rpc Stream(StreamingRequest) returns (stream StreamingResponse) {}
|
rpc Stream(StreamingRequest) returns (stream StreamingResponse) {}
|
||||||
|
rpc PingPong(stream Ping) returns (stream Pong) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
message Message {
|
message Message {
|
||||||
@ -26,3 +27,11 @@ message StreamingRequest {
|
|||||||
message StreamingResponse {
|
message StreamingResponse {
|
||||||
int64 count = 1;
|
int64 count = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message Ping {
|
||||||
|
int64 stroke = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Pong {
|
||||||
|
int64 stroke = 1;
|
||||||
|
}
|
||||||
|
@ -60,9 +60,20 @@ func newRpcPlusCodec(req *transport.Message, socket transport.Socket, c codec.Ne
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rpcPlusCodec) ReadRequestHeader(r *request) error {
|
func (c *rpcPlusCodec) ReadRequestHeader(r *request, first bool) error {
|
||||||
m := codec.Message{
|
m := codec.Message{Headers: c.req.Header}
|
||||||
Headers: c.req.Header,
|
|
||||||
|
if !first {
|
||||||
|
var tm transport.Message
|
||||||
|
if err := c.socket.Recv(&tm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.buf.rbuf.Reset()
|
||||||
|
if _, err := c.buf.rbuf.Write(tm.Body); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Headers = tm.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
err := c.codec.ReadHeader(&m, codec.Request)
|
err := c.codec.ReadHeader(&m, codec.Request)
|
||||||
|
@ -51,7 +51,7 @@ func (r *rpcStream) Recv(msg interface{}) error {
|
|||||||
|
|
||||||
req := request{}
|
req := request{}
|
||||||
|
|
||||||
if err := r.codec.ReadRequestHeader(&req); err != nil {
|
if err := r.codec.ReadRequestHeader(&req, false); err != nil {
|
||||||
// discard body
|
// discard body
|
||||||
r.codec.ReadRequestBody(nil)
|
r.codec.ReadRequestBody(nil)
|
||||||
return err
|
return err
|
||||||
|
@ -389,7 +389,6 @@ func (server *server) readRequest(codec serverCodec) (service *service, mtype *m
|
|||||||
codec.ReadRequestBody(nil)
|
codec.ReadRequestBody(nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// is it a streaming request? then we don't read the body
|
// is it a streaming request? then we don't read the body
|
||||||
if mtype.stream {
|
if mtype.stream {
|
||||||
codec.ReadRequestBody(nil)
|
codec.ReadRequestBody(nil)
|
||||||
@ -421,7 +420,7 @@ func (server *server) readRequest(codec serverCodec) (service *service, mtype *m
|
|||||||
func (server *server) readRequestHeader(codec serverCodec) (service *service, mtype *methodType, req *request, keepReading bool, err error) {
|
func (server *server) readRequestHeader(codec serverCodec) (service *service, mtype *methodType, req *request, keepReading bool, err error) {
|
||||||
// Grab the request header.
|
// Grab the request header.
|
||||||
req = server.getRequest()
|
req = server.getRequest()
|
||||||
err = codec.ReadRequestHeader(req)
|
err = codec.ReadRequestHeader(req, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req = nil
|
req = nil
|
||||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
@ -456,7 +455,7 @@ func (server *server) readRequestHeader(codec serverCodec) (service *service, mt
|
|||||||
}
|
}
|
||||||
|
|
||||||
type serverCodec interface {
|
type serverCodec interface {
|
||||||
ReadRequestHeader(*request) error
|
ReadRequestHeader(*request, bool) error
|
||||||
ReadRequestBody(interface{}) error
|
ReadRequestBody(interface{}) error
|
||||||
WriteResponse(*response, interface{}, bool) error
|
WriteResponse(*response, interface{}, bool) error
|
||||||
|
|
||||||
|
@ -23,16 +23,21 @@ type httpTransportClient struct {
|
|||||||
addr string
|
addr string
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
dialOpts dialOptions
|
dialOpts dialOptions
|
||||||
r chan *http.Request
|
|
||||||
once sync.Once
|
once sync.Once
|
||||||
|
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
r chan *http.Request
|
||||||
|
bl []*http.Request
|
||||||
buff *bufio.Reader
|
buff *bufio.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
type httpTransportSocket struct {
|
type httpTransportSocket struct {
|
||||||
r *http.Request
|
r chan *http.Request
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
|
once sync.Once
|
||||||
|
|
||||||
|
sync.Mutex
|
||||||
|
buff *bufio.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
type httpTransportListener struct {
|
type httpTransportListener struct {
|
||||||
@ -68,7 +73,14 @@ func (h *httpTransportClient) Send(m *Message) error {
|
|||||||
Host: h.addr,
|
Host: h.addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
h.r <- req
|
h.Lock()
|
||||||
|
h.bl = append(h.bl, req)
|
||||||
|
select {
|
||||||
|
case h.r <- h.bl[0]:
|
||||||
|
h.bl = h.bl[1:]
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
h.Unlock()
|
||||||
|
|
||||||
return req.Write(h.conn)
|
return req.Write(h.conn)
|
||||||
}
|
}
|
||||||
@ -134,17 +146,23 @@ func (h *httpTransportSocket) Recv(m *Message) error {
|
|||||||
return errors.New("message passed in is nil")
|
return errors.New("message passed in is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := ioutil.ReadAll(h.r.Body)
|
r, err := http.ReadRequest(h.buff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
h.r.Body.Close()
|
|
||||||
|
b, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.Body.Close()
|
||||||
|
|
||||||
mr := &Message{
|
mr := &Message{
|
||||||
Header: make(map[string]string),
|
Header: make(map[string]string),
|
||||||
Body: b,
|
Body: b,
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range h.r.Header {
|
for k, v := range r.Header {
|
||||||
if len(v) > 0 {
|
if len(v) > 0 {
|
||||||
mr.Header[k] = v[0]
|
mr.Header[k] = v[0]
|
||||||
} else {
|
} else {
|
||||||
@ -152,6 +170,11 @@ func (h *httpTransportSocket) Recv(m *Message) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case h.r <- r:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
*m = *mr
|
*m = *mr
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -159,8 +182,11 @@ func (h *httpTransportSocket) Recv(m *Message) error {
|
|||||||
func (h *httpTransportSocket) Send(m *Message) error {
|
func (h *httpTransportSocket) Send(m *Message) error {
|
||||||
b := bytes.NewBuffer(m.Body)
|
b := bytes.NewBuffer(m.Body)
|
||||||
defer b.Reset()
|
defer b.Reset()
|
||||||
|
|
||||||
|
r := <-h.r
|
||||||
|
|
||||||
rsp := &http.Response{
|
rsp := &http.Response{
|
||||||
Header: h.r.Header,
|
Header: r.Header,
|
||||||
Body: &buffer{b},
|
Body: &buffer{b},
|
||||||
Status: "200 OK",
|
Status: "200 OK",
|
||||||
StatusCode: 200,
|
StatusCode: 200,
|
||||||
@ -174,6 +200,11 @@ func (h *httpTransportSocket) Send(m *Message) error {
|
|||||||
rsp.Header.Set(k, v)
|
rsp.Header.Set(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case h.r <- r:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
return rsp.Write(h.conn)
|
return rsp.Write(h.conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +230,14 @@ func (h *httpTransportSocket) error(m *Message) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpTransportSocket) Close() error {
|
func (h *httpTransportSocket) Close() error {
|
||||||
return h.conn.Close()
|
err := h.conn.Close()
|
||||||
|
h.once.Do(func() {
|
||||||
|
h.Lock()
|
||||||
|
h.buff.Reset(nil)
|
||||||
|
h.buff = nil
|
||||||
|
h.Unlock()
|
||||||
|
})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpTransportListener) Addr() string {
|
func (h *httpTransportListener) Addr() string {
|
||||||
@ -211,18 +249,19 @@ func (h *httpTransportListener) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpTransportListener) Accept(fn func(Socket)) error {
|
func (h *httpTransportListener) Accept(fn func(Socket)) error {
|
||||||
srv := &http.Server{
|
for {
|
||||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
c, err := h.listener.Accept()
|
||||||
conn, _, err := w.(http.Hijacker).Hijack()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sock := &httpTransportSocket{
|
sock := &httpTransportSocket{
|
||||||
conn: conn,
|
conn: c,
|
||||||
r: r,
|
buff: bufio.NewReader(c),
|
||||||
|
r: make(chan *http.Request, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
// TODO: think of a better error response strategy
|
// TODO: think of a better error response strategy
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -231,10 +270,9 @@ func (h *httpTransportListener) Accept(fn func(Socket)) error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
fn(sock)
|
fn(sock)
|
||||||
}),
|
}()
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
return srv.Serve(h.listener)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpTransport) Dial(addr string, opts ...DialOption) (Client, error) {
|
func (h *httpTransport) Dial(addr string, opts ...DialOption) (Client, error) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user