1
0
mirror of https://github.com/go-micro/go-micro.git synced 2024-11-24 08:02:32 +02:00

[feature] stream CloseSend (#2323)

* support stream CloseSend

* move CloseSend into Closer
This commit is contained in:
Johnson C 2021-10-26 22:07:08 +08:00 committed by GitHub
parent af3cfa0a4c
commit d2a51d05c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 2378 additions and 391 deletions

View File

@ -64,6 +64,7 @@ type Response interface {
// Stream is the inteface for a bidirectional synchronous stream
type Stream interface {
Closer
// Context for the stream
Context() context.Context
// The request made
@ -80,6 +81,12 @@ type Stream interface {
Close() error
}
// Closer handle client close
type Closer interface {
// CloseSend closes the send direction of the stream.
CloseSend() error
}
// Option used by the Client
type Option func(*Options)

View File

@ -6,6 +6,7 @@ import (
"sync/atomic"
"time"
"github.com/google/uuid"
"go-micro.dev/v4/broker"
"go-micro.dev/v4/codec"
raw "go-micro.dev/v4/codec/bytes"
@ -17,7 +18,6 @@ import (
"go-micro.dev/v4/util/buf"
"go-micro.dev/v4/util/net"
"go-micro.dev/v4/util/pool"
"github.com/google/uuid"
)
type rpcClient struct {
@ -60,7 +60,7 @@ func (r *rpcClient) newCodec(contentType string) (codec.NewCodec, error) {
if cf, ok := DefaultCodecs[contentType]; ok {
return cf, nil
}
return nil, fmt.Errorf("Unsupported Content-Type: %s", contentType)
return nil, fmt.Errorf("unsupported Content-Type: %s", contentType)
}
func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request, resp interface{}, opts CallOptions) error {

View File

@ -2,6 +2,7 @@ package client
import (
"context"
"errors"
"io"
"sync"
@ -129,6 +130,10 @@ func (r *rpcStream) Error() error {
return r.err
}
func (r *rpcStream) CloseSend() error {
return errors.New("streamer not implemented")
}
func (r *rpcStream) Close() error {
r.Lock()

View File

@ -3,7 +3,7 @@ module github.com/asim/go-micro/cmd/protoc-gen-micro/v4
go 1.16
require (
go-micro.dev/v4 v4.1.0
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8
go-micro.dev/v4 v4.2.1
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c
google.golang.org/protobuf v1.27.1
)

View File

@ -301,11 +301,9 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
@ -490,9 +488,8 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go-micro.dev/v4 v4.1.0 h1:XXZWlKhSpkQZTvPKcXRP5JvJoqbVhV+p/UUIfdVgN7E=
go-micro.dev/v4 v4.1.0/go.mod h1:XTEJj5ILOBW+2ndGDG56r8fBXZ8hmsVaIaS1K5zwj+s=
go-micro.dev/v4 v4.2.1 h1:1E+zymteWxvDLpo4EDixRmXC+ELOAyFGfOdO60ScVbU=
go-micro.dev/v4 v4.2.1/go.mod h1:XTEJj5ILOBW+2ndGDG56r8fBXZ8hmsVaIaS1K5zwj+s=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
@ -546,7 +543,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@ -555,7 +551,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -724,7 +719,6 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -766,8 +760,8 @@ google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8 h1:XosVttQUxX8erNhEruTu053/VchgYuksoS9Bj/OITjU=
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c h1:FqrtZMB5Wr+/RecOM3uPJNPfWR8Upb5hAPnt7PU6i4k=
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@ -800,7 +794,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=

View File

@ -363,6 +363,8 @@ func (g *micro) generateClientMethod(reqServ, servName, serviceDescVar string, m
if !method.GetClientStreaming() {
g.P("if err := stream.Send(in); err != nil { return nil, err }")
// TODO: currently only grpc support CloseSend
// g.P("if err := stream.CloseSend(); err != nil { return nil, err }")
}
g.P("return &", streamType, "{stream}, nil")
@ -377,6 +379,7 @@ func (g *micro) generateClientMethod(reqServ, servName, serviceDescVar string, m
g.P("Context() context.Context")
g.P("SendMsg(interface{}) error")
g.P("RecvMsg(interface{}) error")
g.P("CloseSend() error")
g.P("Close() error")
if genSend {
@ -393,6 +396,11 @@ func (g *micro) generateClientMethod(reqServ, servName, serviceDescVar string, m
g.P("}")
g.P()
g.P("func (x *", streamType, ") CloseSend() error {")
g.P("return x.stream.CloseSend()")
g.P("}")
g.P()
g.P("func (x *", streamType, ") Close() error {")
g.P("return x.stream.Close()")
g.P("}")

View File

@ -4,25 +4,35 @@ go 1.16
replace (
github.com/asim/go-micro/plugins/client/grpc/v4 => ../plugins/client/grpc
github.com/asim/go-micro/plugins/client/http/v4 => ../plugins/client/http
github.com/asim/go-micro/plugins/config/encoder/toml/v4 => ../plugins/config/encoder/toml
github.com/asim/go-micro/plugins/config/encoder/yaml/v4 => ../plugins/config/encoder/yaml
github.com/asim/go-micro/plugins/config/source/grpc/v4 => ../plugins/config/source/grpc
github.com/asim/go-micro/plugins/server/grpc/v4 => ../plugins/server/grpc
github.com/asim/go-micro/plugins/server/http/v4 => ../plugins/server/http
github.com/asim/go-micro/plugins/transport/grpc/v4 => ../plugins/transport/grpc
github.com/asim/go-micro/plugins/wrapper/select/roundrobin/v4 => ../plugins/wrapper/select/roundrobin
github.com/asim/go-micro/plugins/wrapper/select/shard/v4 => ../plugins/wrapper/select/shard
go-micro.dev/v4 => ../../go-micro
)
require (
github.com/asim/go-micro/plugins/client/http/v4 v4.0.0-20211022143028-f96b48dad9f9
github.com/asim/go-micro/plugins/config/encoder/toml/v4 v4.0.0-20211022143028-f96b48dad9f9
github.com/asim/go-micro/plugins/config/encoder/yaml/v4 v4.0.0-20211022143028-f96b48dad9f9
github.com/asim/go-micro/plugins/config/source/grpc/v4 v4.0.0-20211022143028-f96b48dad9f9
github.com/asim/go-micro/plugins/server/http/v4 v4.0.0-20211022143028-f96b48dad9f9
github.com/asim/go-micro/plugins/wrapper/select/roundrobin/v4 v4.0.0-20211022143028-f96b48dad9f9
github.com/asim/go-micro/plugins/wrapper/select/shard/v4 v4.0.0-20211022143028-f96b48dad9f9
github.com/asim/go-micro/plugins/client/grpc/v4 v4.0.0-20211019191242-9edc569e68bb
github.com/asim/go-micro/plugins/client/http/v4 v4.0.0-00010101000000-000000000000
github.com/asim/go-micro/plugins/config/encoder/toml/v4 v4.0.0-00010101000000-000000000000
github.com/asim/go-micro/plugins/config/encoder/yaml/v4 v4.0.0-00010101000000-000000000000
github.com/asim/go-micro/plugins/config/source/grpc/v4 v4.0.0-00010101000000-000000000000
github.com/asim/go-micro/plugins/server/grpc/v4 v4.0.0-00010101000000-000000000000
github.com/asim/go-micro/plugins/server/http/v4 v4.0.0-00010101000000-000000000000
github.com/asim/go-micro/plugins/wrapper/select/roundrobin/v4 v4.0.0-00010101000000-000000000000
github.com/asim/go-micro/plugins/wrapper/select/shard/v4 v4.0.0-00010101000000-000000000000
github.com/gin-gonic/gin v1.7.4
github.com/golang/glog v1.0.0
github.com/golang/protobuf v1.5.2
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/pborman/uuid v1.2.1
github.com/urfave/cli/v2 v2.3.0
go-micro.dev/v4 v4.1.0
go-micro.dev/v4 v4.2.1
golang.org/x/net v0.0.0-20211020060615-d418f374d309
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c
google.golang.org/grpc v1.41.0

View File

@ -70,22 +70,6 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asim/go-micro/plugins/client/http/v4 v4.0.0-20211022143028-f96b48dad9f9 h1:17x43QitBDfbMjtFcpI2ecAc5PpEDdhNjtiotjqYKq8=
github.com/asim/go-micro/plugins/client/http/v4 v4.0.0-20211022143028-f96b48dad9f9/go.mod h1:eCRnBm4m255UbIZw2tabc+wVZQ3ZRP8MWkRbn0MhMbE=
github.com/asim/go-micro/plugins/config/encoder/toml/v4 v4.0.0-20211022143028-f96b48dad9f9 h1:OCoe8T41NrRb8gL/2Q3norzCFVubygzzkoeF46YU+XI=
github.com/asim/go-micro/plugins/config/encoder/toml/v4 v4.0.0-20211022143028-f96b48dad9f9/go.mod h1:Hi2yzGSStKJbJo+9+EpXMwUi8KPd4hLgX4mOrz8c0oA=
github.com/asim/go-micro/plugins/config/encoder/yaml/v4 v4.0.0-20211022143028-f96b48dad9f9 h1:n8EoXmlUJp0IkdUiPUysNM6bJ0QFWdM18oY6EOTy5PY=
github.com/asim/go-micro/plugins/config/encoder/yaml/v4 v4.0.0-20211022143028-f96b48dad9f9/go.mod h1:DJsLvPsBo+CNTCPLejskeLjRupUWFF+ypQAEkUhw4iI=
github.com/asim/go-micro/plugins/config/source/grpc/v4 v4.0.0-20211022143028-f96b48dad9f9 h1:mIgRuPdmQJbQKY7wkRRPyzKbcSEwkO1x8C9T9EOp1Bo=
github.com/asim/go-micro/plugins/config/source/grpc/v4 v4.0.0-20211022143028-f96b48dad9f9/go.mod h1:8WKLbh9L7FP4RViRq3S1CZ7nv0mdapt1Al9w91j0Cjk=
github.com/asim/go-micro/plugins/registry/memory/v4 v4.0.0-20211013123123-62801c3d6883 h1:Kt/XROVWpqglcjjiEq26KSwDYhSLsGL6NAEaukteuvc=
github.com/asim/go-micro/plugins/registry/memory/v4 v4.0.0-20211013123123-62801c3d6883/go.mod h1:cSvG1suZrBwXQZm1H+v4ZHSrDxmGqJO4RV5O1gpmllM=
github.com/asim/go-micro/plugins/server/http/v4 v4.0.0-20211022143028-f96b48dad9f9 h1:SW0nzvYDIyBFMp3ssny7+rtBcbNPQfpMYTXegnJ1Wt0=
github.com/asim/go-micro/plugins/server/http/v4 v4.0.0-20211022143028-f96b48dad9f9/go.mod h1:IJBO19ayd3T0SO72e7kcW2zN3RxaeI1zYEtWvQfc67M=
github.com/asim/go-micro/plugins/wrapper/select/roundrobin/v4 v4.0.0-20211022143028-f96b48dad9f9 h1:RBORITx0x74gDZTk+tohG+nbDFIhgcyPmLUqflWSxGA=
github.com/asim/go-micro/plugins/wrapper/select/roundrobin/v4 v4.0.0-20211022143028-f96b48dad9f9/go.mod h1:g3/YAex/PPKlfludcWp/NLqHbTUUQY5HGjCgsKGgOok=
github.com/asim/go-micro/plugins/wrapper/select/shard/v4 v4.0.0-20211022143028-f96b48dad9f9 h1:53epXCMQs/5BEHxoV4C0HxQhEcMB+eoiiU5ic0uosHQ=
github.com/asim/go-micro/plugins/wrapper/select/shard/v4 v4.0.0-20211022143028-f96b48dad9f9/go.mod h1:V0bMYEIWuaB+TdpgrsYiLUg708JwSeX8whK65tT0J6g=
github.com/aws/aws-sdk-go v1.37.27/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@ -842,6 +826,8 @@ google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20211020151524-b7c3a969101a/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c h1:FqrtZMB5Wr+/RecOM3uPJNPfWR8Upb5hAPnt7PU6i4k=
google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
@ -861,6 +847,8 @@ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
google.golang.org/grpc/examples v0.0.0-20211020220737-f00baa6c3c84 h1:vTEaoYojw/smuQT/Fva/AX+2Bnla97/oRbY75XFhg40=
google.golang.org/grpc/examples v0.0.0-20211020220737-f00baa6c3c84/go.mod h1:gID3PKrg7pWKntu9Ss6zTLJ0ttC0X9IHgREOCZwbCVU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -869,6 +857,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=

View File

@ -0,0 +1,26 @@
# Description
This example is translate [go grpc example](https://grpc.io/docs/languages/go/basics/) into go-micro.
You can also find the orignal codes in [github.com/grpc/grpc-go](https://github.com/grpc/grpc-go/tree/master/examples/route_guide).
# Run the sample code
## Protobuf
```shell
protoc --go_out=proto --micro_out=proto proto/route_guide.proto
```
## Server
```shell
cd stream/gprc/server
go run .
```
## Client
```shell
cd stream/client
go run main.go
```

View File

@ -0,0 +1,161 @@
package main
import (
"context"
"io"
"math/rand"
"time"
pb "github.com/asim/go-micro/examples/v4/stream/grpc/proto"
"github.com/asim/go-micro/plugins/client/grpc/v4"
"go-micro.dev/v4"
"go-micro.dev/v4/logger"
)
func main() {
srv := micro.NewService(
micro.Client(grpc.NewClient()),
micro.Name("stream-client"),
)
srv.Init()
client := pb.NewRouteGuideService("stream-server", srv.Client())
for {
// Looking for a valid feature
printFeature(client, &pb.Point{Latitude: 409146138, Longitude: -746188906})
// Feature missing.
printFeature(client, &pb.Point{Latitude: 0, Longitude: 0})
// Looking for features between 40, -75 and 42, -73.
printFeatures(client, &pb.Rectangle{
Lo: &pb.Point{Latitude: 400000000, Longitude: -750000000},
Hi: &pb.Point{Latitude: 420000000, Longitude: -730000000},
})
// RecordRoute
runRecordRoute(client)
// RouteChat
runRouteChat(client)
time.Sleep(time.Second)
}
}
// printFeature gets the feature for the given point.
func printFeature(client pb.RouteGuideService, point *pb.Point) {
logger.Info("Getting feature for point (%d, %d)", point.Latitude, point.Longitude)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
feature, err := client.GetFeature(ctx, point)
if err != nil {
logger.Fatal(err)
}
logger.Info(feature)
}
// printFeatures lists all the features within the given bounding Rectangle.
func printFeatures(client pb.RouteGuideService, rect *pb.Rectangle) {
logger.Infof("Looking for features within %v", rect)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
stream, err := client.ListFeatures(ctx, rect)
if err != nil {
logger.Fatal(err)
}
// IMPORTANT: do not forgot to close stream
defer stream.Close()
for {
feature, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
logger.Fatal(err)
}
logger.Infof("Feature: name: %q, point:(%v, %v)", feature.GetName(),
feature.GetLocation().GetLatitude(), feature.GetLocation().GetLongitude())
}
}
// runRecordRoute sends a sequence of points to server and expects to get a RouteSummary from server.
func runRecordRoute(client pb.RouteGuideService) {
// Create a random number of random points
r := rand.New(rand.NewSource(time.Now().UnixNano()))
pointCount := int(r.Int31n(100)) + 2 // Traverse at least two points
var points []*pb.Point
for i := 0; i < pointCount; i++ {
points = append(points, randomPoint(r))
}
logger.Infof("Traversing %d points.", len(points))
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
stream, err := client.RecordRoute(ctx)
if err != nil {
logger.Fatal(err)
}
// IMPORTANT: do not forgot to close stream
defer stream.Close()
for _, point := range points {
if err := stream.Send(point); err != nil {
logger.Fatal(err)
}
}
if err := stream.CloseSend(); err != nil {
logger.Fatal(err)
}
summary := pb.RouteSummary{}
if err := stream.RecvMsg(&summary); err != nil {
logger.Fatal(err)
}
logger.Infof("Route summary: %v", &summary)
}
// runRouteChat receives a sequence of route notes, while sending notes for various locations.
func runRouteChat(client pb.RouteGuideService) {
notes := []*pb.RouteNote{
{Location: &pb.Point{Latitude: 0, Longitude: 1}, Message: "First message"},
{Location: &pb.Point{Latitude: 0, Longitude: 2}, Message: "Second message"},
{Location: &pb.Point{Latitude: 0, Longitude: 3}, Message: "Third message"},
{Location: &pb.Point{Latitude: 0, Longitude: 1}, Message: "Fourth message"},
{Location: &pb.Point{Latitude: 0, Longitude: 2}, Message: "Fifth message"},
{Location: &pb.Point{Latitude: 0, Longitude: 3}, Message: "Sixth message"},
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
stream, err := client.RouteChat(ctx)
if err != nil {
logger.Fatal(err)
}
// IMPORTANT: do not forgot to close stream
defer stream.Close()
waitc := make(chan struct{})
go func() {
for {
in, err := stream.Recv()
if err == io.EOF {
// read done.
close(waitc)
break
}
if err != nil {
logger.Fatal(err)
}
logger.Infof("Got message %s at point(%d, %d)", in.Message, in.Location.Latitude, in.Location.Longitude)
}
}()
for _, note := range notes {
if err := stream.Send(note); err != nil {
logger.Fatal(err)
}
}
if err := stream.CloseSend(); err != nil {
logger.Fatal(err)
}
<-waitc
}
func randomPoint(r *rand.Rand) *pb.Point {
lat := (r.Int31n(180) - 90) * 1e7
long := (r.Int31n(360) - 180) * 1e7
return &pb.Point{Latitude: lat, Longitude: long}
}

View File

@ -0,0 +1,514 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.15.6
// source: proto/route_guide.proto
package proto
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// Points are represented as latitude-longitude pairs in the E7 representation
// (degrees multiplied by 10**7 and rounded to the nearest integer).
// Latitudes should be in the range +/- 90 degrees and longitude should be in
// the range +/- 180 degrees (inclusive).
type Point struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Latitude int32 `protobuf:"varint,1,opt,name=latitude,proto3" json:"latitude,omitempty"`
Longitude int32 `protobuf:"varint,2,opt,name=longitude,proto3" json:"longitude,omitempty"`
}
func (x *Point) Reset() {
*x = Point{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_route_guide_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Point) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Point) ProtoMessage() {}
func (x *Point) ProtoReflect() protoreflect.Message {
mi := &file_proto_route_guide_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Point.ProtoReflect.Descriptor instead.
func (*Point) Descriptor() ([]byte, []int) {
return file_proto_route_guide_proto_rawDescGZIP(), []int{0}
}
func (x *Point) GetLatitude() int32 {
if x != nil {
return x.Latitude
}
return 0
}
func (x *Point) GetLongitude() int32 {
if x != nil {
return x.Longitude
}
return 0
}
// A latitude-longitude rectangle, represented as two diagonally opposite
// points "lo" and "hi".
type Rectangle struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// One corner of the rectangle.
Lo *Point `protobuf:"bytes,1,opt,name=lo,proto3" json:"lo,omitempty"`
// The other corner of the rectangle.
Hi *Point `protobuf:"bytes,2,opt,name=hi,proto3" json:"hi,omitempty"`
}
func (x *Rectangle) Reset() {
*x = Rectangle{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_route_guide_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Rectangle) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Rectangle) ProtoMessage() {}
func (x *Rectangle) ProtoReflect() protoreflect.Message {
mi := &file_proto_route_guide_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Rectangle.ProtoReflect.Descriptor instead.
func (*Rectangle) Descriptor() ([]byte, []int) {
return file_proto_route_guide_proto_rawDescGZIP(), []int{1}
}
func (x *Rectangle) GetLo() *Point {
if x != nil {
return x.Lo
}
return nil
}
func (x *Rectangle) GetHi() *Point {
if x != nil {
return x.Hi
}
return nil
}
// A feature names something at a given point.
//
// If a feature could not be named, the name is empty.
type Feature struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The name of the feature.
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// The point where the feature is detected.
Location *Point `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"`
}
func (x *Feature) Reset() {
*x = Feature{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_route_guide_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Feature) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Feature) ProtoMessage() {}
func (x *Feature) ProtoReflect() protoreflect.Message {
mi := &file_proto_route_guide_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Feature.ProtoReflect.Descriptor instead.
func (*Feature) Descriptor() ([]byte, []int) {
return file_proto_route_guide_proto_rawDescGZIP(), []int{2}
}
func (x *Feature) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *Feature) GetLocation() *Point {
if x != nil {
return x.Location
}
return nil
}
// A RouteNote is a message sent while at a given point.
type RouteNote struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The location from which the message is sent.
Location *Point `protobuf:"bytes,1,opt,name=location,proto3" json:"location,omitempty"`
// The message to be sent.
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *RouteNote) Reset() {
*x = RouteNote{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_route_guide_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RouteNote) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RouteNote) ProtoMessage() {}
func (x *RouteNote) ProtoReflect() protoreflect.Message {
mi := &file_proto_route_guide_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RouteNote.ProtoReflect.Descriptor instead.
func (*RouteNote) Descriptor() ([]byte, []int) {
return file_proto_route_guide_proto_rawDescGZIP(), []int{3}
}
func (x *RouteNote) GetLocation() *Point {
if x != nil {
return x.Location
}
return nil
}
func (x *RouteNote) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
// A RouteSummary is received in response to a RecordRoute rpc.
//
// It contains the number of individual points received, the number of
// detected features, and the total distance covered as the cumulative sum of
// the distance between each point.
type RouteSummary struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The number of points received.
PointCount int32 `protobuf:"varint,1,opt,name=point_count,json=pointCount,proto3" json:"point_count,omitempty"`
// The number of known features passed while traversing the route.
FeatureCount int32 `protobuf:"varint,2,opt,name=feature_count,json=featureCount,proto3" json:"feature_count,omitempty"`
// The distance covered in metres.
Distance int32 `protobuf:"varint,3,opt,name=distance,proto3" json:"distance,omitempty"`
// The duration of the traversal in seconds.
ElapsedTime int32 `protobuf:"varint,4,opt,name=elapsed_time,json=elapsedTime,proto3" json:"elapsed_time,omitempty"`
}
func (x *RouteSummary) Reset() {
*x = RouteSummary{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_route_guide_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RouteSummary) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RouteSummary) ProtoMessage() {}
func (x *RouteSummary) ProtoReflect() protoreflect.Message {
mi := &file_proto_route_guide_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RouteSummary.ProtoReflect.Descriptor instead.
func (*RouteSummary) Descriptor() ([]byte, []int) {
return file_proto_route_guide_proto_rawDescGZIP(), []int{4}
}
func (x *RouteSummary) GetPointCount() int32 {
if x != nil {
return x.PointCount
}
return 0
}
func (x *RouteSummary) GetFeatureCount() int32 {
if x != nil {
return x.FeatureCount
}
return 0
}
func (x *RouteSummary) GetDistance() int32 {
if x != nil {
return x.Distance
}
return 0
}
func (x *RouteSummary) GetElapsedTime() int32 {
if x != nil {
return x.ElapsedTime
}
return 0
}
var File_proto_route_guide_proto protoreflect.FileDescriptor
var file_proto_route_guide_proto_rawDesc = []byte{
0x0a, 0x17, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x67, 0x75,
0x69, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x22, 0x41, 0x0a, 0x05, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x74,
0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6c, 0x61, 0x74,
0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75,
0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74,
0x75, 0x64, 0x65, 0x22, 0x47, 0x0a, 0x09, 0x52, 0x65, 0x63, 0x74, 0x61, 0x6e, 0x67, 0x6c, 0x65,
0x12, 0x1c, 0x0a, 0x02, 0x6c, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x02, 0x6c, 0x6f, 0x12, 0x1c,
0x0a, 0x02, 0x68, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x02, 0x68, 0x69, 0x22, 0x47, 0x0a, 0x07,
0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x08, 0x6c,
0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6c, 0x6f, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x4f, 0x0a, 0x09, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x4e, 0x6f,
0x74, 0x65, 0x12, 0x28, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x6f, 0x69,
0x6e, 0x74, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x0c, 0x52, 0x6f, 0x75, 0x74, 0x65,
0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x6f, 0x69, 0x6e, 0x74,
0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x70, 0x6f,
0x69, 0x6e, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x65, 0x61, 0x74,
0x75, 0x72, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
0x0c, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a,
0x08, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52,
0x08, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x6c, 0x61,
0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52,
0x0b, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x32, 0xdd, 0x01, 0x0a,
0x0a, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x47, 0x75, 0x69, 0x64, 0x65, 0x12, 0x2c, 0x0a, 0x0a, 0x47,
0x65, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x00, 0x12, 0x34, 0x0a, 0x0c, 0x4c, 0x69, 0x73,
0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2e, 0x52, 0x65, 0x63, 0x74, 0x61, 0x6e, 0x67, 0x6c, 0x65, 0x1a, 0x0e, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12,
0x34, 0x0a, 0x0b, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x0c,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x1a, 0x13, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72,
0x79, 0x22, 0x00, 0x28, 0x01, 0x12, 0x35, 0x0a, 0x09, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x43, 0x68,
0x61, 0x74, 0x12, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65,
0x4e, 0x6f, 0x74, 0x65, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x6f, 0x75,
0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x0a, 0x5a, 0x08,
0x2e, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proto_route_guide_proto_rawDescOnce sync.Once
file_proto_route_guide_proto_rawDescData = file_proto_route_guide_proto_rawDesc
)
func file_proto_route_guide_proto_rawDescGZIP() []byte {
file_proto_route_guide_proto_rawDescOnce.Do(func() {
file_proto_route_guide_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_route_guide_proto_rawDescData)
})
return file_proto_route_guide_proto_rawDescData
}
var file_proto_route_guide_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_proto_route_guide_proto_goTypes = []interface{}{
(*Point)(nil), // 0: proto.Point
(*Rectangle)(nil), // 1: proto.Rectangle
(*Feature)(nil), // 2: proto.Feature
(*RouteNote)(nil), // 3: proto.RouteNote
(*RouteSummary)(nil), // 4: proto.RouteSummary
}
var file_proto_route_guide_proto_depIdxs = []int32{
0, // 0: proto.Rectangle.lo:type_name -> proto.Point
0, // 1: proto.Rectangle.hi:type_name -> proto.Point
0, // 2: proto.Feature.location:type_name -> proto.Point
0, // 3: proto.RouteNote.location:type_name -> proto.Point
0, // 4: proto.RouteGuide.GetFeature:input_type -> proto.Point
1, // 5: proto.RouteGuide.ListFeatures:input_type -> proto.Rectangle
0, // 6: proto.RouteGuide.RecordRoute:input_type -> proto.Point
3, // 7: proto.RouteGuide.RouteChat:input_type -> proto.RouteNote
2, // 8: proto.RouteGuide.GetFeature:output_type -> proto.Feature
2, // 9: proto.RouteGuide.ListFeatures:output_type -> proto.Feature
4, // 10: proto.RouteGuide.RecordRoute:output_type -> proto.RouteSummary
3, // 11: proto.RouteGuide.RouteChat:output_type -> proto.RouteNote
8, // [8:12] is the sub-list for method output_type
4, // [4:8] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_proto_route_guide_proto_init() }
func file_proto_route_guide_proto_init() {
if File_proto_route_guide_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proto_route_guide_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Point); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_route_guide_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Rectangle); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_route_guide_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Feature); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_route_guide_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RouteNote); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_route_guide_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RouteSummary); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proto_route_guide_proto_rawDesc,
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_proto_route_guide_proto_goTypes,
DependencyIndexes: file_proto_route_guide_proto_depIdxs,
MessageInfos: file_proto_route_guide_proto_msgTypes,
}.Build()
File_proto_route_guide_proto = out.File
file_proto_route_guide_proto_rawDesc = nil
file_proto_route_guide_proto_goTypes = nil
file_proto_route_guide_proto_depIdxs = nil
}

View File

@ -0,0 +1,420 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: proto/route_guide.proto
package proto
import (
fmt "fmt"
proto "google.golang.org/protobuf/proto"
math "math"
)
import (
context "context"
api "go-micro.dev/v4/api"
client "go-micro.dev/v4/client"
server "go-micro.dev/v4/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for RouteGuide service
func NewRouteGuideEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for RouteGuide service
type RouteGuideService interface {
// A simple RPC.
//
// Obtains the feature at a given position.
//
// A feature with an empty name is returned if there's no feature at the given
// position.
GetFeature(ctx context.Context, in *Point, opts ...client.CallOption) (*Feature, error)
// A server-to-client streaming RPC.
//
// Obtains the Features available within the given Rectangle. Results are
// streamed rather than returned at once (e.g. in a response message with a
// repeated field), as the rectangle may cover a large area and contain a
// huge number of features.
ListFeatures(ctx context.Context, in *Rectangle, opts ...client.CallOption) (RouteGuide_ListFeaturesService, error)
// A client-to-server streaming RPC.
//
// Accepts a stream of Points on a route being traversed, returning a
// RouteSummary when traversal is completed.
RecordRoute(ctx context.Context, opts ...client.CallOption) (RouteGuide_RecordRouteService, error)
// A Bidirectional streaming RPC.
//
// Accepts a stream of RouteNotes sent while a route is being traversed,
// while receiving other RouteNotes (e.g. from other users).
RouteChat(ctx context.Context, opts ...client.CallOption) (RouteGuide_RouteChatService, error)
}
type routeGuideService struct {
c client.Client
name string
}
func NewRouteGuideService(name string, c client.Client) RouteGuideService {
return &routeGuideService{
c: c,
name: name,
}
}
func (c *routeGuideService) GetFeature(ctx context.Context, in *Point, opts ...client.CallOption) (*Feature, error) {
req := c.c.NewRequest(c.name, "RouteGuide.GetFeature", in)
out := new(Feature)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *routeGuideService) ListFeatures(ctx context.Context, in *Rectangle, opts ...client.CallOption) (RouteGuide_ListFeaturesService, error) {
req := c.c.NewRequest(c.name, "RouteGuide.ListFeatures", &Rectangle{})
stream, err := c.c.Stream(ctx, req, opts...)
if err != nil {
return nil, err
}
if err := stream.Send(in); err != nil {
return nil, err
}
if err := stream.CloseSend(); err != nil {
return nil, err
}
return &routeGuideServiceListFeatures{stream}, nil
}
type RouteGuide_ListFeaturesService interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
CloseSend() error
Close() error
Recv() (*Feature, error)
}
type routeGuideServiceListFeatures struct {
stream client.Stream
}
func (x *routeGuideServiceListFeatures) CloseSend() error {
return x.stream.CloseSend()
}
func (x *routeGuideServiceListFeatures) Close() error {
return x.stream.Close()
}
func (x *routeGuideServiceListFeatures) Context() context.Context {
return x.stream.Context()
}
func (x *routeGuideServiceListFeatures) SendMsg(m interface{}) error {
return x.stream.Send(m)
}
func (x *routeGuideServiceListFeatures) RecvMsg(m interface{}) error {
return x.stream.Recv(m)
}
func (x *routeGuideServiceListFeatures) Recv() (*Feature, error) {
m := new(Feature)
err := x.stream.Recv(m)
if err != nil {
return nil, err
}
return m, nil
}
func (c *routeGuideService) RecordRoute(ctx context.Context, opts ...client.CallOption) (RouteGuide_RecordRouteService, error) {
req := c.c.NewRequest(c.name, "RouteGuide.RecordRoute", &Point{})
stream, err := c.c.Stream(ctx, req, opts...)
if err != nil {
return nil, err
}
return &routeGuideServiceRecordRoute{stream}, nil
}
type RouteGuide_RecordRouteService interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
CloseSend() error
Close() error
Send(*Point) error
}
type routeGuideServiceRecordRoute struct {
stream client.Stream
}
func (x *routeGuideServiceRecordRoute) CloseSend() error {
return x.stream.CloseSend()
}
func (x *routeGuideServiceRecordRoute) Close() error {
return x.stream.Close()
}
func (x *routeGuideServiceRecordRoute) Context() context.Context {
return x.stream.Context()
}
func (x *routeGuideServiceRecordRoute) SendMsg(m interface{}) error {
return x.stream.Send(m)
}
func (x *routeGuideServiceRecordRoute) RecvMsg(m interface{}) error {
return x.stream.Recv(m)
}
func (x *routeGuideServiceRecordRoute) Send(m *Point) error {
return x.stream.Send(m)
}
func (c *routeGuideService) RouteChat(ctx context.Context, opts ...client.CallOption) (RouteGuide_RouteChatService, error) {
req := c.c.NewRequest(c.name, "RouteGuide.RouteChat", &RouteNote{})
stream, err := c.c.Stream(ctx, req, opts...)
if err != nil {
return nil, err
}
return &routeGuideServiceRouteChat{stream}, nil
}
type RouteGuide_RouteChatService interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
CloseSend() error
Close() error
Send(*RouteNote) error
Recv() (*RouteNote, error)
}
type routeGuideServiceRouteChat struct {
stream client.Stream
}
func (x *routeGuideServiceRouteChat) CloseSend() error {
return x.stream.CloseSend()
}
func (x *routeGuideServiceRouteChat) Close() error {
return x.stream.Close()
}
func (x *routeGuideServiceRouteChat) Context() context.Context {
return x.stream.Context()
}
func (x *routeGuideServiceRouteChat) SendMsg(m interface{}) error {
return x.stream.Send(m)
}
func (x *routeGuideServiceRouteChat) RecvMsg(m interface{}) error {
return x.stream.Recv(m)
}
func (x *routeGuideServiceRouteChat) Send(m *RouteNote) error {
return x.stream.Send(m)
}
func (x *routeGuideServiceRouteChat) Recv() (*RouteNote, error) {
m := new(RouteNote)
err := x.stream.Recv(m)
if err != nil {
return nil, err
}
return m, nil
}
// Server API for RouteGuide service
type RouteGuideHandler interface {
// A simple RPC.
//
// Obtains the feature at a given position.
//
// A feature with an empty name is returned if there's no feature at the given
// position.
GetFeature(context.Context, *Point, *Feature) error
// A server-to-client streaming RPC.
//
// Obtains the Features available within the given Rectangle. Results are
// streamed rather than returned at once (e.g. in a response message with a
// repeated field), as the rectangle may cover a large area and contain a
// huge number of features.
ListFeatures(context.Context, *Rectangle, RouteGuide_ListFeaturesStream) error
// A client-to-server streaming RPC.
//
// Accepts a stream of Points on a route being traversed, returning a
// RouteSummary when traversal is completed.
RecordRoute(context.Context, RouteGuide_RecordRouteStream) error
// A Bidirectional streaming RPC.
//
// Accepts a stream of RouteNotes sent while a route is being traversed,
// while receiving other RouteNotes (e.g. from other users).
RouteChat(context.Context, RouteGuide_RouteChatStream) error
}
func RegisterRouteGuideHandler(s server.Server, hdlr RouteGuideHandler, opts ...server.HandlerOption) error {
type routeGuide interface {
GetFeature(ctx context.Context, in *Point, out *Feature) error
ListFeatures(ctx context.Context, stream server.Stream) error
RecordRoute(ctx context.Context, stream server.Stream) error
RouteChat(ctx context.Context, stream server.Stream) error
}
type RouteGuide struct {
routeGuide
}
h := &routeGuideHandler{hdlr}
return s.Handle(s.NewHandler(&RouteGuide{h}, opts...))
}
type routeGuideHandler struct {
RouteGuideHandler
}
func (h *routeGuideHandler) GetFeature(ctx context.Context, in *Point, out *Feature) error {
return h.RouteGuideHandler.GetFeature(ctx, in, out)
}
func (h *routeGuideHandler) ListFeatures(ctx context.Context, stream server.Stream) error {
m := new(Rectangle)
if err := stream.Recv(m); err != nil {
return err
}
return h.RouteGuideHandler.ListFeatures(ctx, m, &routeGuideListFeaturesStream{stream})
}
type RouteGuide_ListFeaturesStream interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
Close() error
Send(*Feature) error
}
type routeGuideListFeaturesStream struct {
stream server.Stream
}
func (x *routeGuideListFeaturesStream) Close() error {
return x.stream.Close()
}
func (x *routeGuideListFeaturesStream) Context() context.Context {
return x.stream.Context()
}
func (x *routeGuideListFeaturesStream) SendMsg(m interface{}) error {
return x.stream.Send(m)
}
func (x *routeGuideListFeaturesStream) RecvMsg(m interface{}) error {
return x.stream.Recv(m)
}
func (x *routeGuideListFeaturesStream) Send(m *Feature) error {
return x.stream.Send(m)
}
func (h *routeGuideHandler) RecordRoute(ctx context.Context, stream server.Stream) error {
return h.RouteGuideHandler.RecordRoute(ctx, &routeGuideRecordRouteStream{stream})
}
type RouteGuide_RecordRouteStream interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
Close() error
Recv() (*Point, error)
}
type routeGuideRecordRouteStream struct {
stream server.Stream
}
func (x *routeGuideRecordRouteStream) Close() error {
return x.stream.Close()
}
func (x *routeGuideRecordRouteStream) Context() context.Context {
return x.stream.Context()
}
func (x *routeGuideRecordRouteStream) SendMsg(m interface{}) error {
return x.stream.Send(m)
}
func (x *routeGuideRecordRouteStream) RecvMsg(m interface{}) error {
return x.stream.Recv(m)
}
func (x *routeGuideRecordRouteStream) Recv() (*Point, error) {
m := new(Point)
if err := x.stream.Recv(m); err != nil {
return nil, err
}
return m, nil
}
func (h *routeGuideHandler) RouteChat(ctx context.Context, stream server.Stream) error {
return h.RouteGuideHandler.RouteChat(ctx, &routeGuideRouteChatStream{stream})
}
type RouteGuide_RouteChatStream interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
Close() error
Send(*RouteNote) error
Recv() (*RouteNote, error)
}
type routeGuideRouteChatStream struct {
stream server.Stream
}
func (x *routeGuideRouteChatStream) Close() error {
return x.stream.Close()
}
func (x *routeGuideRouteChatStream) Context() context.Context {
return x.stream.Context()
}
func (x *routeGuideRouteChatStream) SendMsg(m interface{}) error {
return x.stream.Send(m)
}
func (x *routeGuideRouteChatStream) RecvMsg(m interface{}) error {
return x.stream.Recv(m)
}
func (x *routeGuideRouteChatStream) Send(m *RouteNote) error {
return x.stream.Send(m)
}
func (x *routeGuideRouteChatStream) Recv() (*RouteNote, error) {
m := new(RouteNote)
if err := x.stream.Recv(m); err != nil {
return nil, err
}
return m, nil
}

View File

@ -0,0 +1,94 @@
syntax = "proto3";
option go_package = "../proto";
package proto;
// Interface exported by the server.
service RouteGuide {
// A simple RPC.
//
// Obtains the feature at a given position.
//
// A feature with an empty name is returned if there's no feature at the given
// position.
rpc GetFeature(Point) returns (Feature) {}
// A server-to-client streaming RPC.
//
// Obtains the Features available within the given Rectangle. Results are
// streamed rather than returned at once (e.g. in a response message with a
// repeated field), as the rectangle may cover a large area and contain a
// huge number of features.
rpc ListFeatures(Rectangle) returns (stream Feature) {}
// A client-to-server streaming RPC.
//
// Accepts a stream of Points on a route being traversed, returning a
// RouteSummary when traversal is completed.
rpc RecordRoute(stream Point) returns (RouteSummary) {}
// A Bidirectional streaming RPC.
//
// Accepts a stream of RouteNotes sent while a route is being traversed,
// while receiving other RouteNotes (e.g. from other users).
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}
// Points are represented as latitude-longitude pairs in the E7 representation
// (degrees multiplied by 10**7 and rounded to the nearest integer).
// Latitudes should be in the range +/- 90 degrees and longitude should be in
// the range +/- 180 degrees (inclusive).
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
// A latitude-longitude rectangle, represented as two diagonally opposite
// points "lo" and "hi".
message Rectangle {
// One corner of the rectangle.
Point lo = 1;
// The other corner of the rectangle.
Point hi = 2;
}
// A feature names something at a given point.
//
// If a feature could not be named, the name is empty.
message Feature {
// The name of the feature.
string name = 1;
// The point where the feature is detected.
Point location = 2;
}
// A RouteNote is a message sent while at a given point.
message RouteNote {
// The location from which the message is sent.
Point location = 1;
// The message to be sent.
string message = 2;
}
// A RouteSummary is received in response to a RecordRoute rpc.
//
// It contains the number of individual points received, the number of
// detected features, and the total distance covered as the cumulative sum of
// the distance between each point.
message RouteSummary {
// The number of points received.
int32 point_count = 1;
// The number of known features passed while traversing the route.
int32 feature_count = 2;
// The distance covered in metres.
int32 distance = 3;
// The duration of the traversal in seconds.
int32 elapsed_time = 4;
}

View File

@ -0,0 +1,661 @@
package main
import (
"encoding/json"
"fmt"
"math"
pb "github.com/asim/go-micro/examples/v4/stream/grpc/proto"
)
var features []*pb.Feature
func init() {
if err := json.Unmarshal(testingData, &features); err != nil {
panic(err)
}
}
func inRange(point *pb.Point, rect *pb.Rectangle) bool {
left := math.Min(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))
right := math.Max(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))
top := math.Max(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))
bottom := math.Min(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))
if float64(point.Longitude) >= left &&
float64(point.Longitude) <= right &&
float64(point.Latitude) >= bottom &&
float64(point.Latitude) <= top {
return true
}
return false
}
func calcDistance(p1 *pb.Point, p2 *pb.Point) int32 {
const CordFactor float64 = 1e7
const R = float64(6371000) // earth radius in metres
lat1 := toRadians(float64(p1.Latitude) / CordFactor)
lat2 := toRadians(float64(p2.Latitude) / CordFactor)
lng1 := toRadians(float64(p1.Longitude) / CordFactor)
lng2 := toRadians(float64(p2.Longitude) / CordFactor)
dlat := lat2 - lat1
dlng := lng2 - lng1
a := math.Sin(dlat/2)*math.Sin(dlat/2) +
math.Cos(lat1)*math.Cos(lat2)*
math.Sin(dlng/2)*math.Sin(dlng/2)
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
distance := R * c
return int32(distance)
}
func toRadians(num float64) float64 {
return num * math.Pi / float64(180)
}
func serialize(point *pb.Point) string {
return fmt.Sprintf("%d %d", point.Latitude, point.Longitude)
}
var testingData = []byte(`[{
"location": {
"latitude": 407838351,
"longitude": -746143763
},
"name": "Patriots Path, Mendham, NJ 07945, USA"
}, {
"location": {
"latitude": 408122808,
"longitude": -743999179
},
"name": "101 New Jersey 10, Whippany, NJ 07981, USA"
}, {
"location": {
"latitude": 413628156,
"longitude": -749015468
},
"name": "U.S. 6, Shohola, PA 18458, USA"
}, {
"location": {
"latitude": 419999544,
"longitude": -740371136
},
"name": "5 Conners Road, Kingston, NY 12401, USA"
}, {
"location": {
"latitude": 414008389,
"longitude": -743951297
},
"name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA"
}, {
"location": {
"latitude": 419611318,
"longitude": -746524769
},
"name": "287 Flugertown Road, Livingston Manor, NY 12758, USA"
}, {
"location": {
"latitude": 406109563,
"longitude": -742186778
},
"name": "4001 Tremley Point Road, Linden, NJ 07036, USA"
}, {
"location": {
"latitude": 416802456,
"longitude": -742370183
},
"name": "352 South Mountain Road, Wallkill, NY 12589, USA"
}, {
"location": {
"latitude": 412950425,
"longitude": -741077389
},
"name": "Bailey Turn Road, Harriman, NY 10926, USA"
}, {
"location": {
"latitude": 412144655,
"longitude": -743949739
},
"name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA"
}, {
"location": {
"latitude": 415736605,
"longitude": -742847522
},
"name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA"
}, {
"location": {
"latitude": 413843930,
"longitude": -740501726
},
"name": "162 Merrill Road, Highland Mills, NY 10930, USA"
}, {
"location": {
"latitude": 410873075,
"longitude": -744459023
},
"name": "Clinton Road, West Milford, NJ 07480, USA"
}, {
"location": {
"latitude": 412346009,
"longitude": -744026814
},
"name": "16 Old Brook Lane, Warwick, NY 10990, USA"
}, {
"location": {
"latitude": 402948455,
"longitude": -747903913
},
"name": "3 Drake Lane, Pennington, NJ 08534, USA"
}, {
"location": {
"latitude": 406337092,
"longitude": -740122226
},
"name": "6324 8th Avenue, Brooklyn, NY 11220, USA"
}, {
"location": {
"latitude": 406421967,
"longitude": -747727624
},
"name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA"
}, {
"location": {
"latitude": 416318082,
"longitude": -749677716
},
"name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA"
}, {
"location": {
"latitude": 415301720,
"longitude": -748416257
},
"name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA"
}, {
"location": {
"latitude": 402647019,
"longitude": -747071791
},
"name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA"
}, {
"location": {
"latitude": 412567807,
"longitude": -741058078
},
"name": "New York State Reference Route 987E, Southfields, NY 10975, USA"
}, {
"location": {
"latitude": 416855156,
"longitude": -744420597
},
"name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA"
}, {
"location": {
"latitude": 404663628,
"longitude": -744820157
},
"name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA"
}, {
"location": {
"latitude": 407113723,
"longitude": -749746483
},
"name": ""
}, {
"location": {
"latitude": 402133926,
"longitude": -743613249
},
"name": ""
}, {
"location": {
"latitude": 400273442,
"longitude": -741220915
},
"name": ""
}, {
"location": {
"latitude": 411236786,
"longitude": -744070769
},
"name": ""
}, {
"location": {
"latitude": 411633782,
"longitude": -746784970
},
"name": "211-225 Plains Road, Augusta, NJ 07822, USA"
}, {
"location": {
"latitude": 415830701,
"longitude": -742952812
},
"name": ""
}, {
"location": {
"latitude": 413447164,
"longitude": -748712898
},
"name": "165 Pedersen Ridge Road, Milford, PA 18337, USA"
}, {
"location": {
"latitude": 405047245,
"longitude": -749800722
},
"name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA"
}, {
"location": {
"latitude": 418858923,
"longitude": -746156790
},
"name": ""
}, {
"location": {
"latitude": 417951888,
"longitude": -748484944
},
"name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA"
}, {
"location": {
"latitude": 407033786,
"longitude": -743977337
},
"name": "26 East 3rd Street, New Providence, NJ 07974, USA"
}, {
"location": {
"latitude": 417548014,
"longitude": -740075041
},
"name": ""
}, {
"location": {
"latitude": 410395868,
"longitude": -744972325
},
"name": ""
}, {
"location": {
"latitude": 404615353,
"longitude": -745129803
},
"name": ""
}, {
"location": {
"latitude": 406589790,
"longitude": -743560121
},
"name": "611 Lawrence Avenue, Westfield, NJ 07090, USA"
}, {
"location": {
"latitude": 414653148,
"longitude": -740477477
},
"name": "18 Lannis Avenue, New Windsor, NY 12553, USA"
}, {
"location": {
"latitude": 405957808,
"longitude": -743255336
},
"name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA"
}, {
"location": {
"latitude": 411733589,
"longitude": -741648093
},
"name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA"
}, {
"location": {
"latitude": 412676291,
"longitude": -742606606
},
"name": "1270 Lakes Road, Monroe, NY 10950, USA"
}, {
"location": {
"latitude": 409224445,
"longitude": -748286738
},
"name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA"
}, {
"location": {
"latitude": 406523420,
"longitude": -742135517
},
"name": "652 Garden Street, Elizabeth, NJ 07202, USA"
}, {
"location": {
"latitude": 401827388,
"longitude": -740294537
},
"name": "349 Sea Spray Court, Neptune City, NJ 07753, USA"
}, {
"location": {
"latitude": 410564152,
"longitude": -743685054
},
"name": "13-17 Stanley Street, West Milford, NJ 07480, USA"
}, {
"location": {
"latitude": 408472324,
"longitude": -740726046
},
"name": "47 Industrial Avenue, Teterboro, NJ 07608, USA"
}, {
"location": {
"latitude": 412452168,
"longitude": -740214052
},
"name": "5 White Oak Lane, Stony Point, NY 10980, USA"
}, {
"location": {
"latitude": 409146138,
"longitude": -746188906
},
"name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA"
}, {
"location": {
"latitude": 404701380,
"longitude": -744781745
},
"name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA"
}, {
"location": {
"latitude": 409642566,
"longitude": -746017679
},
"name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA"
}, {
"location": {
"latitude": 408031728,
"longitude": -748645385
},
"name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA"
}, {
"location": {
"latitude": 413700272,
"longitude": -742135189
},
"name": "367 Prospect Road, Chester, NY 10918, USA"
}, {
"location": {
"latitude": 404310607,
"longitude": -740282632
},
"name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA"
}, {
"location": {
"latitude": 409319800,
"longitude": -746201391
},
"name": "11 Ward Street, Mount Arlington, NJ 07856, USA"
}, {
"location": {
"latitude": 406685311,
"longitude": -742108603
},
"name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA"
}, {
"location": {
"latitude": 419018117,
"longitude": -749142781
},
"name": "43 Dreher Road, Roscoe, NY 12776, USA"
}, {
"location": {
"latitude": 412856162,
"longitude": -745148837
},
"name": "Swan Street, Pine Island, NY 10969, USA"
}, {
"location": {
"latitude": 416560744,
"longitude": -746721964
},
"name": "66 Pleasantview Avenue, Monticello, NY 12701, USA"
}, {
"location": {
"latitude": 405314270,
"longitude": -749836354
},
"name": ""
}, {
"location": {
"latitude": 414219548,
"longitude": -743327440
},
"name": ""
}, {
"location": {
"latitude": 415534177,
"longitude": -742900616
},
"name": "565 Winding Hills Road, Montgomery, NY 12549, USA"
}, {
"location": {
"latitude": 406898530,
"longitude": -749127080
},
"name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA"
}, {
"location": {
"latitude": 407586880,
"longitude": -741670168
},
"name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA"
}, {
"location": {
"latitude": 400106455,
"longitude": -742870190
},
"name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA"
}, {
"location": {
"latitude": 400066188,
"longitude": -746793294
},
"name": ""
}, {
"location": {
"latitude": 418803880,
"longitude": -744102673
},
"name": "40 Mountain Road, Napanoch, NY 12458, USA"
}, {
"location": {
"latitude": 414204288,
"longitude": -747895140
},
"name": ""
}, {
"location": {
"latitude": 414777405,
"longitude": -740615601
},
"name": ""
}, {
"location": {
"latitude": 415464475,
"longitude": -747175374
},
"name": "48 North Road, Forestburgh, NY 12777, USA"
}, {
"location": {
"latitude": 404062378,
"longitude": -746376177
},
"name": ""
}, {
"location": {
"latitude": 405688272,
"longitude": -749285130
},
"name": ""
}, {
"location": {
"latitude": 400342070,
"longitude": -748788996
},
"name": ""
}, {
"location": {
"latitude": 401809022,
"longitude": -744157964
},
"name": ""
}, {
"location": {
"latitude": 404226644,
"longitude": -740517141
},
"name": "9 Thompson Avenue, Leonardo, NJ 07737, USA"
}, {
"location": {
"latitude": 410322033,
"longitude": -747871659
},
"name": ""
}, {
"location": {
"latitude": 407100674,
"longitude": -747742727
},
"name": ""
}, {
"location": {
"latitude": 418811433,
"longitude": -741718005
},
"name": "213 Bush Road, Stone Ridge, NY 12484, USA"
}, {
"location": {
"latitude": 415034302,
"longitude": -743850945
},
"name": ""
}, {
"location": {
"latitude": 411349992,
"longitude": -743694161
},
"name": ""
}, {
"location": {
"latitude": 404839914,
"longitude": -744759616
},
"name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA"
}, {
"location": {
"latitude": 414638017,
"longitude": -745957854
},
"name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA"
}, {
"location": {
"latitude": 412127800,
"longitude": -740173578
},
"name": ""
}, {
"location": {
"latitude": 401263460,
"longitude": -747964303
},
"name": ""
}, {
"location": {
"latitude": 412843391,
"longitude": -749086026
},
"name": ""
}, {
"location": {
"latitude": 418512773,
"longitude": -743067823
},
"name": ""
}, {
"location": {
"latitude": 404318328,
"longitude": -740835638
},
"name": "42-102 Main Street, Belford, NJ 07718, USA"
}, {
"location": {
"latitude": 419020746,
"longitude": -741172328
},
"name": ""
}, {
"location": {
"latitude": 404080723,
"longitude": -746119569
},
"name": ""
}, {
"location": {
"latitude": 401012643,
"longitude": -744035134
},
"name": ""
}, {
"location": {
"latitude": 404306372,
"longitude": -741079661
},
"name": ""
}, {
"location": {
"latitude": 403966326,
"longitude": -748519297
},
"name": ""
}, {
"location": {
"latitude": 405002031,
"longitude": -748407866
},
"name": ""
}, {
"location": {
"latitude": 409532885,
"longitude": -742200683
},
"name": ""
}, {
"location": {
"latitude": 416851321,
"longitude": -742674555
},
"name": ""
}, {
"location": {
"latitude": 406411633,
"longitude": -741722051
},
"name": "3387 Richmond Terrace, Staten Island, NY 10303, USA"
}, {
"location": {
"latitude": 413069058,
"longitude": -744597778
},
"name": "261 Van Sickle Road, Goshen, NY 10924, USA"
}, {
"location": {
"latitude": 418465462,
"longitude": -746859398
},
"name": ""
}, {
"location": {
"latitude": 411733222,
"longitude": -744228360
},
"name": ""
}, {
"location": {
"latitude": 410248224,
"longitude": -747127767
},
"name": "3 Hasta Way, Newton, NJ 07860, USA"
}]`)

View File

@ -0,0 +1,114 @@
package main
import (
"context"
"io"
"sync"
"time"
pb "github.com/asim/go-micro/examples/v4/stream/grpc/proto"
"github.com/asim/go-micro/plugins/server/grpc/v4"
"go-micro.dev/v4"
"go-micro.dev/v4/logger"
"google.golang.org/protobuf/proto"
)
type server struct {
mu sync.Mutex
routeNotes map[string][]*pb.RouteNote
}
func main() {
srv := micro.NewService(
micro.Server(grpc.NewServer()),
micro.Name("stream-server"),
)
srv.Init()
pb.RegisterRouteGuideHandler(srv.Server(), &server{routeNotes: make(map[string][]*pb.RouteNote)})
if err := srv.Run(); err != nil {
logger.Fatal(err)
}
}
func (s *server) GetFeature(ctx context.Context, in *pb.Point, out *pb.Feature) error {
for _, f := range features {
if proto.Equal(f.Location, in) {
out.Location = f.Location
out.Name = f.Name
return nil
}
}
out.Location = in
return nil
}
func (s *server) ListFeatures(ctx context.Context, in *pb.Rectangle, stream pb.RouteGuide_ListFeaturesStream) error {
for _, feature := range features {
if inRange(feature.Location, in) {
if err := stream.Send(feature); err != nil {
return err
}
}
}
return nil
}
func (s *server) RecordRoute(ctx context.Context, stream pb.RouteGuide_RecordRouteStream) error {
var pointCount, featureCount, distance int32
var lastPoint *pb.Point
startTime := time.Now()
for {
point, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
return err
}
pointCount++
for _, feature := range features {
if proto.Equal(feature.Location, point) {
featureCount++
}
}
if lastPoint != nil {
distance += calcDistance(lastPoint, point)
}
lastPoint = point
}
return stream.SendMsg(&pb.RouteSummary{
PointCount: pointCount,
FeatureCount: featureCount,
Distance: distance,
ElapsedTime: int32(time.Since(startTime).Seconds()),
})
}
func (s *server) RouteChat(ctx context.Context, stream pb.RouteGuide_RouteChatStream) error {
for {
in, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
return err
}
key := serialize(in.Location)
s.mu.Lock()
s.routeNotes[key] = append(s.routeNotes[key], in)
// Note: this copy prevents blocking other clients while serving this one.
// We don't need to do a deep copy, because elements in the slice are
// insert-only and never modified.
rn := make([]*pb.RouteNote, len(s.routeNotes[key]))
copy(rn, s.routeNotes[key])
s.mu.Unlock()
for _, note := range rn {
if err := stream.Send(note); err != nil {
return err
}
}
}
return nil
}

View File

@ -2,10 +2,12 @@ package main
import (
"fmt"
"io"
"time"
"context"
proto "github.com/asim/go-micro/examples/v4/stream/server/proto"
proto "github.com/asim/go-micro/examples/v4/stream/rpc/server/proto"
"go-micro.dev/v4"
)
@ -25,6 +27,9 @@ func bidirectional(cl proto.StreamerService) {
return
}
rsp, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
fmt.Println("recv err", err)
break
@ -52,6 +57,9 @@ func serverStream(cl proto.StreamerService) {
// receive messages for a 10 count
for {
rsp, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
fmt.Println("recv err", err)
break

View File

@ -6,7 +6,7 @@ import (
"io"
"log"
proto "github.com/asim/go-micro/examples/v4/stream/server/proto"
proto "github.com/asim/go-micro/examples/v4/stream/rpc/server/proto"
"go-micro.dev/v4"
)

View File

@ -0,0 +1,213 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.15.6
// source: proto/stream.proto
package stream
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Count int64 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"`
}
func (x *Request) Reset() {
*x = Request{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_stream_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Request) ProtoMessage() {}
func (x *Request) ProtoReflect() protoreflect.Message {
mi := &file_proto_stream_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Request.ProtoReflect.Descriptor instead.
func (*Request) Descriptor() ([]byte, []int) {
return file_proto_stream_proto_rawDescGZIP(), []int{0}
}
func (x *Request) GetCount() int64 {
if x != nil {
return x.Count
}
return 0
}
type Response struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Count int64 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"`
}
func (x *Response) Reset() {
*x = Response{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_stream_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Response) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Response) ProtoMessage() {}
func (x *Response) ProtoReflect() protoreflect.Message {
mi := &file_proto_stream_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Response.ProtoReflect.Descriptor instead.
func (*Response) Descriptor() ([]byte, []int) {
return file_proto_stream_proto_rawDescGZIP(), []int{1}
}
func (x *Response) GetCount() int64 {
if x != nil {
return x.Count
}
return 0
}
var File_proto_stream_proto protoreflect.FileDescriptor
var file_proto_stream_proto_rawDesc = []byte{
0x0a, 0x12, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1f, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x20, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0x58, 0x0a, 0x08, 0x53, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x08, 0x2e,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x27, 0x0a, 0x0c, 0x53, 0x65, 0x72, 0x76,
0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x08, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x09, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30,
0x01, 0x42, 0x10, 0x5a, 0x0e, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x73, 0x74, 0x72,
0x65, 0x61, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proto_stream_proto_rawDescOnce sync.Once
file_proto_stream_proto_rawDescData = file_proto_stream_proto_rawDesc
)
func file_proto_stream_proto_rawDescGZIP() []byte {
file_proto_stream_proto_rawDescOnce.Do(func() {
file_proto_stream_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_stream_proto_rawDescData)
})
return file_proto_stream_proto_rawDescData
}
var file_proto_stream_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_proto_stream_proto_goTypes = []interface{}{
(*Request)(nil), // 0: Request
(*Response)(nil), // 1: Response
}
var file_proto_stream_proto_depIdxs = []int32{
0, // 0: Streamer.Stream:input_type -> Request
0, // 1: Streamer.ServerStream:input_type -> Request
1, // 2: Streamer.Stream:output_type -> Response
1, // 3: Streamer.ServerStream:output_type -> Response
2, // [2:4] is the sub-list for method output_type
0, // [0:2] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_proto_stream_proto_init() }
func file_proto_stream_proto_init() {
if File_proto_stream_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proto_stream_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_stream_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Response); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proto_stream_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_proto_stream_proto_goTypes,
DependencyIndexes: file_proto_stream_proto_depIdxs,
MessageInfos: file_proto_stream_proto_msgTypes,
}.Build()
File_proto_stream_proto = out.File
file_proto_stream_proto_rawDesc = nil
file_proto_stream_proto_goTypes = nil
file_proto_stream_proto_depIdxs = nil
}

View File

@ -1,24 +1,17 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: github.com/asim/go-micro/examples/v4/stream/server/proto/stream.proto
// source: proto/stream.proto
/*
Package stream is a generated protocol buffer package.
It is generated from these files:
github.com/asim/go-micro/examples/v4/stream/server/proto/stream.proto
It has these top-level messages:
Request
Response
*/
package stream
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
fmt "fmt"
proto "google.golang.org/protobuf/proto"
math "math"
)
import (
context "context"
api "go-micro.dev/v4/api"
client "go-micro.dev/v4/client"
server "go-micro.dev/v4/server"
)
@ -28,17 +21,18 @@ var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for Streamer service
func NewStreamerEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for Streamer service
type StreamerService interface {
@ -47,61 +41,65 @@ type StreamerService interface {
}
type streamerService struct {
c client.Client
serviceName string
c client.Client
name string
}
func NewStreamerService(serviceName string, c client.Client) StreamerService {
if c == nil {
c = client.NewClient()
}
if len(serviceName) == 0 {
serviceName = "streamer"
}
func NewStreamerService(name string, c client.Client) StreamerService {
return &streamerService{
c: c,
serviceName: serviceName,
c: c,
name: name,
}
}
func (c *streamerService) Stream(ctx context.Context, opts ...client.CallOption) (Streamer_StreamService, error) {
req := c.c.NewRequest(c.serviceName, "Streamer.Stream", &Request{})
req := c.c.NewRequest(c.name, "Streamer.Stream", &Request{})
stream, err := c.c.Stream(ctx, req, opts...)
if err != nil {
return nil, err
}
return &streamerStreamService{stream}, nil
return &streamerServiceStream{stream}, nil
}
type Streamer_StreamService interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
CloseSend() error
Close() error
Send(*Request) error
Recv() (*Response, error)
}
type streamerStreamService struct {
type streamerServiceStream struct {
stream client.Stream
}
func (x *streamerStreamService) Close() error {
func (x *streamerServiceStream) CloseSend() error {
return x.stream.CloseSend()
}
func (x *streamerServiceStream) Close() error {
return x.stream.Close()
}
func (x *streamerStreamService) SendMsg(m interface{}) error {
func (x *streamerServiceStream) Context() context.Context {
return x.stream.Context()
}
func (x *streamerServiceStream) SendMsg(m interface{}) error {
return x.stream.Send(m)
}
func (x *streamerStreamService) RecvMsg(m interface{}) error {
func (x *streamerServiceStream) RecvMsg(m interface{}) error {
return x.stream.Recv(m)
}
func (x *streamerStreamService) Send(m *Request) error {
func (x *streamerServiceStream) Send(m *Request) error {
return x.stream.Send(m)
}
func (x *streamerStreamService) Recv() (*Response, error) {
func (x *streamerServiceStream) Recv() (*Response, error) {
m := new(Response)
err := x.stream.Recv(m)
if err != nil {
@ -111,7 +109,7 @@ func (x *streamerStreamService) Recv() (*Response, error) {
}
func (c *streamerService) ServerStream(ctx context.Context, in *Request, opts ...client.CallOption) (Streamer_ServerStreamService, error) {
req := c.c.NewRequest(c.serviceName, "Streamer.ServerStream", &Request{})
req := c.c.NewRequest(c.name, "Streamer.ServerStream", &Request{})
stream, err := c.c.Stream(ctx, req, opts...)
if err != nil {
return nil, err
@ -119,33 +117,43 @@ func (c *streamerService) ServerStream(ctx context.Context, in *Request, opts ..
if err := stream.Send(in); err != nil {
return nil, err
}
return &streamerServerStreamService{stream}, nil
return &streamerServiceServerStream{stream}, nil
}
type Streamer_ServerStreamService interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
CloseSend() error
Close() error
Recv() (*Response, error)
}
type streamerServerStreamService struct {
type streamerServiceServerStream struct {
stream client.Stream
}
func (x *streamerServerStreamService) Close() error {
func (x *streamerServiceServerStream) CloseSend() error {
return x.stream.CloseSend()
}
func (x *streamerServiceServerStream) Close() error {
return x.stream.Close()
}
func (x *streamerServerStreamService) SendMsg(m interface{}) error {
func (x *streamerServiceServerStream) Context() context.Context {
return x.stream.Context()
}
func (x *streamerServiceServerStream) SendMsg(m interface{}) error {
return x.stream.Send(m)
}
func (x *streamerServerStreamService) RecvMsg(m interface{}) error {
func (x *streamerServiceServerStream) RecvMsg(m interface{}) error {
return x.stream.Recv(m)
}
func (x *streamerServerStreamService) Recv() (*Response, error) {
func (x *streamerServiceServerStream) Recv() (*Response, error) {
m := new(Response)
err := x.stream.Recv(m)
if err != nil {
@ -161,7 +169,7 @@ type StreamerHandler interface {
ServerStream(context.Context, *Request, Streamer_ServerStreamStream) error
}
func RegisterStreamerHandler(s server.Server, hdlr StreamerHandler, opts ...server.HandlerOption) {
func RegisterStreamerHandler(s server.Server, hdlr StreamerHandler, opts ...server.HandlerOption) error {
type streamer interface {
Stream(ctx context.Context, stream server.Stream) error
ServerStream(ctx context.Context, stream server.Stream) error
@ -170,7 +178,7 @@ func RegisterStreamerHandler(s server.Server, hdlr StreamerHandler, opts ...serv
streamer
}
h := &streamerHandler{hdlr}
s.Handle(s.NewHandler(&Streamer{h}, opts...))
return s.Handle(s.NewHandler(&Streamer{h}, opts...))
}
type streamerHandler struct {
@ -182,6 +190,7 @@ func (h *streamerHandler) Stream(ctx context.Context, stream server.Stream) erro
}
type Streamer_StreamStream interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
Close() error
@ -197,6 +206,10 @@ func (x *streamerStreamStream) Close() error {
return x.stream.Close()
}
func (x *streamerStreamStream) Context() context.Context {
return x.stream.Context()
}
func (x *streamerStreamStream) SendMsg(m interface{}) error {
return x.stream.Send(m)
}
@ -226,6 +239,7 @@ func (h *streamerHandler) ServerStream(ctx context.Context, stream server.Stream
}
type Streamer_ServerStreamStream interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
Close() error
@ -240,6 +254,10 @@ func (x *streamerServerStreamStream) Close() error {
return x.stream.Close()
}
func (x *streamerServerStreamStream) Context() context.Context {
return x.stream.Context()
}
func (x *streamerServerStreamStream) SendMsg(m interface{}) error {
return x.stream.Send(m)
}

View File

@ -1,5 +1,7 @@
syntax = "proto3";
option go_package = "./proto;stream";
service Streamer {
rpc Stream(stream Request) returns (stream Response) {}
rpc ServerStream(Request) returns (stream Response) {}

View File

@ -1,254 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: github.com/asim/go-micro/examples/v4/stream/server/proto/stream.proto
/*
Package stream is a generated protocol buffer package.
It is generated from these files:
github.com/asim/go-micro/examples/v4/stream/server/proto/stream.proto
It has these top-level messages:
Request
Response
*/
package stream
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Request struct {
Count int64 `protobuf:"varint,1,opt,name=count" json:"count,omitempty"`
}
func (m *Request) Reset() { *m = Request{} }
func (m *Request) String() string { return proto.CompactTextString(m) }
func (*Request) ProtoMessage() {}
func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Request) GetCount() int64 {
if m != nil {
return m.Count
}
return 0
}
type Response struct {
Count int64 `protobuf:"varint,1,opt,name=count" json:"count,omitempty"`
}
func (m *Response) Reset() { *m = Response{} }
func (m *Response) String() string { return proto.CompactTextString(m) }
func (*Response) ProtoMessage() {}
func (*Response) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *Response) GetCount() int64 {
if m != nil {
return m.Count
}
return 0
}
func init() {
proto.RegisterType((*Request)(nil), "Request")
proto.RegisterType((*Response)(nil), "Response")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// Client API for Streamer service
type StreamerClient interface {
Stream(ctx context.Context, opts ...grpc.CallOption) (Streamer_StreamClient, error)
ServerStream(ctx context.Context, in *Request, opts ...grpc.CallOption) (Streamer_ServerStreamClient, error)
}
type streamerClient struct {
cc *grpc.ClientConn
}
func NewStreamerClient(cc *grpc.ClientConn) StreamerClient {
return &streamerClient{cc}
}
func (c *streamerClient) Stream(ctx context.Context, opts ...grpc.CallOption) (Streamer_StreamClient, error) {
stream, err := grpc.NewClientStream(ctx, &_Streamer_serviceDesc.Streams[0], c.cc, "/Streamer/Stream", opts...)
if err != nil {
return nil, err
}
x := &streamerStreamClient{stream}
return x, nil
}
type Streamer_StreamClient interface {
Send(*Request) error
Recv() (*Response, error)
grpc.ClientStream
}
type streamerStreamClient struct {
grpc.ClientStream
}
func (x *streamerStreamClient) Send(m *Request) error {
return x.ClientStream.SendMsg(m)
}
func (x *streamerStreamClient) Recv() (*Response, error) {
m := new(Response)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *streamerClient) ServerStream(ctx context.Context, in *Request, opts ...grpc.CallOption) (Streamer_ServerStreamClient, error) {
stream, err := grpc.NewClientStream(ctx, &_Streamer_serviceDesc.Streams[1], c.cc, "/Streamer/ServerStream", opts...)
if err != nil {
return nil, err
}
x := &streamerServerStreamClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type Streamer_ServerStreamClient interface {
Recv() (*Response, error)
grpc.ClientStream
}
type streamerServerStreamClient struct {
grpc.ClientStream
}
func (x *streamerServerStreamClient) Recv() (*Response, error) {
m := new(Response)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// Server API for Streamer service
type StreamerServer interface {
Stream(Streamer_StreamServer) error
ServerStream(*Request, Streamer_ServerStreamServer) error
}
func RegisterStreamerServer(s *grpc.Server, srv StreamerServer) {
s.RegisterService(&_Streamer_serviceDesc, srv)
}
func _Streamer_Stream_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(StreamerServer).Stream(&streamerStreamServer{stream})
}
type Streamer_StreamServer interface {
Send(*Response) error
Recv() (*Request, error)
grpc.ServerStream
}
type streamerStreamServer struct {
grpc.ServerStream
}
func (x *streamerStreamServer) Send(m *Response) error {
return x.ServerStream.SendMsg(m)
}
func (x *streamerStreamServer) Recv() (*Request, error) {
m := new(Request)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func _Streamer_ServerStream_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(Request)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(StreamerServer).ServerStream(m, &streamerServerStreamServer{stream})
}
type Streamer_ServerStreamServer interface {
Send(*Response) error
grpc.ServerStream
}
type streamerServerStreamServer struct {
grpc.ServerStream
}
func (x *streamerServerStreamServer) Send(m *Response) error {
return x.ServerStream.SendMsg(m)
}
var _Streamer_serviceDesc = grpc.ServiceDesc{
ServiceName: "Streamer",
HandlerType: (*StreamerServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{
{
StreamName: "Stream",
Handler: _Streamer_Stream_Handler,
ServerStreams: true,
ClientStreams: true,
},
{
StreamName: "ServerStream",
Handler: _Streamer_ServerStream_Handler,
ServerStreams: true,
},
},
Metadata: "github.com/asim/go-micro/examples/v4/stream/server/proto/stream.proto",
}
func init() {
proto.RegisterFile("github.com/asim/go-micro/examples/v4/stream/server/proto/stream.proto", fileDescriptor0)
}
var fileDescriptor0 = []byte{
// 167 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x4a, 0xcf, 0x2c, 0xc9,
0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0xcf, 0xcd, 0x4c, 0x2e, 0xca, 0xd7, 0x4f, 0xad, 0x48,
0xcc, 0x2d, 0xc8, 0x49, 0x2d, 0xd6, 0x2f, 0x2e, 0x29, 0x4a, 0x4d, 0xcc, 0xd5, 0x2f, 0x4e, 0x2d,
0x2a, 0x4b, 0x2d, 0xd2, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x87, 0x8a, 0xe9, 0x81, 0x39, 0x4a, 0xf2,
0x5c, 0xec, 0x41, 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x22, 0x5c, 0xac, 0xc9, 0xf9, 0xa5,
0x79, 0x25, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xcc, 0x41, 0x10, 0x8e, 0x92, 0x02, 0x17, 0x47, 0x50,
0x6a, 0x71, 0x41, 0x7e, 0x5e, 0x71, 0x2a, 0x76, 0x15, 0x46, 0x11, 0x5c, 0x1c, 0xc1, 0x60, 0x23,
0x53, 0x8b, 0x84, 0x94, 0xb9, 0xd8, 0x20, 0x6c, 0x21, 0x0e, 0x3d, 0xa8, 0xb9, 0x52, 0x9c, 0x7a,
0x30, 0x03, 0x94, 0x18, 0x34, 0x18, 0x0d, 0x18, 0x85, 0xd4, 0xb9, 0x78, 0x82, 0xc1, 0x0e, 0xc2,
0xab, 0xd4, 0x80, 0x31, 0x89, 0x0d, 0xec, 0x46, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x16,
0x4a, 0x84, 0x3f, 0xe1, 0x00, 0x00, 0x00,
}

View File

@ -1,19 +1,17 @@
package grpc
import (
b "bytes"
"encoding/json"
"fmt"
"strings"
b "bytes"
"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
"go-micro.dev/v4/codec"
"go-micro.dev/v4/codec/bytes"
"github.com/oxtoacart/bpool"
"google.golang.org/grpc"
"google.golang.org/grpc/encoding"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
)
type jsonCodec struct{}
@ -21,12 +19,8 @@ type protoCodec struct{}
type bytesCodec struct{}
type wrapCodec struct{ encoding.Codec }
var jsonpbMarshaler = &jsonpb.Marshaler{}
var useNumber bool
// create buffer pool with 16 instances each preallocated with 256 bytes
var bufferPool = bpool.NewSizedBufferPool(16, 256)
var (
defaultGRPCCodecs = map[string]encoding.Codec{
"application/json": jsonCodec{},
@ -115,12 +109,11 @@ func (jsonCodec) Marshal(v interface{}) ([]byte, error) {
}
if pb, ok := v.(proto.Message); ok {
buf := bufferPool.Get()
defer bufferPool.Put(buf)
if err := jsonpbMarshaler.Marshal(buf, pb); err != nil {
bytes, err := protojson.Marshal(pb)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
return bytes, nil
}
return json.Marshal(v)
@ -135,7 +128,7 @@ func (jsonCodec) Unmarshal(data []byte, v interface{}) error {
return nil
}
if pb, ok := v.(proto.Message); ok {
return jsonpb.Unmarshal(b.NewReader(data), pb)
return protojson.Unmarshal(data, pb)
}
dec := json.NewDecoder(b.NewReader(data))

View File

@ -3,11 +3,10 @@ module github.com/asim/go-micro/plugins/client/grpc/v4
go 1.16
require (
github.com/golang/protobuf v1.5.2
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c
go-micro.dev/v4 v4.2.1
google.golang.org/grpc v1.41.0
google.golang.org/grpc/examples v0.0.0-20211020220737-f00baa6c3c84
google.golang.org/protobuf v1.26.0
)
replace go-micro.dev/v4 => ../../../../go-micro

View File

@ -12,15 +12,14 @@ import (
"time"
"go-micro.dev/v4/broker"
"go-micro.dev/v4/cmd"
"go-micro.dev/v4/client"
"go-micro.dev/v4/cmd"
raw "go-micro.dev/v4/codec/bytes"
"go-micro.dev/v4/errors"
"go-micro.dev/v4/metadata"
"go-micro.dev/v4/registry"
"go-micro.dev/v4/selector"
pnet "go-micro.dev/v4/util/net"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/encoding"
@ -104,7 +103,6 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
address := node.Address
header = make(map[string]string)
if md, ok := metadata.FromContext(ctx); ok {
header = make(map[string]string, len(md))
for k, v := range md {
@ -132,8 +130,16 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
var grr error
var dialCtx context.Context
var cancel context.CancelFunc
if opts.DialTimeout > 0 {
dialCtx, cancel = context.WithTimeout(ctx, opts.DialTimeout)
} else {
dialCtx, cancel = context.WithCancel(ctx)
}
defer cancel()
grpcDialOptions := []grpc.DialOption{
grpc.WithTimeout(opts.DialTimeout),
g.secure(address),
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(maxRecvMsgSize),
@ -145,7 +151,7 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
grpcDialOptions = append(grpcDialOptions, opts...)
}
cc, err := g.pool.getConn(address, grpcDialOptions...)
cc, err := g.pool.getConn(dialCtx, address, grpcDialOptions...)
if err != nil {
return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
}
@ -208,7 +214,7 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
var dialCtx context.Context
var cancel context.CancelFunc
if opts.DialTimeout >= 0 {
if opts.DialTimeout > 0 {
dialCtx, cancel = context.WithTimeout(ctx, opts.DialTimeout)
} else {
dialCtx, cancel = context.WithCancel(ctx)
@ -218,7 +224,6 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
wc := wrapCodec{cf}
grpcDialOptions := []grpc.DialOption{
grpc.WithTimeout(opts.DialTimeout),
g.secure(address),
}
@ -226,7 +231,7 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
grpcDialOptions = append(grpcDialOptions, opts...)
}
cc, err := grpc.DialContext(dialCtx, address, grpcDialOptions...)
cc, err := g.pool.getConn(dialCtx, address, grpcDialOptions...)
if err != nil {
return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
}
@ -274,14 +279,16 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
context: ctx,
request: req,
response: &response{
conn: cc,
conn: cc.ClientConn,
stream: st,
codec: cf,
gcodec: codec,
},
stream: st,
conn: cc,
cancel: cancel,
release: func(err error) {
g.pool.release(address, cc, err)
},
}
// set the stream as the response
@ -347,7 +354,7 @@ func (g *grpcClient) newGRPCCodec(contentType string) (encoding.Codec, error) {
if c, ok := defaultGRPCCodecs[contentType]; ok {
return wrapCodec{c}, nil
}
return nil, fmt.Errorf("Unsupported Content-Type: %s", contentType)
return nil, fmt.Errorf("unsupported Content-Type: %s", contentType)
}
func (g *grpcClient) Init(opts ...client.Option) error {

View File

@ -1,6 +1,7 @@
package grpc
import (
"context"
"sync"
"time"
@ -66,7 +67,7 @@ func newPool(size int, ttl time.Duration, idle int, ms int) *pool {
}
}
func (p *pool) getConn(addr string, opts ...grpc.DialOption) (*poolConn, error) {
func (p *pool) getConn(dialCtx context.Context, addr string, opts ...grpc.DialOption) (*poolConn, error) {
now := time.Now().Unix()
p.Lock()
sp, ok := p.conns[addr]
@ -135,7 +136,7 @@ func (p *pool) getConn(addr string, opts ...grpc.DialOption) (*poolConn, error)
p.Unlock()
// create new conn
cc, err := grpc.Dial(addr, opts...)
cc, err := grpc.DialContext(dialCtx, addr, opts...)
if err != nil {
return nil, err
}
@ -184,7 +185,6 @@ func (p *pool) release(addr string, conn *poolConn, err error) {
sp.idle++
}
p.Unlock()
return
}
func (conn *poolConn) Close() {

View File

@ -7,7 +7,6 @@ import (
"time"
"google.golang.org/grpc"
pgrpc "google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
@ -19,7 +18,7 @@ func testPool(t *testing.T, size int, ttl time.Duration, idle int, ms int) {
}
defer l.Close()
s := pgrpc.NewServer()
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &greeterServer{})
go s.Serve(l)
@ -30,7 +29,7 @@ func testPool(t *testing.T, size int, ttl time.Duration, idle int, ms int) {
for i := 0; i < 10; i++ {
// get a conn
cc, err := p.getConn(l.Addr().String(), grpc.WithInsecure())
cc, err := p.getConn(context.TODO(), l.Addr().String(), grpc.WithInsecure())
if err != nil {
t.Fatal(err)
}

View File

@ -14,12 +14,12 @@ type grpcStream struct {
sync.RWMutex
closed bool
err error
conn *grpc.ClientConn
stream grpc.ClientStream
request client.Request
response client.Response
context context.Context
cancel func()
release func(error)
}
func (g *grpcStream) Context() context.Context {
@ -43,15 +43,11 @@ func (g *grpcStream) Send(msg interface{}) error {
}
func (g *grpcStream) Recv(msg interface{}) (err error) {
defer g.setError(err)
if err = g.stream.RecvMsg(msg); err != nil {
// #202 - inconsistent gRPC stream behavior
// the only way to tell if the stream is done is when we get a EOF on the Recv
// here we should close the underlying gRPC ClientConn
closeErr := g.Close()
if err == io.EOF && closeErr != nil {
err = closeErr
if err != io.EOF {
g.setError(err)
}
return err
}
return
}
@ -68,11 +64,10 @@ func (g *grpcStream) setError(e error) {
g.Unlock()
}
// Close the gRPC send stream
// #202 - inconsistent gRPC stream behavior
// The underlying gRPC stream should not be closed here since the
// stream should still be able to receive after this function call
// TODO: should the conn be closed in another way?
func (g *grpcStream) CloseSend() error {
return g.stream.CloseSend()
}
func (g *grpcStream) Close() error {
g.Lock()
defer g.Unlock()
@ -83,6 +78,7 @@ func (g *grpcStream) Close() error {
// cancel the context
g.cancel()
g.closed = true
g.stream.CloseSend()
return g.conn.Close()
// release back to pool
g.release(g.err)
return nil
}

View File

@ -120,6 +120,10 @@ func (h *httpStream) Error() error {
return h.err
}
func (h *httpStream) CloseSend() error {
return errors.New("streamer not implemented")
}
func (h *httpStream) Close() error {
select {
case <-h.closed: