move implementations to external repos (#17)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
@@ -1,30 +0,0 @@
|
||||
# GRPC Server
|
||||
|
||||
The grpc server is a [micro.Server](https://godoc.org/github.com/micro/go-micro/server#Server) compatible server.
|
||||
|
||||
## Overview
|
||||
|
||||
The server makes use of the [google.golang.org/grpc](google.golang.org/grpc) framework for the underlying server
|
||||
but continues to use micro handler signatures and protoc-gen-micro generated code.
|
||||
|
||||
## Usage
|
||||
|
||||
Specify the server to your micro service
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/micro/go-micro"
|
||||
"github.com/micro/go-plugins/server/grpc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
service := micro.NewService(
|
||||
// This needs to be first as it replaces the underlying server
|
||||
// which causes any configuration set before it
|
||||
// to be discarded
|
||||
micro.Server(grpc.NewServer()),
|
||||
micro.Name("greeter"),
|
||||
)
|
||||
}
|
||||
```
|
||||
**NOTE**: Setting the gRPC server and/or client causes the underlying the server/client to be replaced which causes any previous configuration set on that server/client to be discarded. It is therefore recommended to set gRPC server/client before any other configuration
|
@@ -1,190 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
"github.com/unistack-org/micro/v3/codec/bytes"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/encoding"
|
||||
"google.golang.org/grpc/metadata"
|
||||
jsonpb "google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type jsonCodec struct{}
|
||||
type bytesCodec struct{}
|
||||
type protoCodec struct{}
|
||||
type wrapCodec struct{ encoding.Codec }
|
||||
|
||||
var jsonpbMarshaler = jsonpb.MarshalOptions{
|
||||
UseEnumNumbers: false,
|
||||
EmitUnpopulated: false,
|
||||
UseProtoNames: true,
|
||||
AllowPartial: false,
|
||||
}
|
||||
|
||||
var jsonpbUnmarshaler = jsonpb.UnmarshalOptions{
|
||||
DiscardUnknown: false,
|
||||
AllowPartial: false,
|
||||
}
|
||||
|
||||
var (
|
||||
defaultGRPCCodecs = map[string]encoding.Codec{
|
||||
"application/json": jsonCodec{},
|
||||
"application/proto": protoCodec{},
|
||||
"application/protobuf": protoCodec{},
|
||||
"application/octet-stream": protoCodec{},
|
||||
"application/grpc": protoCodec{},
|
||||
"application/grpc+json": jsonCodec{},
|
||||
"application/grpc+proto": protoCodec{},
|
||||
"application/grpc+bytes": bytesCodec{},
|
||||
}
|
||||
)
|
||||
|
||||
func (w wrapCodec) String() string {
|
||||
return w.Codec.Name()
|
||||
}
|
||||
|
||||
func (w wrapCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
b, ok := v.(*bytes.Frame)
|
||||
if ok {
|
||||
return b.Data, nil
|
||||
}
|
||||
return w.Codec.Marshal(v)
|
||||
}
|
||||
|
||||
func (w wrapCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
b, ok := v.(*bytes.Frame)
|
||||
if ok {
|
||||
b.Data = data
|
||||
return nil
|
||||
}
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return w.Codec.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
func (protoCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
m, ok := v.(proto.Message)
|
||||
if !ok {
|
||||
return nil, codec.ErrInvalidMessage
|
||||
}
|
||||
return proto.Marshal(m)
|
||||
}
|
||||
|
||||
func (protoCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
m, ok := v.(proto.Message)
|
||||
if !ok {
|
||||
return codec.ErrInvalidMessage
|
||||
}
|
||||
return proto.Unmarshal(data, m)
|
||||
}
|
||||
|
||||
func (protoCodec) Name() string {
|
||||
return "proto"
|
||||
}
|
||||
|
||||
func (jsonCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
if pb, ok := v.(proto.Message); ok {
|
||||
s, err := jsonpbMarshaler.Marshal(pb)
|
||||
return s, err
|
||||
}
|
||||
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
func (jsonCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
if pb, ok := v.(proto.Message); ok {
|
||||
return jsonpbUnmarshaler.Unmarshal(data, pb)
|
||||
}
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
func (jsonCodec) Name() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
func (bytesCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
b, ok := v.(*[]byte)
|
||||
if !ok {
|
||||
return nil, codec.ErrInvalidMessage
|
||||
}
|
||||
return *b, nil
|
||||
}
|
||||
|
||||
func (bytesCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
b, ok := v.(*[]byte)
|
||||
if !ok {
|
||||
return codec.ErrInvalidMessage
|
||||
}
|
||||
*b = data
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bytesCodec) Name() string {
|
||||
return "bytes"
|
||||
}
|
||||
|
||||
type grpcCodec struct {
|
||||
grpc.ServerStream
|
||||
// headers
|
||||
id string
|
||||
target string
|
||||
method string
|
||||
endpoint string
|
||||
|
||||
c encoding.Codec
|
||||
}
|
||||
|
||||
func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error {
|
||||
md, _ := metadata.FromIncomingContext(g.ServerStream.Context())
|
||||
if m == nil {
|
||||
m = new(codec.Message)
|
||||
}
|
||||
if m.Header == nil {
|
||||
m.Header = make(map[string]string, len(md))
|
||||
}
|
||||
for k, v := range md {
|
||||
m.Header[k] = strings.Join(v, ",")
|
||||
}
|
||||
m.Id = g.id
|
||||
m.Target = g.target
|
||||
m.Method = g.method
|
||||
m.Endpoint = g.endpoint
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcCodec) ReadBody(v interface{}) error {
|
||||
// caller has requested a frame
|
||||
if f, ok := v.(*bytes.Frame); ok {
|
||||
return g.ServerStream.RecvMsg(f)
|
||||
}
|
||||
return g.ServerStream.RecvMsg(v)
|
||||
}
|
||||
|
||||
func (g *grpcCodec) Write(m *codec.Message, v interface{}) error {
|
||||
// if we don't have a body
|
||||
if v != nil {
|
||||
b, err := g.c.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Body = b
|
||||
}
|
||||
// write the body using the framing codec
|
||||
return g.ServerStream.SendMsg(&bytes.Frame{Data: m.Body})
|
||||
}
|
||||
|
||||
func (g *grpcCodec) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcCodec) String() string {
|
||||
return "grpc"
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
func setServerOption(k, v interface{}) server.Option {
|
||||
return func(o *server.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/unistack-org/micro/v3/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
var errMapping = map[int32]codes.Code{
|
||||
http.StatusOK: codes.OK,
|
||||
http.StatusBadRequest: codes.InvalidArgument,
|
||||
http.StatusRequestTimeout: codes.DeadlineExceeded,
|
||||
http.StatusNotFound: codes.NotFound,
|
||||
http.StatusConflict: codes.AlreadyExists,
|
||||
http.StatusForbidden: codes.PermissionDenied,
|
||||
http.StatusUnauthorized: codes.Unauthenticated,
|
||||
http.StatusPreconditionFailed: codes.FailedPrecondition,
|
||||
http.StatusNotImplemented: codes.Unimplemented,
|
||||
http.StatusInternalServerError: codes.Internal,
|
||||
http.StatusServiceUnavailable: codes.Unavailable,
|
||||
}
|
||||
|
||||
func microError(err *errors.Error) codes.Code {
|
||||
if err == nil {
|
||||
return codes.OK
|
||||
}
|
||||
|
||||
if code, ok := errMapping[err.Code]; ok {
|
||||
return code
|
||||
}
|
||||
return codes.Unknown
|
||||
}
|
@@ -1,122 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/unistack-org/micro/v3/registry"
|
||||
)
|
||||
|
||||
func extractValue(v reflect.Type, d int) *registry.Value {
|
||||
if d == 3 {
|
||||
return nil
|
||||
}
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
arg := ®istry.Value{
|
||||
Name: v.Name(),
|
||||
Type: v.Name(),
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
f := v.Field(i)
|
||||
val := extractValue(f.Type, d+1)
|
||||
if val == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// if we can find a json tag use it
|
||||
if tags := f.Tag.Get("json"); len(tags) > 0 {
|
||||
parts := strings.Split(tags, ",")
|
||||
if parts[0] == "-" || parts[0] == "omitempty" {
|
||||
continue
|
||||
}
|
||||
val.Name = parts[0]
|
||||
}
|
||||
|
||||
// if there's no name default it
|
||||
if len(val.Name) == 0 {
|
||||
val.Name = v.Field(i).Name
|
||||
}
|
||||
|
||||
arg.Values = append(arg.Values, val)
|
||||
}
|
||||
case reflect.Slice:
|
||||
p := v.Elem()
|
||||
if p.Kind() == reflect.Ptr {
|
||||
p = p.Elem()
|
||||
}
|
||||
arg.Type = "[]" + p.Name()
|
||||
}
|
||||
|
||||
return arg
|
||||
}
|
||||
|
||||
func extractEndpoint(method reflect.Method) *registry.Endpoint {
|
||||
if method.PkgPath != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var rspType, reqType reflect.Type
|
||||
var stream bool
|
||||
mt := method.Type
|
||||
|
||||
switch mt.NumIn() {
|
||||
case 3:
|
||||
reqType = mt.In(1)
|
||||
rspType = mt.In(2)
|
||||
case 4:
|
||||
reqType = mt.In(2)
|
||||
rspType = mt.In(3)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
// are we dealing with a stream?
|
||||
switch rspType.Kind() {
|
||||
case reflect.Func, reflect.Interface:
|
||||
stream = true
|
||||
}
|
||||
|
||||
request := extractValue(reqType, 0)
|
||||
response := extractValue(rspType, 0)
|
||||
|
||||
ep := ®istry.Endpoint{
|
||||
Name: method.Name,
|
||||
Request: request,
|
||||
Response: response,
|
||||
Metadata: make(map[string]string),
|
||||
}
|
||||
|
||||
if stream {
|
||||
ep.Metadata = map[string]string{
|
||||
"stream": fmt.Sprintf("%v", stream),
|
||||
}
|
||||
}
|
||||
|
||||
return ep
|
||||
}
|
||||
|
||||
func extractSubValue(typ reflect.Type) *registry.Value {
|
||||
var reqType reflect.Type
|
||||
switch typ.NumIn() {
|
||||
case 1:
|
||||
reqType = typ.In(0)
|
||||
case 2:
|
||||
reqType = typ.In(1)
|
||||
case 3:
|
||||
reqType = typ.In(2)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return extractValue(reqType, 0)
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/unistack-org/micro/v3/registry"
|
||||
)
|
||||
|
||||
type testHandler struct{}
|
||||
|
||||
type testRequest struct{}
|
||||
|
||||
type testResponse struct{}
|
||||
|
||||
func (t *testHandler) Test(ctx context.Context, req *testRequest, rsp *testResponse) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestExtractEndpoint(t *testing.T) {
|
||||
handler := &testHandler{}
|
||||
typ := reflect.TypeOf(handler)
|
||||
|
||||
var endpoints []*registry.Endpoint
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
if e := extractEndpoint(typ.Method(m)); e != nil {
|
||||
endpoints = append(endpoints, e)
|
||||
}
|
||||
}
|
||||
|
||||
if i := len(endpoints); i != 1 {
|
||||
t.Errorf("Expected 1 endpoint, have %d", i)
|
||||
}
|
||||
|
||||
if endpoints[0].Name != "Test" {
|
||||
t.Errorf("Expected handler Test, got %s", endpoints[0].Name)
|
||||
}
|
||||
|
||||
if endpoints[0].Request == nil {
|
||||
t.Error("Expected non nil request")
|
||||
}
|
||||
|
||||
if endpoints[0].Response == nil {
|
||||
t.Error("Expected non nil request")
|
||||
}
|
||||
|
||||
if endpoints[0].Request.Name != "testRequest" {
|
||||
t.Errorf("Expected testRequest got %s", endpoints[0].Request.Name)
|
||||
}
|
||||
|
||||
if endpoints[0].Response.Name != "testResponse" {
|
||||
t.Errorf("Expected testResponse got %s", endpoints[0].Response.Name)
|
||||
}
|
||||
|
||||
if endpoints[0].Request.Type != "testRequest" {
|
||||
t.Errorf("Expected testRequest type got %s", endpoints[0].Request.Type)
|
||||
}
|
||||
|
||||
if endpoints[0].Response.Type != "testResponse" {
|
||||
t.Errorf("Expected testResponse type got %s", endpoints[0].Response.Type)
|
||||
}
|
||||
|
||||
}
|
1047
server/grpc/grpc.go
1047
server/grpc/grpc.go
File diff suppressed because it is too large
Load Diff
@@ -1,303 +0,0 @@
|
||||
package grpc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
bmemory "github.com/unistack-org/micro/v3/broker/memory"
|
||||
"github.com/unistack-org/micro/v3/client"
|
||||
gcli "github.com/unistack-org/micro/v3/client/grpc"
|
||||
"github.com/unistack-org/micro/v3/errors"
|
||||
pberr "github.com/unistack-org/micro/v3/errors/proto"
|
||||
rmemory "github.com/unistack-org/micro/v3/registry/memory"
|
||||
"github.com/unistack-org/micro/v3/router"
|
||||
rtreg "github.com/unistack-org/micro/v3/router/registry"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
gsrv "github.com/unistack-org/micro/v3/server/grpc"
|
||||
pb "github.com/unistack-org/micro/v3/server/grpc/proto"
|
||||
tgrpc "github.com/unistack-org/micro/v3/transport/grpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// server is used to implement helloworld.GreeterServer.
|
||||
type testServer struct {
|
||||
msgCount int
|
||||
}
|
||||
|
||||
func (s *testServer) Handle(ctx context.Context, msg *pb.Request) error {
|
||||
s.msgCount++
|
||||
return nil
|
||||
}
|
||||
func (s *testServer) HandleError(ctx context.Context, msg *pb.Request) error {
|
||||
return fmt.Errorf("fake")
|
||||
}
|
||||
|
||||
// TestHello implements helloworld.GreeterServer
|
||||
func (s *testServer) CallPcre(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
|
||||
if req.Name == "Error" {
|
||||
return &errors.Error{Id: "1", Code: 99, Detail: "detail"}
|
||||
}
|
||||
|
||||
rsp.Msg = "Hello " + req.Name
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestHello implements helloworld.GreeterServer
|
||||
func (s *testServer) CallPcreInvalid(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
|
||||
if req.Name == "Error" {
|
||||
return &errors.Error{Id: "1", Code: 99, Detail: "detail"}
|
||||
}
|
||||
|
||||
rsp.Msg = "Hello " + req.Name
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestHello implements helloworld.GreeterServer
|
||||
func (s *testServer) Call(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
|
||||
if req.Name == "Error" {
|
||||
return &errors.Error{Id: "1", Code: 99, Detail: "detail"}
|
||||
}
|
||||
|
||||
if req.Name == "Panic" {
|
||||
// make it panic
|
||||
panic("handler panic")
|
||||
}
|
||||
|
||||
rsp.Msg = "Hello " + req.Name
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
func BenchmarkServer(b *testing.B) {
|
||||
r := rmemory.NewRegistry()
|
||||
br := bmemory.NewBroker()
|
||||
tr := tgrpc.NewTransport()
|
||||
s := gsrv.NewServer(
|
||||
server.Broker(br),
|
||||
server.Name("foo"),
|
||||
server.Registry(r),
|
||||
server.Transport(tr),
|
||||
)
|
||||
c := gcli.NewClient(
|
||||
client.Registry(r),
|
||||
client.Broker(br),
|
||||
client.Transport(tr),
|
||||
)
|
||||
ctx := context.TODO()
|
||||
|
||||
h := &testServer{}
|
||||
pb.RegisterTestHandler(s, h)
|
||||
if err := s.Start(); err != nil {
|
||||
b.Fatalf("failed to start: %v", err)
|
||||
}
|
||||
|
||||
// check registration
|
||||
services, err := r.GetService("foo")
|
||||
if err != nil || len(services) == 0 {
|
||||
b.Fatalf("failed to get service: %v # %d", err, len(services))
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := s.Stop(); err != nil {
|
||||
b.Fatalf("failed to stop: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Call()
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
func TestGRPCServer(t *testing.T) {
|
||||
r := rmemory.NewRegistry()
|
||||
b := bmemory.NewBroker()
|
||||
tr := tgrpc.NewTransport()
|
||||
rtr := rtreg.NewRouter(router.Registry(r))
|
||||
|
||||
s := gsrv.NewServer(
|
||||
server.Broker(b),
|
||||
server.Name("foo"),
|
||||
server.Registry(r),
|
||||
server.Transport(tr),
|
||||
)
|
||||
|
||||
c := gcli.NewClient(
|
||||
client.Router(rtr),
|
||||
client.Broker(b),
|
||||
client.Transport(tr),
|
||||
)
|
||||
ctx := context.TODO()
|
||||
|
||||
h := &testServer{}
|
||||
pb.RegisterTestHandler(s, h)
|
||||
|
||||
if err := s.Subscribe(s.NewSubscriber("test_topic", h.Handle)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := s.Start(); err != nil {
|
||||
t.Fatalf("failed to start: %v", err)
|
||||
}
|
||||
|
||||
// check registration
|
||||
services, err := r.GetService("foo")
|
||||
if err != nil || len(services) == 0 {
|
||||
t.Fatalf("failed to get service: %v # %d", err, len(services))
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := s.Stop(); err != nil {
|
||||
t.Fatalf("failed to stop: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
cnt := 4
|
||||
for i := 0; i < cnt; i++ {
|
||||
msg := c.NewMessage("test_topic", &pb.Request{Name: fmt.Sprintf("msg %d", i)})
|
||||
if err = c.Publish(ctx, msg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if h.msgCount != cnt {
|
||||
t.Fatalf("pub/sub not work, or invalid message count %d", h.msgCount)
|
||||
}
|
||||
|
||||
cc, err := grpc.Dial(s.Options().Address, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to dial server: %v", err)
|
||||
}
|
||||
|
||||
testMethods := []string{"/test.Test/Call", "/go.micro.test.Test/Call"}
|
||||
|
||||
for _, method := range testMethods {
|
||||
rsp := pb.Response{}
|
||||
|
||||
if err := cc.Invoke(context.Background(), method, &pb.Request{Name: "John"}, &rsp); err != nil {
|
||||
t.Fatalf("error calling server: %v", err)
|
||||
}
|
||||
|
||||
if rsp.Msg != "Hello John" {
|
||||
t.Fatalf("Got unexpected response %v", rsp.Msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Test grpc error
|
||||
rsp := pb.Response{}
|
||||
|
||||
if err := cc.Invoke(context.Background(), "/test.Test/Call", &pb.Request{Name: "Error"}, &rsp); err != nil {
|
||||
st, ok := status.FromError(err)
|
||||
if !ok {
|
||||
t.Fatalf("invalid error received %#+v\n", err)
|
||||
}
|
||||
verr, ok := st.Details()[0].(*pberr.Error)
|
||||
if !ok {
|
||||
t.Fatalf("invalid error received %#+v\n", st.Details()[0])
|
||||
}
|
||||
if verr.Code != 99 && verr.Id != "1" && verr.Detail != "detail" {
|
||||
t.Fatalf("invalid error received %#+v\n", verr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestGRPCServerWithPanicWrapper test grpc server with panic wrapper
|
||||
// gRPC server should not crash when wrapper crashed
|
||||
func TestGRPCServerWithPanicWrapper(t *testing.T) {
|
||||
r := rmemory.NewRegistry()
|
||||
b := bmemory.NewBroker()
|
||||
tr := tgrpc.NewTransport()
|
||||
s := gsrv.NewServer(
|
||||
server.Broker(b),
|
||||
server.Name("foo"),
|
||||
server.Registry(r),
|
||||
server.Transport(tr),
|
||||
server.WrapHandler(func(hf server.HandlerFunc) server.HandlerFunc {
|
||||
return func(ctx context.Context, req server.Request, rsp interface{}) error {
|
||||
// make it panic
|
||||
panic("wrapper panic")
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
h := &testServer{}
|
||||
pb.RegisterTestHandler(s, h)
|
||||
|
||||
if err := s.Start(); err != nil {
|
||||
t.Fatalf("failed to start: %v", err)
|
||||
}
|
||||
|
||||
// check registration
|
||||
services, err := r.GetService("foo")
|
||||
if err != nil || len(services) == 0 {
|
||||
t.Fatalf("failed to get service: %v # %d", err, len(services))
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := s.Stop(); err != nil {
|
||||
t.Fatalf("failed to stop: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
cc, err := grpc.Dial(s.Options().Address, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to dial server: %v", err)
|
||||
}
|
||||
|
||||
rsp := pb.Response{}
|
||||
if err := cc.Invoke(context.Background(), "/test.Test/Call", &pb.Request{Name: "John"}, &rsp); err == nil {
|
||||
t.Fatal("this must return error, as wrapper should be panic")
|
||||
}
|
||||
|
||||
// both wrapper and handler should panic
|
||||
rsp = pb.Response{}
|
||||
if err := cc.Invoke(context.Background(), "/test.Test/Call", &pb.Request{Name: "Panic"}, &rsp); err == nil {
|
||||
t.Fatal("this must return error, as wrapper and handler should be panic")
|
||||
}
|
||||
}
|
||||
|
||||
// TestGRPCServerWithPanicWrapper test grpc server with panic handler
|
||||
// gRPC server should not crash when handler crashed
|
||||
func TestGRPCServerWithPanicHandler(t *testing.T) {
|
||||
r := rmemory.NewRegistry()
|
||||
b := bmemory.NewBroker()
|
||||
tr := tgrpc.NewTransport()
|
||||
s := gsrv.NewServer(
|
||||
server.Broker(b),
|
||||
server.Name("foo"),
|
||||
server.Registry(r),
|
||||
server.Transport(tr),
|
||||
)
|
||||
|
||||
h := &testServer{}
|
||||
pb.RegisterTestHandler(s, h)
|
||||
|
||||
if err := s.Start(); err != nil {
|
||||
t.Fatalf("failed to start: %v", err)
|
||||
}
|
||||
|
||||
// check registration
|
||||
services, err := r.GetService("foo")
|
||||
if err != nil || len(services) == 0 {
|
||||
t.Fatalf("failed to get service: %v # %d", err, len(services))
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := s.Stop(); err != nil {
|
||||
t.Fatalf("failed to stop: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
cc, err := grpc.Dial(s.Options().Address, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to dial server: %v", err)
|
||||
}
|
||||
|
||||
rsp := pb.Response{}
|
||||
if err := cc.Invoke(context.Background(), "/test.Test/Call", &pb.Request{Name: "Panic"}, &rsp); err == nil {
|
||||
t.Fatal("this must return error, as handler should be panic")
|
||||
}
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/unistack-org/micro/v3/registry"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
type rpcHandler struct {
|
||||
name string
|
||||
handler interface{}
|
||||
endpoints []*registry.Endpoint
|
||||
opts server.HandlerOptions
|
||||
}
|
||||
|
||||
func newRpcHandler(handler interface{}, opts ...server.HandlerOption) server.Handler {
|
||||
options := server.HandlerOptions{
|
||||
Metadata: make(map[string]map[string]string),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
typ := reflect.TypeOf(handler)
|
||||
hdlr := reflect.ValueOf(handler)
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
var endpoints []*registry.Endpoint
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
if e := extractEndpoint(typ.Method(m)); e != nil {
|
||||
e.Name = name + "." + e.Name
|
||||
|
||||
for k, v := range options.Metadata[e.Name] {
|
||||
e.Metadata[k] = v
|
||||
}
|
||||
|
||||
endpoints = append(endpoints, e)
|
||||
}
|
||||
}
|
||||
|
||||
return &rpcHandler{
|
||||
name: name,
|
||||
handler: handler,
|
||||
endpoints: endpoints,
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Name() string {
|
||||
return r.name
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Handler() interface{} {
|
||||
return r.handler
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Endpoints() []*registry.Endpoint {
|
||||
return r.endpoints
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Options() server.HandlerOptions {
|
||||
return r.opts
|
||||
}
|
@@ -1,85 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
|
||||
"github.com/unistack-org/micro/v3/broker/http"
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
"github.com/unistack-org/micro/v3/registry/mdns"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/encoding"
|
||||
)
|
||||
|
||||
type codecsKey struct{}
|
||||
type grpcOptions struct{}
|
||||
type netListener struct{}
|
||||
type maxMsgSizeKey struct{}
|
||||
type maxConnKey struct{}
|
||||
type tlsAuth struct{}
|
||||
|
||||
// gRPC Codec to be used to encode/decode requests for a given content type
|
||||
func Codec(contentType string, c encoding.Codec) server.Option {
|
||||
return func(o *server.Options) {
|
||||
codecs := make(map[string]encoding.Codec)
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
if v, ok := o.Context.Value(codecsKey{}).(map[string]encoding.Codec); ok && v != nil {
|
||||
codecs = v
|
||||
}
|
||||
codecs[contentType] = c
|
||||
o.Context = context.WithValue(o.Context, codecsKey{}, codecs)
|
||||
}
|
||||
}
|
||||
|
||||
// AuthTLS should be used to setup a secure authentication using TLS
|
||||
func AuthTLS(t *tls.Config) server.Option {
|
||||
return setServerOption(tlsAuth{}, t)
|
||||
}
|
||||
|
||||
// MaxConn specifies maximum number of max simultaneous connections to server
|
||||
func MaxConn(n int) server.Option {
|
||||
return setServerOption(maxConnKey{}, n)
|
||||
}
|
||||
|
||||
// Listener specifies the net.Listener to use instead of the default
|
||||
func Listener(l net.Listener) server.Option {
|
||||
return setServerOption(netListener{}, l)
|
||||
}
|
||||
|
||||
// Options to be used to configure gRPC options
|
||||
func Options(opts ...grpc.ServerOption) server.Option {
|
||||
return setServerOption(grpcOptions{}, opts)
|
||||
}
|
||||
|
||||
//
|
||||
// MaxMsgSize set the maximum message in bytes the server can receive and
|
||||
// send. Default maximum message size is 4 MB.
|
||||
//
|
||||
func MaxMsgSize(s int) server.Option {
|
||||
return setServerOption(maxMsgSizeKey{}, s)
|
||||
}
|
||||
|
||||
func newOptions(opt ...server.Option) server.Options {
|
||||
opts := server.Options{
|
||||
Codecs: make(map[string]codec.NewCodec),
|
||||
Metadata: map[string]string{},
|
||||
Broker: http.NewBroker(),
|
||||
Registry: mdns.NewRegistry(),
|
||||
Address: server.DefaultAddress,
|
||||
Name: server.DefaultName,
|
||||
Id: server.DefaultId,
|
||||
Version: server.DefaultVersion,
|
||||
RegisterInterval: server.DefaultRegisterInterval,
|
||||
RegisterTTL: server.DefaultRegisterTTL,
|
||||
}
|
||||
|
||||
for _, o := range opt {
|
||||
o(&opts)
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
@@ -1,240 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.6.1
|
||||
// source: server/grpc/proto/test.proto
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
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)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type Request struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Uuid string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Request) Reset() {
|
||||
*x = Request{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_server_grpc_proto_test_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_server_grpc_proto_test_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_server_grpc_proto_test_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Request) GetUuid() string {
|
||||
if x != nil {
|
||||
return x.Uuid
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Request) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Msg string `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Response) Reset() {
|
||||
*x = Response{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_server_grpc_proto_test_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_server_grpc_proto_test_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_server_grpc_proto_test_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Response) GetMsg() string {
|
||||
if x != nil {
|
||||
return x.Msg
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_server_grpc_proto_test_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_server_grpc_proto_test_proto_rawDesc = []byte{
|
||||
0x0a, 0x1c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x31, 0x0a, 0x07,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22,
|
||||
0x1c, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d,
|
||||
0x73, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x32, 0xe6, 0x01,
|
||||
0x0a, 0x04, 0x54, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x04, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x08,
|
||||
0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x18, 0x2f, 0x61, 0x70,
|
||||
0x69, 0x2f, 0x76, 0x30, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x63, 0x61, 0x6c, 0x6c, 0x2f, 0x7b,
|
||||
0x75, 0x75, 0x69, 0x64, 0x7d, 0x3a, 0x01, 0x2a, 0x12, 0x46, 0x0a, 0x08, 0x43, 0x61, 0x6c, 0x6c,
|
||||
0x50, 0x63, 0x72, 0x65, 0x12, 0x08, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09,
|
||||
0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02,
|
||||
0x1f, 0x22, 0x1a, 0x5e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x74, 0x65, 0x73, 0x74,
|
||||
0x2f, 0x63, 0x61, 0x6c, 0x6c, 0x2f, 0x70, 0x63, 0x72, 0x65, 0x2f, 0x3f, 0x24, 0x3a, 0x01, 0x2a,
|
||||
0x12, 0x54, 0x0a, 0x0f, 0x43, 0x61, 0x6c, 0x6c, 0x50, 0x63, 0x72, 0x65, 0x49, 0x6e, 0x76, 0x61,
|
||||
0x6c, 0x69, 0x64, 0x12, 0x08, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26,
|
||||
0x22, 0x21, 0x5e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2f,
|
||||
0x63, 0x61, 0x6c, 0x6c, 0x2f, 0x70, 0x63, 0x72, 0x65, 0x2f, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69,
|
||||
0x64, 0x2f, 0x3f, 0x3a, 0x01, 0x2a, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_server_grpc_proto_test_proto_rawDescOnce sync.Once
|
||||
file_server_grpc_proto_test_proto_rawDescData = file_server_grpc_proto_test_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_server_grpc_proto_test_proto_rawDescGZIP() []byte {
|
||||
file_server_grpc_proto_test_proto_rawDescOnce.Do(func() {
|
||||
file_server_grpc_proto_test_proto_rawDescData = protoimpl.X.CompressGZIP(file_server_grpc_proto_test_proto_rawDescData)
|
||||
})
|
||||
return file_server_grpc_proto_test_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_server_grpc_proto_test_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_server_grpc_proto_test_proto_goTypes = []interface{}{
|
||||
(*Request)(nil), // 0: Request
|
||||
(*Response)(nil), // 1: Response
|
||||
}
|
||||
var file_server_grpc_proto_test_proto_depIdxs = []int32{
|
||||
0, // 0: Test.Call:input_type -> Request
|
||||
0, // 1: Test.CallPcre:input_type -> Request
|
||||
0, // 2: Test.CallPcreInvalid:input_type -> Request
|
||||
1, // 3: Test.Call:output_type -> Response
|
||||
1, // 4: Test.CallPcre:output_type -> Response
|
||||
1, // 5: Test.CallPcreInvalid:output_type -> Response
|
||||
3, // [3:6] is the sub-list for method output_type
|
||||
0, // [0:3] 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_server_grpc_proto_test_proto_init() }
|
||||
func file_server_grpc_proto_test_proto_init() {
|
||||
if File_server_grpc_proto_test_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_server_grpc_proto_test_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_server_grpc_proto_test_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_server_grpc_proto_test_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_server_grpc_proto_test_proto_goTypes,
|
||||
DependencyIndexes: file_server_grpc_proto_test_proto_depIdxs,
|
||||
MessageInfos: file_server_grpc_proto_test_proto_msgTypes,
|
||||
}.Build()
|
||||
File_server_grpc_proto_test_proto = out.File
|
||||
file_server_grpc_proto_test_proto_rawDesc = nil
|
||||
file_server_grpc_proto_test_proto_goTypes = nil
|
||||
file_server_grpc_proto_test_proto_depIdxs = nil
|
||||
}
|
@@ -1,171 +0,0 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: server/grpc/proto/test.proto
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
math "math"
|
||||
)
|
||||
|
||||
import (
|
||||
context "context"
|
||||
api "github.com/unistack-org/micro/v3/api"
|
||||
client "github.com/unistack-org/micro/v3/client"
|
||||
server "github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
// 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.ProtoPackageIsVersion3 // 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 Test service
|
||||
|
||||
func NewTestEndpoints() []*api.Endpoint {
|
||||
return []*api.Endpoint{
|
||||
&api.Endpoint{
|
||||
Name: "Test.Call",
|
||||
Path: []string{"/api/v0/test/call/{uuid}"},
|
||||
Method: []string{"POST"},
|
||||
Body: "*",
|
||||
Handler: "rpc",
|
||||
},
|
||||
&api.Endpoint{
|
||||
Name: "Test.CallPcre",
|
||||
Path: []string{"^/api/v0/test/call/pcre/?$"},
|
||||
Method: []string{"POST"},
|
||||
Body: "*",
|
||||
Handler: "rpc",
|
||||
},
|
||||
&api.Endpoint{
|
||||
Name: "Test.CallPcreInvalid",
|
||||
Path: []string{"^/api/v0/test/call/pcre/invalid/?"},
|
||||
Method: []string{"POST"},
|
||||
Body: "*",
|
||||
Handler: "rpc",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Client API for Test service
|
||||
|
||||
type TestService interface {
|
||||
Call(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
|
||||
CallPcre(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
|
||||
CallPcreInvalid(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
|
||||
}
|
||||
|
||||
type testService struct {
|
||||
c client.Client
|
||||
name string
|
||||
}
|
||||
|
||||
func NewTestService(name string, c client.Client) TestService {
|
||||
return &testService{
|
||||
c: c,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *testService) Call(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
|
||||
req := c.c.NewRequest(c.name, "Test.Call", in)
|
||||
out := new(Response)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *testService) CallPcre(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
|
||||
req := c.c.NewRequest(c.name, "Test.CallPcre", in)
|
||||
out := new(Response)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *testService) CallPcreInvalid(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
|
||||
req := c.c.NewRequest(c.name, "Test.CallPcreInvalid", in)
|
||||
out := new(Response)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for Test service
|
||||
|
||||
type TestHandler interface {
|
||||
Call(context.Context, *Request, *Response) error
|
||||
CallPcre(context.Context, *Request, *Response) error
|
||||
CallPcreInvalid(context.Context, *Request, *Response) error
|
||||
}
|
||||
|
||||
func RegisterTestHandler(s server.Server, hdlr TestHandler, opts ...server.HandlerOption) error {
|
||||
type test interface {
|
||||
Call(ctx context.Context, in *Request, out *Response) error
|
||||
CallPcre(ctx context.Context, in *Request, out *Response) error
|
||||
CallPcreInvalid(ctx context.Context, in *Request, out *Response) error
|
||||
}
|
||||
type Test struct {
|
||||
test
|
||||
}
|
||||
h := &testHandler{hdlr}
|
||||
opts = append(opts, api.WithEndpoint(&api.Endpoint{
|
||||
Name: "Test.Call",
|
||||
Path: []string{"/api/v0/test/call/{uuid}"},
|
||||
Method: []string{"POST"},
|
||||
Body: "*",
|
||||
Handler: "rpc",
|
||||
}))
|
||||
opts = append(opts, api.WithEndpoint(&api.Endpoint{
|
||||
Name: "Test.CallPcre",
|
||||
Path: []string{"^/api/v0/test/call/pcre/?$"},
|
||||
Method: []string{"POST"},
|
||||
Body: "*",
|
||||
Handler: "rpc",
|
||||
}))
|
||||
opts = append(opts, api.WithEndpoint(&api.Endpoint{
|
||||
Name: "Test.CallPcreInvalid",
|
||||
Path: []string{"^/api/v0/test/call/pcre/invalid/?"},
|
||||
Method: []string{"POST"},
|
||||
Body: "*",
|
||||
Handler: "rpc",
|
||||
}))
|
||||
return s.Handle(s.NewHandler(&Test{h}, opts...))
|
||||
}
|
||||
|
||||
type testHandler struct {
|
||||
TestHandler
|
||||
}
|
||||
|
||||
func (h *testHandler) Call(ctx context.Context, in *Request, out *Response) error {
|
||||
return h.TestHandler.Call(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *testHandler) CallPcre(ctx context.Context, in *Request, out *Response) error {
|
||||
return h.TestHandler.CallPcre(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *testHandler) CallPcreInvalid(ctx context.Context, in *Request, out *Response) error {
|
||||
return h.TestHandler.CallPcreInvalid(ctx, in, out)
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "google/api/annotations.proto";
|
||||
|
||||
service Test {
|
||||
rpc Call(Request) returns (Response) {
|
||||
option (google.api.http) = { post: "/api/v0/test/call/{uuid}"; body:"*"; };
|
||||
};
|
||||
rpc CallPcre(Request) returns (Response) {
|
||||
option (google.api.http) = { post: "^/api/v0/test/call/pcre/?$"; body:"*"; };
|
||||
};
|
||||
rpc CallPcreInvalid(Request) returns (Response) {
|
||||
option (google.api.http) = { post: "^/api/v0/test/call/pcre/invalid/?"; body:"*"; };
|
||||
};
|
||||
}
|
||||
|
||||
message Request {
|
||||
string uuid = 1;
|
||||
string name = 2;
|
||||
}
|
||||
|
||||
message Response {
|
||||
string msg = 1;
|
||||
}
|
@@ -1,162 +0,0 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// 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.SupportPackageIsVersion6
|
||||
|
||||
// TestClient is the client API for Test service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type TestClient interface {
|
||||
Call(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
|
||||
CallPcre(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
|
||||
CallPcreInvalid(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
|
||||
}
|
||||
|
||||
type testClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewTestClient(cc grpc.ClientConnInterface) TestClient {
|
||||
return &testClient{cc}
|
||||
}
|
||||
|
||||
func (c *testClient) Call(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
|
||||
out := new(Response)
|
||||
err := c.cc.Invoke(ctx, "/Test/Call", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *testClient) CallPcre(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
|
||||
out := new(Response)
|
||||
err := c.cc.Invoke(ctx, "/Test/CallPcre", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *testClient) CallPcreInvalid(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
|
||||
out := new(Response)
|
||||
err := c.cc.Invoke(ctx, "/Test/CallPcreInvalid", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// TestServer is the server API for Test service.
|
||||
// All implementations must embed UnimplementedTestServer
|
||||
// for forward compatibility
|
||||
type TestServer interface {
|
||||
Call(context.Context, *Request) (*Response, error)
|
||||
CallPcre(context.Context, *Request) (*Response, error)
|
||||
CallPcreInvalid(context.Context, *Request) (*Response, error)
|
||||
mustEmbedUnimplementedTestServer()
|
||||
}
|
||||
|
||||
// UnimplementedTestServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedTestServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedTestServer) Call(context.Context, *Request) (*Response, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Call not implemented")
|
||||
}
|
||||
func (*UnimplementedTestServer) CallPcre(context.Context, *Request) (*Response, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CallPcre not implemented")
|
||||
}
|
||||
func (*UnimplementedTestServer) CallPcreInvalid(context.Context, *Request) (*Response, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CallPcreInvalid not implemented")
|
||||
}
|
||||
func (*UnimplementedTestServer) mustEmbedUnimplementedTestServer() {}
|
||||
|
||||
func RegisterTestServer(s *grpc.Server, srv TestServer) {
|
||||
s.RegisterService(&_Test_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Test_Call_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Request)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TestServer).Call(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/Test/Call",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TestServer).Call(ctx, req.(*Request))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Test_CallPcre_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Request)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TestServer).CallPcre(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/Test/CallPcre",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TestServer).CallPcre(ctx, req.(*Request))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Test_CallPcreInvalid_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Request)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TestServer).CallPcreInvalid(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/Test/CallPcreInvalid",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TestServer).CallPcreInvalid(ctx, req.(*Request))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Test_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "Test",
|
||||
HandlerType: (*TestServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Call",
|
||||
Handler: _Test_Call_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CallPcre",
|
||||
Handler: _Test_CallPcre_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CallPcreInvalid",
|
||||
Handler: _Test_CallPcreInvalid_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "server/grpc/proto/test.proto",
|
||||
}
|
@@ -1,90 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
"github.com/unistack-org/micro/v3/codec/bytes"
|
||||
)
|
||||
|
||||
type rpcRequest struct {
|
||||
service string
|
||||
method string
|
||||
contentType string
|
||||
codec codec.Codec
|
||||
header map[string]string
|
||||
body []byte
|
||||
stream bool
|
||||
payload interface{}
|
||||
}
|
||||
|
||||
type rpcMessage struct {
|
||||
topic string
|
||||
contentType string
|
||||
payload interface{}
|
||||
header map[string]string
|
||||
body []byte
|
||||
codec codec.Codec
|
||||
}
|
||||
|
||||
func (r *rpcRequest) ContentType() string {
|
||||
return r.contentType
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Service() string {
|
||||
return r.service
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Method() string {
|
||||
return r.method
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Endpoint() string {
|
||||
return r.method
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Codec() codec.Reader {
|
||||
return r.codec
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Header() map[string]string {
|
||||
return r.header
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Read() ([]byte, error) {
|
||||
f := &bytes.Frame{}
|
||||
if err := r.codec.ReadBody(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f.Data, nil
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Stream() bool {
|
||||
return r.stream
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Body() interface{} {
|
||||
return r.payload
|
||||
}
|
||||
|
||||
func (r *rpcMessage) ContentType() string {
|
||||
return r.contentType
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Topic() string {
|
||||
return r.topic
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Payload() interface{} {
|
||||
return r.payload
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Header() map[string]string {
|
||||
return r.header
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Body() []byte {
|
||||
return r.body
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Codec() codec.Reader {
|
||||
return r.codec
|
||||
}
|
@@ -1,27 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
)
|
||||
|
||||
type rpcResponse struct {
|
||||
header map[string]string
|
||||
codec codec.Codec
|
||||
}
|
||||
|
||||
func (r *rpcResponse) Codec() codec.Writer {
|
||||
return r.codec
|
||||
}
|
||||
|
||||
func (r *rpcResponse) WriteHeader(hdr map[string]string) {
|
||||
for k, v := range hdr {
|
||||
r.header[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (r *rpcResponse) Write(b []byte) error {
|
||||
return r.codec.Write(&codec.Message{
|
||||
Header: r.header,
|
||||
Body: b,
|
||||
}, nil)
|
||||
}
|
@@ -1,198 +0,0 @@
|
||||
package grpc
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// Meh, we need to get rid of this shit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"reflect"
|
||||
"sync"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/unistack-org/micro/v3/logger"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
var (
|
||||
// Precompute the reflect type for error. Can't use error directly
|
||||
// because Typeof takes an empty interface value. This is annoying.
|
||||
typeOfError = reflect.TypeOf((*error)(nil)).Elem()
|
||||
)
|
||||
|
||||
type methodType struct {
|
||||
method reflect.Method
|
||||
ArgType reflect.Type
|
||||
ReplyType reflect.Type
|
||||
ContextType reflect.Type
|
||||
stream bool
|
||||
}
|
||||
|
||||
type service struct {
|
||||
name string // name of service
|
||||
rcvr reflect.Value // receiver of methods for the service
|
||||
typ reflect.Type // type of the receiver
|
||||
method map[string]*methodType // registered methods
|
||||
}
|
||||
|
||||
// server represents an RPC Server.
|
||||
type rServer struct {
|
||||
mu sync.Mutex // protects the serviceMap
|
||||
serviceMap map[string]*service
|
||||
}
|
||||
|
||||
// Is this an exported - upper case - name?
|
||||
func isExported(name string) bool {
|
||||
rune, _ := utf8.DecodeRuneInString(name)
|
||||
return unicode.IsUpper(rune)
|
||||
}
|
||||
|
||||
// Is this type exported or a builtin?
|
||||
func isExportedOrBuiltinType(t reflect.Type) bool {
|
||||
for t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
// PkgPath will be non-empty even for an exported type,
|
||||
// so we need to check the type name as well.
|
||||
return isExported(t.Name()) || t.PkgPath() == ""
|
||||
}
|
||||
|
||||
// prepareEndpoint() returns a methodType for the provided method or nil
|
||||
// in case if the method was unsuitable.
|
||||
func prepareEndpoint(method reflect.Method) *methodType {
|
||||
mtype := method.Type
|
||||
mname := method.Name
|
||||
var replyType, argType, contextType reflect.Type
|
||||
var stream bool
|
||||
|
||||
// Endpoint() must be exported.
|
||||
if method.PkgPath != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch mtype.NumIn() {
|
||||
case 3:
|
||||
// assuming streaming
|
||||
argType = mtype.In(2)
|
||||
contextType = mtype.In(1)
|
||||
stream = true
|
||||
case 4:
|
||||
// method that takes a context
|
||||
argType = mtype.In(2)
|
||||
replyType = mtype.In(3)
|
||||
contextType = mtype.In(1)
|
||||
default:
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("method %v of %v has wrong number of ins: %v", mname, mtype, mtype.NumIn())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if stream {
|
||||
// check stream type
|
||||
streamType := reflect.TypeOf((*server.Stream)(nil)).Elem()
|
||||
if !argType.Implements(streamType) {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("%v argument does not implement Streamer interface: %v", mname, argType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
// if not stream check the replyType
|
||||
|
||||
// First arg need not be a pointer.
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("%v argument type not exported: %v", mname, argType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if replyType.Kind() != reflect.Ptr {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("method %v reply type not a pointer: %v", mname, replyType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reply type must be exported.
|
||||
if !isExportedOrBuiltinType(replyType) {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("method %v reply type not exported: %v", mname, replyType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Endpoint() needs one out.
|
||||
if mtype.NumOut() != 1 {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("method %v has wrong number of outs: %v", mname, mtype.NumOut())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// The return type of the method must be error.
|
||||
if returnType := mtype.Out(0); returnType != typeOfError {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("method %v returns %v not error", mname, returnType.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream}
|
||||
}
|
||||
|
||||
func (server *rServer) register(rcvr interface{}) error {
|
||||
server.mu.Lock()
|
||||
defer server.mu.Unlock()
|
||||
if server.serviceMap == nil {
|
||||
server.serviceMap = make(map[string]*service)
|
||||
}
|
||||
s := new(service)
|
||||
s.typ = reflect.TypeOf(rcvr)
|
||||
s.rcvr = reflect.ValueOf(rcvr)
|
||||
sname := reflect.Indirect(s.rcvr).Type().Name()
|
||||
if sname == "" {
|
||||
logger.Fatalf("rpc: no service name for type %v", s.typ.String())
|
||||
}
|
||||
if !isExported(sname) {
|
||||
s := "rpc Register: type " + sname + " is not exported"
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(s)
|
||||
}
|
||||
return errors.New(s)
|
||||
}
|
||||
if _, present := server.serviceMap[sname]; present {
|
||||
return errors.New("rpc: service already defined: " + sname)
|
||||
}
|
||||
s.name = sname
|
||||
s.method = make(map[string]*methodType)
|
||||
|
||||
// Install the methods
|
||||
for m := 0; m < s.typ.NumMethod(); m++ {
|
||||
method := s.typ.Method(m)
|
||||
if mt := prepareEndpoint(method); mt != nil {
|
||||
s.method[method.Name] = mt
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.method) == 0 {
|
||||
s := "rpc Register: type " + sname + " has no exported methods of suitable type"
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(s)
|
||||
}
|
||||
return errors.New(s)
|
||||
}
|
||||
server.serviceMap[s.name] = s
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *methodType) prepareContext(ctx context.Context) reflect.Value {
|
||||
if contextv := reflect.ValueOf(ctx); contextv.IsValid() {
|
||||
return contextv
|
||||
}
|
||||
return reflect.Zero(m.ContextType)
|
||||
}
|
@@ -1,40 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// rpcStream implements a server side Stream.
|
||||
type rpcStream struct {
|
||||
// embed the grpc stream so we can access it
|
||||
grpc.ServerStream
|
||||
|
||||
request server.Request
|
||||
}
|
||||
|
||||
func (r *rpcStream) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *rpcStream) Error() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *rpcStream) Request() server.Request {
|
||||
return r.request
|
||||
}
|
||||
|
||||
func (r *rpcStream) Context() context.Context {
|
||||
return r.ServerStream.Context()
|
||||
}
|
||||
|
||||
func (r *rpcStream) Send(m interface{}) error {
|
||||
return r.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (r *rpcStream) Recv(m interface{}) error {
|
||||
return r.ServerStream.RecvMsg(m)
|
||||
}
|
@@ -1,293 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
"github.com/unistack-org/micro/v3/broker"
|
||||
"github.com/unistack-org/micro/v3/errors"
|
||||
"github.com/unistack-org/micro/v3/logger"
|
||||
"github.com/unistack-org/micro/v3/metadata"
|
||||
"github.com/unistack-org/micro/v3/registry"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
const (
|
||||
subSig = "func(context.Context, interface{}) error"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
method reflect.Value
|
||||
reqType reflect.Type
|
||||
ctxType reflect.Type
|
||||
}
|
||||
|
||||
type subscriber struct {
|
||||
topic string
|
||||
rcvr reflect.Value
|
||||
typ reflect.Type
|
||||
subscriber interface{}
|
||||
handlers []*handler
|
||||
endpoints []*registry.Endpoint
|
||||
opts server.SubscriberOptions
|
||||
}
|
||||
|
||||
func newSubscriber(topic string, sub interface{}, opts ...server.SubscriberOption) server.Subscriber {
|
||||
options := server.SubscriberOptions{
|
||||
AutoAck: true,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
var endpoints []*registry.Endpoint
|
||||
var handlers []*handler
|
||||
|
||||
if typ := reflect.TypeOf(sub); typ.Kind() == reflect.Func {
|
||||
h := &handler{
|
||||
method: reflect.ValueOf(sub),
|
||||
}
|
||||
|
||||
switch typ.NumIn() {
|
||||
case 1:
|
||||
h.reqType = typ.In(0)
|
||||
case 2:
|
||||
h.ctxType = typ.In(0)
|
||||
h.reqType = typ.In(1)
|
||||
}
|
||||
|
||||
handlers = append(handlers, h)
|
||||
|
||||
endpoints = append(endpoints, ®istry.Endpoint{
|
||||
Name: "Func",
|
||||
Request: extractSubValue(typ),
|
||||
Metadata: map[string]string{
|
||||
"topic": topic,
|
||||
"subscriber": "true",
|
||||
},
|
||||
})
|
||||
} else {
|
||||
hdlr := reflect.ValueOf(sub)
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
method := typ.Method(m)
|
||||
h := &handler{
|
||||
method: method.Func,
|
||||
}
|
||||
|
||||
switch method.Type.NumIn() {
|
||||
case 2:
|
||||
h.reqType = method.Type.In(1)
|
||||
case 3:
|
||||
h.ctxType = method.Type.In(1)
|
||||
h.reqType = method.Type.In(2)
|
||||
}
|
||||
|
||||
handlers = append(handlers, h)
|
||||
|
||||
endpoints = append(endpoints, ®istry.Endpoint{
|
||||
Name: name + "." + method.Name,
|
||||
Request: extractSubValue(method.Type),
|
||||
Metadata: map[string]string{
|
||||
"topic": topic,
|
||||
"subscriber": "true",
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &subscriber{
|
||||
rcvr: reflect.ValueOf(sub),
|
||||
typ: reflect.TypeOf(sub),
|
||||
topic: topic,
|
||||
subscriber: sub,
|
||||
handlers: handlers,
|
||||
endpoints: endpoints,
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
func validateSubscriber(sub server.Subscriber) error {
|
||||
typ := reflect.TypeOf(sub.Subscriber())
|
||||
var argType reflect.Type
|
||||
|
||||
if typ.Kind() == reflect.Func {
|
||||
name := "Func"
|
||||
switch typ.NumIn() {
|
||||
case 2:
|
||||
argType = typ.In(1)
|
||||
default:
|
||||
return fmt.Errorf("subscriber %v takes wrong number of args: %v required signature %s", name, typ.NumIn(), subSig)
|
||||
}
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
return fmt.Errorf("subscriber %v argument type not exported: %v", name, argType)
|
||||
}
|
||||
if typ.NumOut() != 1 {
|
||||
return fmt.Errorf("subscriber %v has wrong number of outs: %v require signature %s",
|
||||
name, typ.NumOut(), subSig)
|
||||
}
|
||||
if returnType := typ.Out(0); returnType != typeOfError {
|
||||
return fmt.Errorf("subscriber %v returns %v not error", name, returnType.String())
|
||||
}
|
||||
} else {
|
||||
hdlr := reflect.ValueOf(sub.Subscriber())
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
method := typ.Method(m)
|
||||
|
||||
switch method.Type.NumIn() {
|
||||
case 3:
|
||||
argType = method.Type.In(2)
|
||||
default:
|
||||
return fmt.Errorf("subscriber %v.%v takes wrong number of args: %v required signature %s",
|
||||
name, method.Name, method.Type.NumIn(), subSig)
|
||||
}
|
||||
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
return fmt.Errorf("%v argument type not exported: %v", name, argType)
|
||||
}
|
||||
if method.Type.NumOut() != 1 {
|
||||
return fmt.Errorf(
|
||||
"subscriber %v.%v has wrong number of outs: %v require signature %s",
|
||||
name, method.Name, method.Type.NumOut(), subSig)
|
||||
}
|
||||
if returnType := method.Type.Out(0); returnType != typeOfError {
|
||||
return fmt.Errorf("subscriber %v.%v returns %v not error", name, method.Name, returnType.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broker.Handler {
|
||||
return func(msg *broker.Message) (err error) {
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("panic recovered: ", r)
|
||||
logger.Error(string(debug.Stack()))
|
||||
}
|
||||
err = errors.InternalServerError(g.opts.Name+".subscriber", "panic recovered: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
// if we don't have headers, create empty map
|
||||
if msg.Header == nil {
|
||||
msg.Header = make(map[string]string)
|
||||
}
|
||||
|
||||
ct := msg.Header["Content-Type"]
|
||||
if len(ct) == 0 {
|
||||
msg.Header["Content-Type"] = defaultContentType
|
||||
ct = defaultContentType
|
||||
}
|
||||
cf, err := g.newGRPCCodec(ct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hdr := make(map[string]string, len(msg.Header))
|
||||
for k, v := range msg.Header {
|
||||
hdr[k] = v
|
||||
}
|
||||
delete(hdr, "Content-Type")
|
||||
ctx := metadata.NewContext(context.Background(), hdr)
|
||||
|
||||
results := make(chan error, len(sb.handlers))
|
||||
|
||||
for i := 0; i < len(sb.handlers); i++ {
|
||||
handler := sb.handlers[i]
|
||||
|
||||
var isVal bool
|
||||
var req reflect.Value
|
||||
|
||||
if handler.reqType.Kind() == reflect.Ptr {
|
||||
req = reflect.New(handler.reqType.Elem())
|
||||
} else {
|
||||
req = reflect.New(handler.reqType)
|
||||
isVal = true
|
||||
}
|
||||
if isVal {
|
||||
req = req.Elem()
|
||||
}
|
||||
|
||||
if err = cf.Unmarshal(msg.Body, req.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fn := func(ctx context.Context, msg server.Message) error {
|
||||
var vals []reflect.Value
|
||||
if sb.typ.Kind() != reflect.Func {
|
||||
vals = append(vals, sb.rcvr)
|
||||
}
|
||||
if handler.ctxType != nil {
|
||||
vals = append(vals, reflect.ValueOf(ctx))
|
||||
}
|
||||
|
||||
vals = append(vals, reflect.ValueOf(msg.Payload()))
|
||||
|
||||
returnValues := handler.method.Call(vals)
|
||||
if rerr := returnValues[0].Interface(); rerr != nil {
|
||||
return rerr.(error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := len(opts.SubWrappers); i > 0; i-- {
|
||||
fn = opts.SubWrappers[i-1](fn)
|
||||
}
|
||||
|
||||
if g.wg != nil {
|
||||
g.wg.Add(1)
|
||||
}
|
||||
go func() {
|
||||
if g.wg != nil {
|
||||
defer g.wg.Done()
|
||||
}
|
||||
err := fn(ctx, &rpcMessage{
|
||||
topic: sb.topic,
|
||||
contentType: ct,
|
||||
payload: req.Interface(),
|
||||
header: msg.Header,
|
||||
body: msg.Body,
|
||||
})
|
||||
results <- err
|
||||
}()
|
||||
}
|
||||
var errors []string
|
||||
for i := 0; i < len(sb.handlers); i++ {
|
||||
if rerr := <-results; rerr != nil {
|
||||
errors = append(errors, rerr.Error())
|
||||
}
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
err = fmt.Errorf("subscriber error: %s", strings.Join(errors, "\n"))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (s *subscriber) Topic() string {
|
||||
return s.topic
|
||||
}
|
||||
|
||||
func (s *subscriber) Subscriber() interface{} {
|
||||
return s.subscriber
|
||||
}
|
||||
|
||||
func (s *subscriber) Endpoints() []*registry.Endpoint {
|
||||
return s.endpoints
|
||||
}
|
||||
|
||||
func (s *subscriber) Options() server.SubscriberOptions {
|
||||
return s.opts
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
// convertCode converts a standard Go error into its canonical code. Note that
|
||||
// this is only used to translate the error returned by the server applications.
|
||||
func convertCode(err error) codes.Code {
|
||||
switch err {
|
||||
case nil:
|
||||
return codes.OK
|
||||
case io.EOF:
|
||||
return codes.OutOfRange
|
||||
case io.ErrClosedPipe, io.ErrNoProgress, io.ErrShortBuffer, io.ErrShortWrite, io.ErrUnexpectedEOF:
|
||||
return codes.FailedPrecondition
|
||||
case os.ErrInvalid:
|
||||
return codes.InvalidArgument
|
||||
case context.Canceled:
|
||||
return codes.Canceled
|
||||
case context.DeadlineExceeded:
|
||||
return codes.DeadlineExceeded
|
||||
}
|
||||
switch {
|
||||
case os.IsExist(err):
|
||||
return codes.AlreadyExists
|
||||
case os.IsNotExist(err):
|
||||
return codes.NotFound
|
||||
case os.IsPermission(err):
|
||||
return codes.PermissionDenied
|
||||
}
|
||||
return codes.Unknown
|
||||
}
|
||||
|
||||
func wait(ctx context.Context) *sync.WaitGroup {
|
||||
if ctx == nil {
|
||||
return nil
|
||||
}
|
||||
wg, ok := ctx.Value("wait").(*sync.WaitGroup)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return wg
|
||||
}
|
@@ -1,139 +0,0 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
type MockServer struct {
|
||||
sync.Mutex
|
||||
Running bool
|
||||
Opts server.Options
|
||||
Handlers map[string]server.Handler
|
||||
Subscribers map[string][]server.Subscriber
|
||||
}
|
||||
|
||||
var (
|
||||
_ server.Server = NewServer()
|
||||
)
|
||||
|
||||
func newMockServer(opts ...server.Option) *MockServer {
|
||||
var options server.Options
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return &MockServer{
|
||||
Opts: options,
|
||||
Handlers: make(map[string]server.Handler),
|
||||
Subscribers: make(map[string][]server.Subscriber),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MockServer) Options() server.Options {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
return m.Opts
|
||||
}
|
||||
|
||||
func (m *MockServer) Init(opts ...server.Option) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
for _, o := range opts {
|
||||
o(&m.Opts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockServer) Handle(h server.Handler) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if _, ok := m.Handlers[h.Name()]; ok {
|
||||
return errors.New("Handler " + h.Name() + " already exists")
|
||||
}
|
||||
m.Handlers[h.Name()] = h
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockServer) NewHandler(h interface{}, opts ...server.HandlerOption) server.Handler {
|
||||
var options server.HandlerOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return &MockHandler{
|
||||
Id: uuid.New().String(),
|
||||
Hdlr: h,
|
||||
Opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MockServer) NewSubscriber(topic string, fn interface{}, opts ...server.SubscriberOption) server.Subscriber {
|
||||
var options server.SubscriberOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return &MockSubscriber{
|
||||
Id: topic,
|
||||
Sub: fn,
|
||||
Opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MockServer) Subscribe(sub server.Subscriber) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
subs := m.Subscribers[sub.Topic()]
|
||||
subs = append(subs, sub)
|
||||
m.Subscribers[sub.Topic()] = subs
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockServer) Register() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockServer) Deregister() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockServer) Start() error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if m.Running {
|
||||
return errors.New("already running")
|
||||
}
|
||||
|
||||
m.Running = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockServer) Stop() error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if !m.Running {
|
||||
return errors.New("not running")
|
||||
}
|
||||
|
||||
m.Running = false
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockServer) String() string {
|
||||
return "mock"
|
||||
}
|
||||
|
||||
func NewServer(opts ...server.Option) *MockServer {
|
||||
return newMockServer(opts...)
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"github.com/unistack-org/micro/v3/registry"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
type MockHandler struct {
|
||||
Id string
|
||||
Opts server.HandlerOptions
|
||||
Hdlr interface{}
|
||||
}
|
||||
|
||||
func (m *MockHandler) Name() string {
|
||||
return m.Id
|
||||
}
|
||||
|
||||
func (m *MockHandler) Handler() interface{} {
|
||||
return m.Hdlr
|
||||
}
|
||||
|
||||
func (m *MockHandler) Endpoints() []*registry.Endpoint {
|
||||
return []*registry.Endpoint{}
|
||||
}
|
||||
|
||||
func (m *MockHandler) Options() server.HandlerOptions {
|
||||
return m.Opts
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"github.com/unistack-org/micro/v3/registry"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
type MockSubscriber struct {
|
||||
Id string
|
||||
Opts server.SubscriberOptions
|
||||
Sub interface{}
|
||||
}
|
||||
|
||||
func (m *MockSubscriber) Topic() string {
|
||||
return m.Id
|
||||
}
|
||||
|
||||
func (m *MockSubscriber) Subscriber() interface{} {
|
||||
return m.Sub
|
||||
}
|
||||
|
||||
func (m *MockSubscriber) Endpoints() []*registry.Endpoint {
|
||||
return []*registry.Endpoint{}
|
||||
}
|
||||
|
||||
func (m *MockSubscriber) Options() server.SubscriberOptions {
|
||||
return m.Opts
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
func TestMockServer(t *testing.T) {
|
||||
srv := NewServer(
|
||||
server.Name("mock"),
|
||||
server.Version("latest"),
|
||||
)
|
||||
|
||||
if srv.Options().Name != "mock" {
|
||||
t.Fatalf("Expected name mock, got %s", srv.Options().Name)
|
||||
}
|
||||
|
||||
if srv.Options().Version != "latest" {
|
||||
t.Fatalf("Expected version latest, got %s", srv.Options().Version)
|
||||
}
|
||||
|
||||
srv.Init(server.Version("test"))
|
||||
if srv.Options().Version != "test" {
|
||||
t.Fatalf("Expected version test, got %s", srv.Options().Version)
|
||||
}
|
||||
|
||||
h := srv.NewHandler(func() string { return "foo" })
|
||||
if err := srv.Handle(h); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sub := srv.NewSubscriber("test", func() string { return "foo" })
|
||||
if err := srv.Subscribe(sub); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if sub.Topic() != "test" {
|
||||
t.Fatalf("Expected topic test got %s", sub.Topic())
|
||||
}
|
||||
|
||||
if err := srv.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := srv.Register(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := srv.Deregister(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := srv.Stop(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
@@ -1,128 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/unistack-org/micro/v3/registry"
|
||||
)
|
||||
|
||||
func extractValue(v reflect.Type, d int) *registry.Value {
|
||||
if d == 3 {
|
||||
return nil
|
||||
}
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
arg := ®istry.Value{
|
||||
Name: v.Name(),
|
||||
Type: v.Name(),
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
f := v.Field(i)
|
||||
val := extractValue(f.Type, d+1)
|
||||
if val == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// if we can find a json tag use it
|
||||
if tags := f.Tag.Get("json"); len(tags) > 0 {
|
||||
parts := strings.Split(tags, ",")
|
||||
if parts[0] == "-" || parts[0] == "omitempty" {
|
||||
continue
|
||||
}
|
||||
val.Name = parts[0]
|
||||
}
|
||||
|
||||
// if there's no name default it
|
||||
if len(val.Name) == 0 {
|
||||
val.Name = v.Field(i).Name
|
||||
}
|
||||
|
||||
// still no name then continue
|
||||
if len(val.Name) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
arg.Values = append(arg.Values, val)
|
||||
}
|
||||
case reflect.Slice:
|
||||
p := v.Elem()
|
||||
if p.Kind() == reflect.Ptr {
|
||||
p = p.Elem()
|
||||
}
|
||||
arg.Type = "[]" + p.Name()
|
||||
}
|
||||
|
||||
return arg
|
||||
}
|
||||
|
||||
func extractEndpoint(method reflect.Method) *registry.Endpoint {
|
||||
if method.PkgPath != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var rspType, reqType reflect.Type
|
||||
var stream bool
|
||||
mt := method.Type
|
||||
|
||||
switch mt.NumIn() {
|
||||
case 3:
|
||||
reqType = mt.In(1)
|
||||
rspType = mt.In(2)
|
||||
case 4:
|
||||
reqType = mt.In(2)
|
||||
rspType = mt.In(3)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
// are we dealing with a stream?
|
||||
switch rspType.Kind() {
|
||||
case reflect.Func, reflect.Interface:
|
||||
stream = true
|
||||
}
|
||||
|
||||
request := extractValue(reqType, 0)
|
||||
response := extractValue(rspType, 0)
|
||||
|
||||
ep := ®istry.Endpoint{
|
||||
Name: method.Name,
|
||||
Request: request,
|
||||
Response: response,
|
||||
Metadata: make(map[string]string),
|
||||
}
|
||||
|
||||
// set endpoint metadata for stream
|
||||
if stream {
|
||||
ep.Metadata = map[string]string{
|
||||
"stream": fmt.Sprintf("%v", stream),
|
||||
}
|
||||
}
|
||||
|
||||
return ep
|
||||
}
|
||||
|
||||
func extractSubValue(typ reflect.Type) *registry.Value {
|
||||
var reqType reflect.Type
|
||||
switch typ.NumIn() {
|
||||
case 1:
|
||||
reqType = typ.In(0)
|
||||
case 2:
|
||||
reqType = typ.In(1)
|
||||
case 3:
|
||||
reqType = typ.In(2)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return extractValue(reqType, 0)
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/unistack-org/micro/v3/registry"
|
||||
)
|
||||
|
||||
type testHandler struct{}
|
||||
|
||||
type testRequest struct{}
|
||||
|
||||
type testResponse struct{}
|
||||
|
||||
func (t *testHandler) Test(ctx context.Context, req *testRequest, rsp *testResponse) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestExtractEndpoint(t *testing.T) {
|
||||
handler := &testHandler{}
|
||||
typ := reflect.TypeOf(handler)
|
||||
|
||||
var endpoints []*registry.Endpoint
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
if e := extractEndpoint(typ.Method(m)); e != nil {
|
||||
endpoints = append(endpoints, e)
|
||||
}
|
||||
}
|
||||
|
||||
if i := len(endpoints); i != 1 {
|
||||
t.Errorf("Expected 1 endpoint, have %d", i)
|
||||
}
|
||||
|
||||
if endpoints[0].Name != "Test" {
|
||||
t.Errorf("Expected handler Test, got %s", endpoints[0].Name)
|
||||
}
|
||||
|
||||
if endpoints[0].Request == nil {
|
||||
t.Error("Expected non nil request")
|
||||
}
|
||||
|
||||
if endpoints[0].Response == nil {
|
||||
t.Error("Expected non nil request")
|
||||
}
|
||||
|
||||
if endpoints[0].Request.Name != "testRequest" {
|
||||
t.Errorf("Expected testRequest got %s", endpoints[0].Request.Name)
|
||||
}
|
||||
|
||||
if endpoints[0].Response.Name != "testResponse" {
|
||||
t.Errorf("Expected testResponse got %s", endpoints[0].Response.Name)
|
||||
}
|
||||
|
||||
if endpoints[0].Request.Type != "testRequest" {
|
||||
t.Errorf("Expected testRequest type got %s", endpoints[0].Request.Type)
|
||||
}
|
||||
|
||||
if endpoints[0].Response.Type != "testResponse" {
|
||||
t.Errorf("Expected testResponse type got %s", endpoints[0].Response.Type)
|
||||
}
|
||||
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
// Package mucp provides an mucp server
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultRouter = newRpcRouter()
|
||||
)
|
||||
|
||||
// NewServer returns a micro server interface
|
||||
func NewServer(opts ...server.Option) server.Server {
|
||||
return newServer(opts...)
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"github.com/unistack-org/micro/v3/broker/http"
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
"github.com/unistack-org/micro/v3/registry/mdns"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
thttp "github.com/unistack-org/micro/v3/transport/http"
|
||||
)
|
||||
|
||||
func newOptions(opt ...server.Option) server.Options {
|
||||
opts := server.Options{
|
||||
Codecs: make(map[string]codec.NewCodec),
|
||||
Metadata: map[string]string{},
|
||||
RegisterInterval: server.DefaultRegisterInterval,
|
||||
RegisterTTL: server.DefaultRegisterTTL,
|
||||
}
|
||||
|
||||
for _, o := range opt {
|
||||
o(&opts)
|
||||
}
|
||||
|
||||
if opts.Broker == nil {
|
||||
opts.Broker = http.NewBroker()
|
||||
}
|
||||
|
||||
if opts.Registry == nil {
|
||||
opts.Registry = mdns.NewRegistry()
|
||||
}
|
||||
|
||||
if opts.Transport == nil {
|
||||
opts.Transport = thttp.NewTransport()
|
||||
}
|
||||
|
||||
if opts.RegisterCheck == nil {
|
||||
opts.RegisterCheck = server.DefaultRegisterCheck
|
||||
}
|
||||
|
||||
if len(opts.Address) == 0 {
|
||||
opts.Address = server.DefaultAddress
|
||||
}
|
||||
|
||||
if len(opts.Name) == 0 {
|
||||
opts.Name = server.DefaultName
|
||||
}
|
||||
|
||||
if len(opts.Id) == 0 {
|
||||
opts.Id = server.DefaultId
|
||||
}
|
||||
|
||||
if len(opts.Version) == 0 {
|
||||
opts.Version = server.DefaultVersion
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
@@ -1,354 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
|
||||
"github.com/oxtoacart/bpool"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
raw "github.com/unistack-org/micro/v3/codec/bytes"
|
||||
"github.com/unistack-org/micro/v3/codec/grpc"
|
||||
"github.com/unistack-org/micro/v3/codec/json"
|
||||
"github.com/unistack-org/micro/v3/codec/jsonrpc"
|
||||
"github.com/unistack-org/micro/v3/codec/proto"
|
||||
"github.com/unistack-org/micro/v3/codec/protorpc"
|
||||
"github.com/unistack-org/micro/v3/transport"
|
||||
)
|
||||
|
||||
type rpcCodec struct {
|
||||
socket transport.Socket
|
||||
codec codec.Codec
|
||||
protocol string
|
||||
|
||||
req *transport.Message
|
||||
buf *readWriteCloser
|
||||
|
||||
// check if we're the first
|
||||
sync.RWMutex
|
||||
first chan bool
|
||||
}
|
||||
|
||||
type readWriteCloser struct {
|
||||
sync.RWMutex
|
||||
wbuf *bytes.Buffer
|
||||
rbuf *bytes.Buffer
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultContentType = "application/protobuf"
|
||||
|
||||
DefaultCodecs = map[string]codec.NewCodec{
|
||||
"application/grpc": grpc.NewCodec,
|
||||
"application/grpc+json": grpc.NewCodec,
|
||||
"application/grpc+proto": grpc.NewCodec,
|
||||
"application/json": json.NewCodec,
|
||||
"application/json-rpc": jsonrpc.NewCodec,
|
||||
"application/protobuf": proto.NewCodec,
|
||||
"application/proto-rpc": protorpc.NewCodec,
|
||||
"application/octet-stream": raw.NewCodec,
|
||||
}
|
||||
|
||||
// TODO: remove legacy codec list
|
||||
defaultCodecs = map[string]codec.NewCodec{
|
||||
"application/json": jsonrpc.NewCodec,
|
||||
"application/json-rpc": jsonrpc.NewCodec,
|
||||
"application/protobuf": protorpc.NewCodec,
|
||||
"application/proto-rpc": protorpc.NewCodec,
|
||||
"application/octet-stream": protorpc.NewCodec,
|
||||
}
|
||||
|
||||
// the local buffer pool
|
||||
bufferPool = bpool.NewSizedBufferPool(32, 1)
|
||||
)
|
||||
|
||||
func (rwc *readWriteCloser) Read(p []byte) (n int, err error) {
|
||||
rwc.RLock()
|
||||
defer rwc.RUnlock()
|
||||
return rwc.rbuf.Read(p)
|
||||
}
|
||||
|
||||
func (rwc *readWriteCloser) Write(p []byte) (n int, err error) {
|
||||
rwc.Lock()
|
||||
defer rwc.Unlock()
|
||||
return rwc.wbuf.Write(p)
|
||||
}
|
||||
|
||||
func (rwc *readWriteCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getHeader(hdr string, md map[string]string) string {
|
||||
if hd := md[hdr]; len(hd) > 0 {
|
||||
return hd
|
||||
}
|
||||
return md["X-"+hdr]
|
||||
}
|
||||
|
||||
func getHeaders(m *codec.Message) {
|
||||
set := func(v, hdr string) string {
|
||||
if len(v) > 0 {
|
||||
return v
|
||||
}
|
||||
return m.Header[hdr]
|
||||
}
|
||||
|
||||
m.Id = set(m.Id, "Micro-Id")
|
||||
m.Error = set(m.Error, "Micro-Error")
|
||||
m.Endpoint = set(m.Endpoint, "Micro-Endpoint")
|
||||
m.Method = set(m.Method, "Micro-Method")
|
||||
m.Target = set(m.Target, "Micro-Service")
|
||||
|
||||
// TODO: remove this cruft
|
||||
if len(m.Endpoint) == 0 {
|
||||
m.Endpoint = m.Method
|
||||
}
|
||||
}
|
||||
|
||||
func setHeaders(m, r *codec.Message) {
|
||||
set := func(hdr, v string) {
|
||||
if len(v) == 0 {
|
||||
return
|
||||
}
|
||||
m.Header[hdr] = v
|
||||
m.Header["X-"+hdr] = v
|
||||
}
|
||||
|
||||
// set headers
|
||||
set("Micro-Id", r.Id)
|
||||
set("Micro-Service", r.Target)
|
||||
set("Micro-Method", r.Method)
|
||||
set("Micro-Endpoint", r.Endpoint)
|
||||
set("Micro-Error", r.Error)
|
||||
}
|
||||
|
||||
// setupProtocol sets up the old protocol
|
||||
func setupProtocol(msg *transport.Message) codec.NewCodec {
|
||||
service := getHeader("Micro-Service", msg.Header)
|
||||
method := getHeader("Micro-Method", msg.Header)
|
||||
endpoint := getHeader("Micro-Endpoint", msg.Header)
|
||||
protocol := getHeader("Micro-Protocol", msg.Header)
|
||||
target := getHeader("Micro-Target", msg.Header)
|
||||
topic := getHeader("Micro-Topic", msg.Header)
|
||||
|
||||
// if the protocol exists (mucp) do nothing
|
||||
if len(protocol) > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// newer method of processing messages over transport
|
||||
if len(topic) > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if no service/method/endpoint then it's the old protocol
|
||||
if len(service) == 0 && len(method) == 0 && len(endpoint) == 0 {
|
||||
return defaultCodecs[msg.Header["Content-Type"]]
|
||||
}
|
||||
|
||||
// old target method specified
|
||||
if len(target) > 0 {
|
||||
return defaultCodecs[msg.Header["Content-Type"]]
|
||||
}
|
||||
|
||||
// no method then set to endpoint
|
||||
if len(method) == 0 {
|
||||
msg.Header["Micro-Method"] = endpoint
|
||||
}
|
||||
|
||||
// no endpoint then set to method
|
||||
if len(endpoint) == 0 {
|
||||
msg.Header["Micro-Endpoint"] = method
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newRpcCodec(req *transport.Message, socket transport.Socket, c codec.NewCodec) codec.Codec {
|
||||
rwc := &readWriteCloser{
|
||||
rbuf: bufferPool.Get(),
|
||||
wbuf: bufferPool.Get(),
|
||||
}
|
||||
|
||||
r := &rpcCodec{
|
||||
buf: rwc,
|
||||
codec: c(rwc),
|
||||
req: req,
|
||||
socket: socket,
|
||||
protocol: "mucp",
|
||||
first: make(chan bool),
|
||||
}
|
||||
|
||||
// if grpc pre-load the buffer
|
||||
// TODO: remove this terrible hack
|
||||
switch r.codec.String() {
|
||||
case "grpc":
|
||||
// write the body
|
||||
rwc.rbuf.Write(req.Body)
|
||||
// set the protocol
|
||||
r.protocol = "grpc"
|
||||
default:
|
||||
// first is not preloaded
|
||||
close(r.first)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (c *rpcCodec) ReadHeader(r *codec.Message, t codec.MessageType) error {
|
||||
// the initial message
|
||||
m := codec.Message{
|
||||
Header: c.req.Header,
|
||||
Body: c.req.Body,
|
||||
}
|
||||
|
||||
// first message could be pre-loaded
|
||||
select {
|
||||
case <-c.first:
|
||||
// not the first
|
||||
var tm transport.Message
|
||||
|
||||
// read off the socket
|
||||
if err := c.socket.Recv(&tm); err != nil {
|
||||
return err
|
||||
}
|
||||
// reset the read buffer
|
||||
c.buf.rbuf.Reset()
|
||||
|
||||
// write the body to the buffer
|
||||
if _, err := c.buf.rbuf.Write(tm.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the message header
|
||||
m.Header = tm.Header
|
||||
// set the message body
|
||||
m.Body = tm.Body
|
||||
|
||||
// set req
|
||||
c.req = &tm
|
||||
default:
|
||||
// we need to lock here to prevent race conditions
|
||||
// and we make use of a channel otherwise because
|
||||
// this does not result in a context switch
|
||||
// locking to check c.first on every call to ReadHeader
|
||||
// would otherwise drastically slow the code execution
|
||||
c.Lock()
|
||||
// recheck before closing because the select statement
|
||||
// above is not thread safe, so thread safety here is
|
||||
// mandatory
|
||||
select {
|
||||
case <-c.first:
|
||||
default:
|
||||
// disable first
|
||||
close(c.first)
|
||||
}
|
||||
// now unlock and we never need this again
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
// set some internal things
|
||||
getHeaders(&m)
|
||||
|
||||
// read header via codec
|
||||
if err := c.codec.ReadHeader(&m, codec.Request); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// fallback for 0.14 and older
|
||||
if len(m.Endpoint) == 0 {
|
||||
m.Endpoint = m.Method
|
||||
}
|
||||
|
||||
// set message
|
||||
*r = m
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *rpcCodec) ReadBody(b interface{}) error {
|
||||
// don't read empty body
|
||||
if len(c.req.Body) == 0 {
|
||||
return nil
|
||||
}
|
||||
// read raw data
|
||||
if v, ok := b.(*raw.Frame); ok {
|
||||
v.Data = c.req.Body
|
||||
return nil
|
||||
}
|
||||
// decode the usual way
|
||||
return c.codec.ReadBody(b)
|
||||
}
|
||||
|
||||
func (c *rpcCodec) Write(r *codec.Message, b interface{}) error {
|
||||
c.buf.wbuf.Reset()
|
||||
|
||||
// create a new message
|
||||
m := &codec.Message{
|
||||
Target: r.Target,
|
||||
Method: r.Method,
|
||||
Endpoint: r.Endpoint,
|
||||
Id: r.Id,
|
||||
Error: r.Error,
|
||||
Type: r.Type,
|
||||
Header: r.Header,
|
||||
}
|
||||
|
||||
if m.Header == nil {
|
||||
m.Header = map[string]string{}
|
||||
}
|
||||
|
||||
setHeaders(m, r)
|
||||
|
||||
// the body being sent
|
||||
var body []byte
|
||||
|
||||
// is it a raw frame?
|
||||
if v, ok := b.(*raw.Frame); ok {
|
||||
body = v.Data
|
||||
// if we have encoded data just send it
|
||||
} else if len(r.Body) > 0 {
|
||||
body = r.Body
|
||||
// write the body to codec
|
||||
} else if err := c.codec.Write(m, b); err != nil {
|
||||
c.buf.wbuf.Reset()
|
||||
|
||||
// write an error if it failed
|
||||
m.Error = errors.Wrapf(err, "Unable to encode body").Error()
|
||||
m.Header["Micro-Error"] = m.Error
|
||||
// no body to write
|
||||
if err := c.codec.Write(m, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// set the body
|
||||
body = c.buf.wbuf.Bytes()
|
||||
}
|
||||
|
||||
// Set content type if theres content
|
||||
if len(body) > 0 {
|
||||
m.Header["Content-Type"] = c.req.Header["Content-Type"]
|
||||
}
|
||||
|
||||
// send on the socket
|
||||
return c.socket.Send(&transport.Message{
|
||||
Header: m.Header,
|
||||
Body: body,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *rpcCodec) Close() error {
|
||||
// close the codec
|
||||
c.codec.Close()
|
||||
// close the socket
|
||||
err := c.socket.Close()
|
||||
// put back the buffers
|
||||
bufferPool.Put(c.buf.rbuf)
|
||||
bufferPool.Put(c.buf.wbuf)
|
||||
// return the error
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *rpcCodec) String() string {
|
||||
return c.protocol
|
||||
}
|
@@ -1,109 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
"github.com/unistack-org/micro/v3/transport"
|
||||
)
|
||||
|
||||
// testCodec is a dummy codec that only knows how to encode nil bodies
|
||||
type testCodec struct {
|
||||
buf *bytes.Buffer
|
||||
}
|
||||
|
||||
type testSocket struct {
|
||||
local string
|
||||
remote string
|
||||
}
|
||||
|
||||
// TestCodecWriteError simulates what happens when a codec is unable
|
||||
// to encode a message (e.g. a missing branch of an "oneof" message in
|
||||
// protobufs)
|
||||
//
|
||||
// We expect an error to be sent to the socket. Previously the socket
|
||||
// would remain open with no bytes sent, leading to client-side
|
||||
// timeouts.
|
||||
func TestCodecWriteError(t *testing.T) {
|
||||
socket := testSocket{}
|
||||
message := transport.Message{
|
||||
Header: map[string]string{},
|
||||
Body: []byte{},
|
||||
}
|
||||
|
||||
rwc := readWriteCloser{
|
||||
rbuf: new(bytes.Buffer),
|
||||
wbuf: new(bytes.Buffer),
|
||||
}
|
||||
|
||||
c := rpcCodec{
|
||||
buf: &rwc,
|
||||
codec: &testCodec{
|
||||
buf: rwc.wbuf,
|
||||
},
|
||||
req: &message,
|
||||
socket: socket,
|
||||
}
|
||||
|
||||
err := c.Write(&codec.Message{
|
||||
Endpoint: "Service.Endpoint",
|
||||
Id: "0",
|
||||
Error: "",
|
||||
}, "body")
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf(`Expected Write to fail; got "%+v" instead`, err)
|
||||
}
|
||||
|
||||
const expectedError = "Unable to encode body: simulating a codec write failure"
|
||||
actualError := rwc.wbuf.String()
|
||||
if actualError != expectedError {
|
||||
t.Fatalf(`Expected error "%+v" in the write buffer, got "%+v" instead`, expectedError, actualError)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *testCodec) ReadHeader(message *codec.Message, typ codec.MessageType) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *testCodec) ReadBody(dest interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *testCodec) Write(message *codec.Message, dest interface{}) error {
|
||||
if dest != nil {
|
||||
return errors.New("simulating a codec write failure")
|
||||
}
|
||||
c.buf.Write([]byte(message.Error))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *testCodec) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *testCodec) String() string {
|
||||
return "string"
|
||||
}
|
||||
|
||||
func (s testSocket) Local() string {
|
||||
return s.local
|
||||
}
|
||||
|
||||
func (s testSocket) Remote() string {
|
||||
return s.remote
|
||||
}
|
||||
|
||||
func (s testSocket) Recv(message *transport.Message) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s testSocket) Send(message *transport.Message) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s testSocket) Close() error {
|
||||
return nil
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/unistack-org/micro/v3/registry"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
type rpcHandler struct {
|
||||
name string
|
||||
handler interface{}
|
||||
endpoints []*registry.Endpoint
|
||||
opts server.HandlerOptions
|
||||
}
|
||||
|
||||
func newRpcHandler(handler interface{}, opts ...server.HandlerOption) server.Handler {
|
||||
options := server.HandlerOptions{
|
||||
Metadata: make(map[string]map[string]string),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
typ := reflect.TypeOf(handler)
|
||||
hdlr := reflect.ValueOf(handler)
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
var endpoints []*registry.Endpoint
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
if e := extractEndpoint(typ.Method(m)); e != nil {
|
||||
e.Name = name + "." + e.Name
|
||||
|
||||
for k, v := range options.Metadata[e.Name] {
|
||||
e.Metadata[k] = v
|
||||
}
|
||||
|
||||
endpoints = append(endpoints, e)
|
||||
}
|
||||
}
|
||||
|
||||
return &rpcHandler{
|
||||
name: name,
|
||||
handler: handler,
|
||||
endpoints: endpoints,
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Name() string {
|
||||
return r.name
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Handler() interface{} {
|
||||
return r.handler
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Endpoints() []*registry.Endpoint {
|
||||
return r.endpoints
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Options() server.HandlerOptions {
|
||||
return r.opts
|
||||
}
|
@@ -1,107 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
"github.com/unistack-org/micro/v3/transport"
|
||||
"github.com/unistack-org/micro/v3/util/buf"
|
||||
)
|
||||
|
||||
type rpcRequest struct {
|
||||
service string
|
||||
method string
|
||||
endpoint string
|
||||
contentType string
|
||||
socket transport.Socket
|
||||
codec codec.Codec
|
||||
header map[string]string
|
||||
body []byte
|
||||
rawBody interface{}
|
||||
stream bool
|
||||
first bool
|
||||
}
|
||||
|
||||
type rpcMessage struct {
|
||||
topic string
|
||||
contentType string
|
||||
payload interface{}
|
||||
header map[string]string
|
||||
body []byte
|
||||
codec codec.NewCodec
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Codec() codec.Reader {
|
||||
return r.codec
|
||||
}
|
||||
|
||||
func (r *rpcRequest) ContentType() string {
|
||||
return r.contentType
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Service() string {
|
||||
return r.service
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Method() string {
|
||||
return r.method
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Endpoint() string {
|
||||
return r.endpoint
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Header() map[string]string {
|
||||
return r.header
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Body() interface{} {
|
||||
return r.rawBody
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Read() ([]byte, error) {
|
||||
// got a body
|
||||
if r.first {
|
||||
b := r.body
|
||||
r.first = false
|
||||
return b, nil
|
||||
}
|
||||
|
||||
var msg transport.Message
|
||||
err := r.socket.Recv(&msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.header = msg.Header
|
||||
|
||||
return msg.Body, nil
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Stream() bool {
|
||||
return r.stream
|
||||
}
|
||||
|
||||
func (r *rpcMessage) ContentType() string {
|
||||
return r.contentType
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Topic() string {
|
||||
return r.topic
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Payload() interface{} {
|
||||
return r.payload
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Header() map[string]string {
|
||||
return r.header
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Body() []byte {
|
||||
return r.body
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Codec() codec.Reader {
|
||||
b := buf.New(bytes.NewBuffer(r.body))
|
||||
return r.codec(b)
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
"github.com/unistack-org/micro/v3/transport"
|
||||
)
|
||||
|
||||
type rpcResponse struct {
|
||||
header map[string]string
|
||||
socket transport.Socket
|
||||
codec codec.Codec
|
||||
}
|
||||
|
||||
func (r *rpcResponse) Codec() codec.Writer {
|
||||
return r.codec
|
||||
}
|
||||
|
||||
func (r *rpcResponse) WriteHeader(hdr map[string]string) {
|
||||
for k, v := range hdr {
|
||||
r.header[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (r *rpcResponse) Write(b []byte) error {
|
||||
if _, ok := r.header["Content-Type"]; !ok {
|
||||
r.header["Content-Type"] = http.DetectContentType(b)
|
||||
}
|
||||
|
||||
return r.socket.Send(&transport.Message{
|
||||
Header: r.header,
|
||||
Body: b,
|
||||
})
|
||||
}
|
@@ -1,618 +0,0 @@
|
||||
package mucp
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// Meh, we need to get rid of this shit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"sync"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
merrors "github.com/unistack-org/micro/v3/errors"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
var (
|
||||
lastStreamResponseError = errors.New("EOS")
|
||||
|
||||
// Precompute the reflect type for error. Can't use error directly
|
||||
// because Typeof takes an empty interface value. This is annoying.
|
||||
typeOfError = reflect.TypeOf((*error)(nil)).Elem()
|
||||
)
|
||||
|
||||
type methodType struct {
|
||||
sync.Mutex // protects counters
|
||||
method reflect.Method
|
||||
ArgType reflect.Type
|
||||
ReplyType reflect.Type
|
||||
ContextType reflect.Type
|
||||
stream bool
|
||||
}
|
||||
|
||||
type service struct {
|
||||
name string // name of service
|
||||
rcvr reflect.Value // receiver of methods for the service
|
||||
typ reflect.Type // type of the receiver
|
||||
method map[string]*methodType // registered methods
|
||||
}
|
||||
|
||||
type request struct {
|
||||
msg *codec.Message
|
||||
next *request // for free list in Server
|
||||
}
|
||||
|
||||
type response struct {
|
||||
msg *codec.Message
|
||||
next *response // for free list in Server
|
||||
}
|
||||
|
||||
// router represents an RPC router.
|
||||
type router struct {
|
||||
mu sync.Mutex // protects the serviceMap
|
||||
serviceMap map[string]*service
|
||||
|
||||
reqLock sync.Mutex // protects freeReq
|
||||
freeReq *request
|
||||
|
||||
respLock sync.Mutex // protects freeResp
|
||||
freeResp *response
|
||||
|
||||
// handler wrappers
|
||||
hdlrWrappers []server.HandlerWrapper
|
||||
// subscriber wrappers
|
||||
subWrappers []server.SubscriberWrapper
|
||||
|
||||
su sync.RWMutex
|
||||
subscribers map[string][]*subscriber
|
||||
}
|
||||
|
||||
// rpcRouter encapsulates functions that become a server.Router
|
||||
type rpcRouter struct {
|
||||
h func(context.Context, server.Request, interface{}) error
|
||||
m func(context.Context, server.Message) error
|
||||
}
|
||||
|
||||
func (r rpcRouter) ProcessMessage(ctx context.Context, msg server.Message) error {
|
||||
return r.m(ctx, msg)
|
||||
}
|
||||
|
||||
func (r rpcRouter) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error {
|
||||
return r.h(ctx, req, rsp)
|
||||
}
|
||||
|
||||
func newRpcRouter() *router {
|
||||
return &router{
|
||||
serviceMap: make(map[string]*service),
|
||||
subscribers: make(map[string][]*subscriber),
|
||||
}
|
||||
}
|
||||
|
||||
// Is this an exported - upper case - name?
|
||||
func isExported(name string) bool {
|
||||
rune, _ := utf8.DecodeRuneInString(name)
|
||||
return unicode.IsUpper(rune)
|
||||
}
|
||||
|
||||
// Is this type exported or a builtin?
|
||||
func isExportedOrBuiltinType(t reflect.Type) bool {
|
||||
for t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
// PkgPath will be non-empty even for an exported type,
|
||||
// so we need to check the type name as well.
|
||||
return isExported(t.Name()) || t.PkgPath() == ""
|
||||
}
|
||||
|
||||
// prepareMethod returns a methodType for the provided method or nil
|
||||
// in case if the method was unsuitable.
|
||||
func prepareMethod(method reflect.Method) *methodType {
|
||||
mtype := method.Type
|
||||
mname := method.Name
|
||||
var replyType, argType, contextType reflect.Type
|
||||
var stream bool
|
||||
|
||||
// Method must be exported.
|
||||
if method.PkgPath != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch mtype.NumIn() {
|
||||
case 3:
|
||||
// assuming streaming
|
||||
argType = mtype.In(2)
|
||||
contextType = mtype.In(1)
|
||||
stream = true
|
||||
case 4:
|
||||
// method that takes a context
|
||||
argType = mtype.In(2)
|
||||
replyType = mtype.In(3)
|
||||
contextType = mtype.In(1)
|
||||
default:
|
||||
log.Errorf("method %v of %v has wrong number of ins: %v", mname, mtype, mtype.NumIn())
|
||||
return nil
|
||||
}
|
||||
|
||||
if stream {
|
||||
// check stream type
|
||||
streamType := reflect.TypeOf((*server.Stream)(nil)).Elem()
|
||||
if !argType.Implements(streamType) {
|
||||
log.Errorf("%v argument does not implement Stream interface: %v", mname, argType)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
// if not stream check the replyType
|
||||
|
||||
// First arg need not be a pointer.
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
log.Errorf("%v argument type not exported: %v", mname, argType)
|
||||
return nil
|
||||
}
|
||||
|
||||
if replyType.Kind() != reflect.Ptr {
|
||||
log.Errorf("method %v reply type not a pointer: %v", mname, replyType)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reply type must be exported.
|
||||
if !isExportedOrBuiltinType(replyType) {
|
||||
log.Errorf("method %v reply type not exported: %v", mname, replyType)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Method needs one out.
|
||||
if mtype.NumOut() != 1 {
|
||||
log.Errorf("method %v has wrong number of outs: %v", mname, mtype.NumOut())
|
||||
return nil
|
||||
}
|
||||
// The return type of the method must be error.
|
||||
if returnType := mtype.Out(0); returnType != typeOfError {
|
||||
log.Errorf("method %v returns %v not error", mname, returnType.String())
|
||||
return nil
|
||||
}
|
||||
return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream}
|
||||
}
|
||||
|
||||
func (router *router) sendResponse(sending sync.Locker, req *request, reply interface{}, cc codec.Writer, last bool) error {
|
||||
msg := new(codec.Message)
|
||||
msg.Type = codec.Response
|
||||
resp := router.getResponse()
|
||||
resp.msg = msg
|
||||
|
||||
resp.msg.Id = req.msg.Id
|
||||
sending.Lock()
|
||||
err := cc.Write(resp.msg, reply)
|
||||
sending.Unlock()
|
||||
router.freeResponse(resp)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *service) call(ctx context.Context, router *router, sending *sync.Mutex, mtype *methodType, req *request, argv, replyv reflect.Value, cc codec.Writer) error {
|
||||
defer router.freeRequest(req)
|
||||
|
||||
function := mtype.method.Func
|
||||
var returnValues []reflect.Value
|
||||
|
||||
r := &rpcRequest{
|
||||
service: req.msg.Target,
|
||||
contentType: req.msg.Header["Content-Type"],
|
||||
method: req.msg.Method,
|
||||
endpoint: req.msg.Endpoint,
|
||||
body: req.msg.Body,
|
||||
header: req.msg.Header,
|
||||
}
|
||||
|
||||
// only set if not nil
|
||||
if argv.IsValid() {
|
||||
r.rawBody = argv.Interface()
|
||||
}
|
||||
|
||||
if !mtype.stream {
|
||||
fn := func(ctx context.Context, req server.Request, rsp interface{}) error {
|
||||
returnValues = function.Call([]reflect.Value{s.rcvr, mtype.prepareContext(ctx), reflect.ValueOf(argv.Interface()), reflect.ValueOf(rsp)})
|
||||
|
||||
// The return value for the method is an error.
|
||||
if err := returnValues[0].Interface(); err != nil {
|
||||
return err.(error)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// wrap the handler
|
||||
for i := len(router.hdlrWrappers); i > 0; i-- {
|
||||
fn = router.hdlrWrappers[i-1](fn)
|
||||
}
|
||||
|
||||
// execute handler
|
||||
if err := fn(ctx, r, replyv.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// send response
|
||||
return router.sendResponse(sending, req, replyv.Interface(), cc, true)
|
||||
}
|
||||
|
||||
// declare a local error to see if we errored out already
|
||||
// keep track of the type, to make sure we return
|
||||
// the same one consistently
|
||||
rawStream := &rpcStream{
|
||||
context: ctx,
|
||||
codec: cc.(codec.Codec),
|
||||
request: r,
|
||||
id: req.msg.Id,
|
||||
}
|
||||
|
||||
// Invoke the method, providing a new value for the reply.
|
||||
fn := func(ctx context.Context, req server.Request, stream interface{}) error {
|
||||
returnValues = function.Call([]reflect.Value{s.rcvr, mtype.prepareContext(ctx), reflect.ValueOf(stream)})
|
||||
if err := returnValues[0].Interface(); err != nil {
|
||||
// the function returned an error, we use that
|
||||
return err.(error)
|
||||
} else if serr := rawStream.Error(); serr == io.EOF || serr == io.ErrUnexpectedEOF {
|
||||
return nil
|
||||
} else {
|
||||
// no error, we send the special EOS error
|
||||
return lastStreamResponseError
|
||||
}
|
||||
}
|
||||
|
||||
// wrap the handler
|
||||
for i := len(router.hdlrWrappers); i > 0; i-- {
|
||||
fn = router.hdlrWrappers[i-1](fn)
|
||||
}
|
||||
|
||||
// client.Stream request
|
||||
r.stream = true
|
||||
|
||||
// execute handler
|
||||
return fn(ctx, r, rawStream)
|
||||
}
|
||||
|
||||
func (m *methodType) prepareContext(ctx context.Context) reflect.Value {
|
||||
if contextv := reflect.ValueOf(ctx); contextv.IsValid() {
|
||||
return contextv
|
||||
}
|
||||
return reflect.Zero(m.ContextType)
|
||||
}
|
||||
|
||||
func (router *router) getRequest() *request {
|
||||
router.reqLock.Lock()
|
||||
req := router.freeReq
|
||||
if req == nil {
|
||||
req = new(request)
|
||||
} else {
|
||||
router.freeReq = req.next
|
||||
*req = request{}
|
||||
}
|
||||
router.reqLock.Unlock()
|
||||
return req
|
||||
}
|
||||
|
||||
func (router *router) freeRequest(req *request) {
|
||||
router.reqLock.Lock()
|
||||
req.next = router.freeReq
|
||||
router.freeReq = req
|
||||
router.reqLock.Unlock()
|
||||
}
|
||||
|
||||
func (router *router) getResponse() *response {
|
||||
router.respLock.Lock()
|
||||
resp := router.freeResp
|
||||
if resp == nil {
|
||||
resp = new(response)
|
||||
} else {
|
||||
router.freeResp = resp.next
|
||||
*resp = response{}
|
||||
}
|
||||
router.respLock.Unlock()
|
||||
return resp
|
||||
}
|
||||
|
||||
func (router *router) freeResponse(resp *response) {
|
||||
router.respLock.Lock()
|
||||
resp.next = router.freeResp
|
||||
router.freeResp = resp
|
||||
router.respLock.Unlock()
|
||||
}
|
||||
|
||||
func (router *router) readRequest(r server.Request) (service *service, mtype *methodType, req *request, argv, replyv reflect.Value, keepReading bool, err error) {
|
||||
cc := r.Codec()
|
||||
|
||||
service, mtype, req, keepReading, err = router.readHeader(cc)
|
||||
if err != nil {
|
||||
if !keepReading {
|
||||
return
|
||||
}
|
||||
// discard body
|
||||
cc.ReadBody(nil)
|
||||
return
|
||||
}
|
||||
// is it a streaming request? then we don't read the body
|
||||
if mtype.stream {
|
||||
if cc.(codec.Codec).String() != "grpc" {
|
||||
cc.ReadBody(nil)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Decode the argument value.
|
||||
argIsValue := false // if true, need to indirect before calling.
|
||||
if mtype.ArgType.Kind() == reflect.Ptr {
|
||||
argv = reflect.New(mtype.ArgType.Elem())
|
||||
} else {
|
||||
argv = reflect.New(mtype.ArgType)
|
||||
argIsValue = true
|
||||
}
|
||||
// argv guaranteed to be a pointer now.
|
||||
if err = cc.ReadBody(argv.Interface()); err != nil {
|
||||
return
|
||||
}
|
||||
if argIsValue {
|
||||
argv = argv.Elem()
|
||||
}
|
||||
|
||||
if !mtype.stream {
|
||||
replyv = reflect.New(mtype.ReplyType.Elem())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (router *router) readHeader(cc codec.Reader) (*service, *methodType, *request, bool, error) {
|
||||
var err error
|
||||
var service *service
|
||||
var mtype *methodType
|
||||
var req *request
|
||||
|
||||
// Grab the request header.
|
||||
msg := new(codec.Message)
|
||||
msg.Type = codec.Request
|
||||
req = router.getRequest()
|
||||
req.msg = msg
|
||||
|
||||
err = cc.ReadHeader(msg, msg.Type)
|
||||
if err != nil {
|
||||
req = nil
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
return nil, nil, nil, false, err
|
||||
}
|
||||
return nil, nil, nil, false, fmt.Errorf("rpc: router cannot decode request: %v", err)
|
||||
}
|
||||
|
||||
// We read the header successfully. If we see an error now,
|
||||
// we can still recover and move on to the next request.
|
||||
keepReading := true
|
||||
|
||||
serviceMethod := strings.Split(req.msg.Endpoint, ".")
|
||||
if len(serviceMethod) != 2 {
|
||||
return nil, nil, nil, keepReading, fmt.Errorf("rpc: service/endpoint request ill-formed: %v", req.msg.Endpoint)
|
||||
}
|
||||
// Look up the request.
|
||||
router.mu.Lock()
|
||||
service = router.serviceMap[serviceMethod[0]]
|
||||
router.mu.Unlock()
|
||||
if service == nil {
|
||||
return nil, nil, nil, keepReading, fmt.Errorf("rpc: can't find service %v", serviceMethod[0])
|
||||
}
|
||||
mtype = service.method[serviceMethod[1]]
|
||||
if mtype == nil {
|
||||
return nil, nil, nil, keepReading, fmt.Errorf("rpc: can't find method %v", serviceMethod[1])
|
||||
}
|
||||
|
||||
return service, mtype, req, keepReading, nil
|
||||
}
|
||||
|
||||
func (router *router) NewHandler(h interface{}, opts ...server.HandlerOption) server.Handler {
|
||||
return newRpcHandler(h, opts...)
|
||||
}
|
||||
|
||||
func (router *router) Handle(h server.Handler) error {
|
||||
router.mu.Lock()
|
||||
defer router.mu.Unlock()
|
||||
if router.serviceMap == nil {
|
||||
router.serviceMap = make(map[string]*service)
|
||||
}
|
||||
|
||||
if len(h.Name()) == 0 {
|
||||
return errors.New("rpc.Handle: handler has no name")
|
||||
}
|
||||
if !isExported(h.Name()) {
|
||||
return errors.New("rpc.Handle: type " + h.Name() + " is not exported")
|
||||
}
|
||||
|
||||
rcvr := h.Handler()
|
||||
s := new(service)
|
||||
s.typ = reflect.TypeOf(rcvr)
|
||||
s.rcvr = reflect.ValueOf(rcvr)
|
||||
|
||||
// check name
|
||||
if _, present := router.serviceMap[h.Name()]; present {
|
||||
return errors.New("rpc.Handle: service already defined: " + h.Name())
|
||||
}
|
||||
|
||||
s.name = h.Name()
|
||||
s.method = make(map[string]*methodType)
|
||||
|
||||
// Install the methods
|
||||
for m := 0; m < s.typ.NumMethod(); m++ {
|
||||
method := s.typ.Method(m)
|
||||
if mt := prepareMethod(method); mt != nil {
|
||||
s.method[method.Name] = mt
|
||||
}
|
||||
}
|
||||
|
||||
// Check there are methods
|
||||
if len(s.method) == 0 {
|
||||
return errors.New("rpc Register: type " + s.name + " has no exported methods of suitable type")
|
||||
}
|
||||
|
||||
// save handler
|
||||
router.serviceMap[s.name] = s
|
||||
return nil
|
||||
}
|
||||
|
||||
func (router *router) ServeRequest(ctx context.Context, r server.Request, rsp server.Response) error {
|
||||
sending := new(sync.Mutex)
|
||||
service, mtype, req, argv, replyv, keepReading, err := router.readRequest(r)
|
||||
if err != nil {
|
||||
if !keepReading {
|
||||
return err
|
||||
}
|
||||
// send a response if we actually managed to read a header.
|
||||
if req != nil {
|
||||
router.freeRequest(req)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return service.call(ctx, router, sending, mtype, req, argv, replyv, rsp.Codec())
|
||||
}
|
||||
|
||||
func (router *router) NewSubscriber(topic string, handler interface{}, opts ...server.SubscriberOption) server.Subscriber {
|
||||
return newSubscriber(topic, handler, opts...)
|
||||
}
|
||||
|
||||
func (router *router) Subscribe(s server.Subscriber) error {
|
||||
sub, ok := s.(*subscriber)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid subscriber: expected *subscriber")
|
||||
}
|
||||
if len(sub.handlers) == 0 {
|
||||
return fmt.Errorf("invalid subscriber: no handler functions")
|
||||
}
|
||||
|
||||
if err := validateSubscriber(sub); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
router.su.Lock()
|
||||
defer router.su.Unlock()
|
||||
|
||||
// append to subscribers
|
||||
subs := router.subscribers[sub.Topic()]
|
||||
subs = append(subs, sub)
|
||||
router.subscribers[sub.Topic()] = subs
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (router *router) String() string {
|
||||
return "mucp"
|
||||
}
|
||||
|
||||
func (router *router) ProcessMessage(ctx context.Context, msg server.Message) (err error) {
|
||||
defer func() {
|
||||
// recover any panics
|
||||
if r := recover(); r != nil {
|
||||
log.Errorf("panic recovered: %v", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
err = merrors.InternalServerError("go.micro.server", "panic recovered: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
router.su.RLock()
|
||||
// get the subscribers by topic
|
||||
subs, ok := router.subscribers[msg.Topic()]
|
||||
// unlock since we only need to get the subs
|
||||
router.su.RUnlock()
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
var errResults []string
|
||||
|
||||
// we may have multiple subscribers for the topic
|
||||
for _, sub := range subs {
|
||||
// we may have multiple handlers per subscriber
|
||||
for i := 0; i < len(sub.handlers); i++ {
|
||||
// get the handler
|
||||
handler := sub.handlers[i]
|
||||
|
||||
var isVal bool
|
||||
var req reflect.Value
|
||||
|
||||
// check whether the handler is a pointer
|
||||
if handler.reqType.Kind() == reflect.Ptr {
|
||||
req = reflect.New(handler.reqType.Elem())
|
||||
} else {
|
||||
req = reflect.New(handler.reqType)
|
||||
isVal = true
|
||||
}
|
||||
|
||||
// if its a value get the element
|
||||
if isVal {
|
||||
req = req.Elem()
|
||||
}
|
||||
|
||||
cc := msg.Codec()
|
||||
|
||||
// read the header. mostly a noop
|
||||
if err = cc.ReadHeader(&codec.Message{}, codec.Event); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// read the body into the handler request value
|
||||
if err = cc.ReadBody(req.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create the handler which will honour the SubscriberFunc type
|
||||
fn := func(ctx context.Context, msg server.Message) error {
|
||||
var vals []reflect.Value
|
||||
if sub.typ.Kind() != reflect.Func {
|
||||
vals = append(vals, sub.rcvr)
|
||||
}
|
||||
if handler.ctxType != nil {
|
||||
vals = append(vals, reflect.ValueOf(ctx))
|
||||
}
|
||||
|
||||
// values to pass the handler
|
||||
vals = append(vals, reflect.ValueOf(msg.Payload()))
|
||||
|
||||
// execute the actuall call of the handler
|
||||
returnValues := handler.method.Call(vals)
|
||||
if rerr := returnValues[0].Interface(); rerr != nil {
|
||||
err = rerr.(error)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// wrap with subscriber wrappers
|
||||
for i := len(router.subWrappers); i > 0; i-- {
|
||||
fn = router.subWrappers[i-1](fn)
|
||||
}
|
||||
|
||||
// create new rpc message
|
||||
rpcMsg := &rpcMessage{
|
||||
topic: msg.Topic(),
|
||||
contentType: msg.ContentType(),
|
||||
payload: req.Interface(),
|
||||
codec: msg.(*rpcMessage).codec,
|
||||
header: msg.Header(),
|
||||
body: msg.Body(),
|
||||
}
|
||||
|
||||
// execute the message handler
|
||||
if err = fn(ctx, rpcMsg); err != nil {
|
||||
errResults = append(errResults, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no errors just return
|
||||
if len(errResults) > 0 {
|
||||
err = merrors.InternalServerError("go.micro.server", "subscriber error: %v", strings.Join(errResults, "\n"))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -1,105 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
// Implements the Streamer interface
|
||||
type rpcStream struct {
|
||||
sync.RWMutex
|
||||
id string
|
||||
closed bool
|
||||
err error
|
||||
request server.Request
|
||||
codec codec.Codec
|
||||
context context.Context
|
||||
}
|
||||
|
||||
func (r *rpcStream) Context() context.Context {
|
||||
return r.context
|
||||
}
|
||||
|
||||
func (r *rpcStream) Request() server.Request {
|
||||
return r.request
|
||||
}
|
||||
|
||||
func (r *rpcStream) Send(msg interface{}) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
resp := codec.Message{
|
||||
Target: r.request.Service(),
|
||||
Method: r.request.Method(),
|
||||
Endpoint: r.request.Endpoint(),
|
||||
Id: r.id,
|
||||
Type: codec.Response,
|
||||
}
|
||||
|
||||
if err := r.codec.Write(&resp, msg); err != nil {
|
||||
r.err = err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *rpcStream) Recv(msg interface{}) error {
|
||||
req := new(codec.Message)
|
||||
req.Type = codec.Request
|
||||
|
||||
err := r.codec.ReadHeader(req, req.Type)
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
if err != nil {
|
||||
// discard body
|
||||
r.codec.ReadBody(nil)
|
||||
r.err = err
|
||||
return err
|
||||
}
|
||||
|
||||
// check the error
|
||||
if len(req.Error) > 0 {
|
||||
// Check the client closed the stream
|
||||
switch req.Error {
|
||||
case lastStreamResponseError.Error():
|
||||
// discard body
|
||||
r.Unlock()
|
||||
r.codec.ReadBody(nil)
|
||||
r.Lock()
|
||||
r.err = io.EOF
|
||||
return io.EOF
|
||||
default:
|
||||
return errors.New(req.Error)
|
||||
}
|
||||
}
|
||||
|
||||
// we need to stay up to date with sequence numbers
|
||||
r.id = req.Id
|
||||
r.Unlock()
|
||||
err = r.codec.ReadBody(msg)
|
||||
r.Lock()
|
||||
if err != nil {
|
||||
r.err = err
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *rpcStream) Error() error {
|
||||
r.RLock()
|
||||
defer r.RUnlock()
|
||||
return r.err
|
||||
}
|
||||
|
||||
func (r *rpcStream) Close() error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
r.closed = true
|
||||
return r.codec.Close()
|
||||
}
|
@@ -1,133 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/unistack-org/micro/v3/codec/json"
|
||||
protoCodec "github.com/unistack-org/micro/v3/codec/proto"
|
||||
)
|
||||
|
||||
// protoStruct implements proto.Message
|
||||
type protoStruct struct {
|
||||
Payload string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||
}
|
||||
|
||||
func (m *protoStruct) Reset() { *m = protoStruct{} }
|
||||
func (m *protoStruct) String() string { return proto.CompactTextString(m) }
|
||||
func (*protoStruct) ProtoMessage() {}
|
||||
|
||||
// safeBuffer throws away everything and wont Read data back
|
||||
type safeBuffer struct {
|
||||
sync.RWMutex
|
||||
buf []byte
|
||||
off int
|
||||
}
|
||||
|
||||
func (b *safeBuffer) Write(p []byte) (n int, err error) {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
// Cannot retain p, so we must copy it:
|
||||
p2 := make([]byte, len(p))
|
||||
copy(p2, p)
|
||||
b.Lock()
|
||||
b.buf = append(b.buf, p2...)
|
||||
b.Unlock()
|
||||
return len(p2), nil
|
||||
}
|
||||
|
||||
func (b *safeBuffer) Read(p []byte) (n int, err error) {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
b.RLock()
|
||||
n = copy(p, b.buf[b.off:])
|
||||
b.RUnlock()
|
||||
if n == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
b.off += n
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (b *safeBuffer) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestRPCStream_Sequence(t *testing.T) {
|
||||
buffer := new(bytes.Buffer)
|
||||
rwc := readWriteCloser{
|
||||
rbuf: buffer,
|
||||
wbuf: buffer,
|
||||
}
|
||||
codec := json.NewCodec(&rwc)
|
||||
streamServer := rpcStream{
|
||||
codec: codec,
|
||||
request: &rpcRequest{
|
||||
codec: codec,
|
||||
},
|
||||
}
|
||||
|
||||
// Check if sequence is correct
|
||||
for i := 0; i < 1000; i++ {
|
||||
if err := streamServer.Send(fmt.Sprintf(`{"test":"value %d"}`, i)); err != nil {
|
||||
t.Errorf("Unexpected Send error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
var msg string
|
||||
if err := streamServer.Recv(&msg); err != nil {
|
||||
t.Errorf("Unexpected Recv error: %s", err)
|
||||
}
|
||||
if msg != fmt.Sprintf(`{"test":"value %d"}`, i) {
|
||||
t.Errorf("Unexpected msg: %s", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRPCStream_Concurrency(t *testing.T) {
|
||||
buffer := new(safeBuffer)
|
||||
codec := protoCodec.NewCodec(buffer)
|
||||
streamServer := rpcStream{
|
||||
codec: codec,
|
||||
request: &rpcRequest{
|
||||
codec: codec,
|
||||
},
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
// Check if race conditions happen
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(2)
|
||||
|
||||
go func() {
|
||||
for i := 0; i < 50; i++ {
|
||||
msg := protoStruct{Payload: "test"}
|
||||
<-time.After(time.Duration(rand.Intn(50)) * time.Millisecond)
|
||||
if err := streamServer.Send(msg); err != nil {
|
||||
t.Errorf("Unexpected Send error: %s", err)
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for i := 0; i < 50; i++ {
|
||||
<-time.After(time.Duration(rand.Intn(50)) * time.Millisecond)
|
||||
if err := streamServer.Recv(&protoStruct{}); err != nil {
|
||||
t.Errorf("Unexpected Recv error: %s", err)
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// waitgroup for global management of connections
|
||||
type waitGroup struct {
|
||||
// local waitgroup
|
||||
lg sync.WaitGroup
|
||||
// global waitgroup
|
||||
gg *sync.WaitGroup
|
||||
}
|
||||
|
||||
func (w *waitGroup) Add(i int) {
|
||||
w.lg.Add(i)
|
||||
if w.gg != nil {
|
||||
w.gg.Add(i)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *waitGroup) Done() {
|
||||
w.lg.Done()
|
||||
if w.gg != nil {
|
||||
w.gg.Done()
|
||||
}
|
||||
}
|
||||
|
||||
func (w *waitGroup) Wait() {
|
||||
// only wait on local group
|
||||
w.lg.Wait()
|
||||
}
|
@@ -1,185 +0,0 @@
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/unistack-org/micro/v3/broker"
|
||||
"github.com/unistack-org/micro/v3/registry"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
"github.com/unistack-org/micro/v3/transport"
|
||||
)
|
||||
|
||||
const (
|
||||
subSig = "func(context.Context, interface{}) error"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
method reflect.Value
|
||||
reqType reflect.Type
|
||||
ctxType reflect.Type
|
||||
}
|
||||
|
||||
type subscriber struct {
|
||||
topic string
|
||||
rcvr reflect.Value
|
||||
typ reflect.Type
|
||||
subscriber interface{}
|
||||
handlers []*handler
|
||||
endpoints []*registry.Endpoint
|
||||
opts server.SubscriberOptions
|
||||
}
|
||||
|
||||
func newMessage(msg transport.Message) *broker.Message {
|
||||
return &broker.Message{
|
||||
Header: msg.Header,
|
||||
Body: msg.Body,
|
||||
}
|
||||
}
|
||||
|
||||
func newSubscriber(topic string, sub interface{}, opts ...server.SubscriberOption) server.Subscriber {
|
||||
options := server.SubscriberOptions{
|
||||
AutoAck: true,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
var endpoints []*registry.Endpoint
|
||||
var handlers []*handler
|
||||
|
||||
if typ := reflect.TypeOf(sub); typ.Kind() == reflect.Func {
|
||||
h := &handler{
|
||||
method: reflect.ValueOf(sub),
|
||||
}
|
||||
|
||||
switch typ.NumIn() {
|
||||
case 1:
|
||||
h.reqType = typ.In(0)
|
||||
case 2:
|
||||
h.ctxType = typ.In(0)
|
||||
h.reqType = typ.In(1)
|
||||
}
|
||||
|
||||
handlers = append(handlers, h)
|
||||
|
||||
endpoints = append(endpoints, ®istry.Endpoint{
|
||||
Name: "Func",
|
||||
Request: extractSubValue(typ),
|
||||
Metadata: map[string]string{
|
||||
"topic": topic,
|
||||
"subscriber": "true",
|
||||
},
|
||||
})
|
||||
} else {
|
||||
hdlr := reflect.ValueOf(sub)
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
method := typ.Method(m)
|
||||
h := &handler{
|
||||
method: method.Func,
|
||||
}
|
||||
|
||||
switch method.Type.NumIn() {
|
||||
case 2:
|
||||
h.reqType = method.Type.In(1)
|
||||
case 3:
|
||||
h.ctxType = method.Type.In(1)
|
||||
h.reqType = method.Type.In(2)
|
||||
}
|
||||
|
||||
handlers = append(handlers, h)
|
||||
|
||||
endpoints = append(endpoints, ®istry.Endpoint{
|
||||
Name: name + "." + method.Name,
|
||||
Request: extractSubValue(method.Type),
|
||||
Metadata: map[string]string{
|
||||
"topic": topic,
|
||||
"subscriber": "true",
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &subscriber{
|
||||
rcvr: reflect.ValueOf(sub),
|
||||
typ: reflect.TypeOf(sub),
|
||||
topic: topic,
|
||||
subscriber: sub,
|
||||
handlers: handlers,
|
||||
endpoints: endpoints,
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
func validateSubscriber(sub server.Subscriber) error {
|
||||
typ := reflect.TypeOf(sub.Subscriber())
|
||||
var argType reflect.Type
|
||||
|
||||
if typ.Kind() == reflect.Func {
|
||||
name := "Func"
|
||||
switch typ.NumIn() {
|
||||
case 2:
|
||||
argType = typ.In(1)
|
||||
default:
|
||||
return fmt.Errorf("subscriber %v takes wrong number of args: %v required signature %s", name, typ.NumIn(), subSig)
|
||||
}
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
return fmt.Errorf("subscriber %v argument type not exported: %v", name, argType)
|
||||
}
|
||||
if typ.NumOut() != 1 {
|
||||
return fmt.Errorf("subscriber %v has wrong number of outs: %v require signature %s",
|
||||
name, typ.NumOut(), subSig)
|
||||
}
|
||||
if returnType := typ.Out(0); returnType != typeOfError {
|
||||
return fmt.Errorf("subscriber %v returns %v not error", name, returnType.String())
|
||||
}
|
||||
} else {
|
||||
hdlr := reflect.ValueOf(sub.Subscriber())
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
method := typ.Method(m)
|
||||
|
||||
switch method.Type.NumIn() {
|
||||
case 3:
|
||||
argType = method.Type.In(2)
|
||||
default:
|
||||
return fmt.Errorf("subscriber %v.%v takes wrong number of args: %v required signature %s",
|
||||
name, method.Name, method.Type.NumIn(), subSig)
|
||||
}
|
||||
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
return fmt.Errorf("%v argument type not exported: %v", name, argType)
|
||||
}
|
||||
if method.Type.NumOut() != 1 {
|
||||
return fmt.Errorf(
|
||||
"subscriber %v.%v has wrong number of outs: %v require signature %s",
|
||||
name, method.Name, method.Type.NumOut(), subSig)
|
||||
}
|
||||
if returnType := method.Type.Out(0); returnType != typeOfError {
|
||||
return fmt.Errorf("subscriber %v.%v returns %v not error", name, method.Name, returnType.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *subscriber) Topic() string {
|
||||
return s.topic
|
||||
}
|
||||
|
||||
func (s *subscriber) Subscriber() interface{} {
|
||||
return s.subscriber
|
||||
}
|
||||
|
||||
func (s *subscriber) Endpoints() []*registry.Endpoint {
|
||||
return s.endpoints
|
||||
}
|
||||
|
||||
func (s *subscriber) Options() server.SubscriberOptions {
|
||||
return s.opts
|
||||
}
|
@@ -8,13 +8,10 @@ import (
|
||||
|
||||
"github.com/unistack-org/micro/v3/auth"
|
||||
"github.com/unistack-org/micro/v3/broker"
|
||||
"github.com/unistack-org/micro/v3/broker/http"
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
"github.com/unistack-org/micro/v3/debug/trace"
|
||||
"github.com/unistack-org/micro/v3/registry"
|
||||
"github.com/unistack-org/micro/v3/registry/mdns"
|
||||
"github.com/unistack-org/micro/v3/transport"
|
||||
thttp "github.com/unistack-org/micro/v3/transport/http"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
@@ -64,18 +61,6 @@ func newOptions(opt ...Option) Options {
|
||||
o(&opts)
|
||||
}
|
||||
|
||||
if opts.Broker == nil {
|
||||
opts.Broker = http.NewBroker()
|
||||
}
|
||||
|
||||
if opts.Registry == nil {
|
||||
opts.Registry = mdns.NewRegistry()
|
||||
}
|
||||
|
||||
if opts.Transport == nil {
|
||||
opts.Transport = thttp.NewTransport()
|
||||
}
|
||||
|
||||
if opts.RegisterCheck == nil {
|
||||
opts.RegisterCheck = DefaultRegisterCheck
|
||||
}
|
||||
@@ -228,9 +213,6 @@ func TLSConfig(t *tls.Config) Option {
|
||||
|
||||
// set the default transport if one is not
|
||||
// already set. Required for Init call below.
|
||||
if o.Transport == nil {
|
||||
o.Transport = thttp.NewTransport()
|
||||
}
|
||||
|
||||
// set the transport tls
|
||||
o.Transport.Init(
|
||||
|
@@ -1,349 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.6.1
|
||||
// source: server/proto/server.proto
|
||||
|
||||
package go_micro_server
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
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)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type HandleRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||
Endpoint string `protobuf:"bytes,2,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
|
||||
Protocol string `protobuf:"bytes,3,opt,name=protocol,proto3" json:"protocol,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HandleRequest) Reset() {
|
||||
*x = HandleRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_server_proto_server_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *HandleRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HandleRequest) ProtoMessage() {}
|
||||
|
||||
func (x *HandleRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_server_proto_server_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 HandleRequest.ProtoReflect.Descriptor instead.
|
||||
func (*HandleRequest) Descriptor() ([]byte, []int) {
|
||||
return file_server_proto_server_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *HandleRequest) GetService() string {
|
||||
if x != nil {
|
||||
return x.Service
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *HandleRequest) GetEndpoint() string {
|
||||
if x != nil {
|
||||
return x.Endpoint
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *HandleRequest) GetProtocol() string {
|
||||
if x != nil {
|
||||
return x.Protocol
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type HandleResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *HandleResponse) Reset() {
|
||||
*x = HandleResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_server_proto_server_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *HandleResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HandleResponse) ProtoMessage() {}
|
||||
|
||||
func (x *HandleResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_server_proto_server_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 HandleResponse.ProtoReflect.Descriptor instead.
|
||||
func (*HandleResponse) Descriptor() ([]byte, []int) {
|
||||
return file_server_proto_server_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
type SubscribeRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Topic string `protobuf:"bytes,1,opt,name=topic,proto3" json:"topic,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SubscribeRequest) Reset() {
|
||||
*x = SubscribeRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_server_proto_server_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SubscribeRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SubscribeRequest) ProtoMessage() {}
|
||||
|
||||
func (x *SubscribeRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_server_proto_server_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 SubscribeRequest.ProtoReflect.Descriptor instead.
|
||||
func (*SubscribeRequest) Descriptor() ([]byte, []int) {
|
||||
return file_server_proto_server_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *SubscribeRequest) GetTopic() string {
|
||||
if x != nil {
|
||||
return x.Topic
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SubscribeResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *SubscribeResponse) Reset() {
|
||||
*x = SubscribeResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_server_proto_server_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *SubscribeResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SubscribeResponse) ProtoMessage() {}
|
||||
|
||||
func (x *SubscribeResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_server_proto_server_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 SubscribeResponse.ProtoReflect.Descriptor instead.
|
||||
func (*SubscribeResponse) Descriptor() ([]byte, []int) {
|
||||
return file_server_proto_server_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
var File_server_proto_server_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_server_proto_server_proto_rawDesc = []byte{
|
||||
0x0a, 0x19, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x67, 0x6f, 0x2e,
|
||||
0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x61, 0x0a, 0x0d,
|
||||
0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a,
|
||||
0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22,
|
||||
0x10, 0x0a, 0x0e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x28, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x22, 0x13, 0x0a, 0x11, 0x53,
|
||||
0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x32, 0xab, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x4b, 0x0a, 0x06, 0x48,
|
||||
0x61, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73,
|
||||
0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62,
|
||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x6f, 0x2e, 0x6d, 0x69,
|
||||
0x63, 0x72, 0x6f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63,
|
||||
0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_server_proto_server_proto_rawDescOnce sync.Once
|
||||
file_server_proto_server_proto_rawDescData = file_server_proto_server_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_server_proto_server_proto_rawDescGZIP() []byte {
|
||||
file_server_proto_server_proto_rawDescOnce.Do(func() {
|
||||
file_server_proto_server_proto_rawDescData = protoimpl.X.CompressGZIP(file_server_proto_server_proto_rawDescData)
|
||||
})
|
||||
return file_server_proto_server_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_server_proto_server_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_server_proto_server_proto_goTypes = []interface{}{
|
||||
(*HandleRequest)(nil), // 0: go.micro.server.HandleRequest
|
||||
(*HandleResponse)(nil), // 1: go.micro.server.HandleResponse
|
||||
(*SubscribeRequest)(nil), // 2: go.micro.server.SubscribeRequest
|
||||
(*SubscribeResponse)(nil), // 3: go.micro.server.SubscribeResponse
|
||||
}
|
||||
var file_server_proto_server_proto_depIdxs = []int32{
|
||||
0, // 0: go.micro.server.Server.Handle:input_type -> go.micro.server.HandleRequest
|
||||
2, // 1: go.micro.server.Server.Subscribe:input_type -> go.micro.server.SubscribeRequest
|
||||
1, // 2: go.micro.server.Server.Handle:output_type -> go.micro.server.HandleResponse
|
||||
3, // 3: go.micro.server.Server.Subscribe:output_type -> go.micro.server.SubscribeResponse
|
||||
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_server_proto_server_proto_init() }
|
||||
func file_server_proto_server_proto_init() {
|
||||
if File_server_proto_server_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_server_proto_server_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HandleRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_server_proto_server_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HandleResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_server_proto_server_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SubscribeRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_server_proto_server_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SubscribeResponse); 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_server_proto_server_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 4,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_server_proto_server_proto_goTypes,
|
||||
DependencyIndexes: file_server_proto_server_proto_depIdxs,
|
||||
MessageInfos: file_server_proto_server_proto_msgTypes,
|
||||
}.Build()
|
||||
File_server_proto_server_proto = out.File
|
||||
file_server_proto_server_proto_rawDesc = nil
|
||||
file_server_proto_server_proto_goTypes = nil
|
||||
file_server_proto_server_proto_depIdxs = nil
|
||||
}
|
@@ -1,110 +0,0 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: server/proto/server.proto
|
||||
|
||||
package go_micro_server
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
math "math"
|
||||
)
|
||||
|
||||
import (
|
||||
context "context"
|
||||
api "github.com/unistack-org/micro/v3/api"
|
||||
client "github.com/unistack-org/micro/v3/client"
|
||||
server "github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
// 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.ProtoPackageIsVersion3 // 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 Server service
|
||||
|
||||
func NewServerEndpoints() []*api.Endpoint {
|
||||
return []*api.Endpoint{}
|
||||
}
|
||||
|
||||
// Client API for Server service
|
||||
|
||||
type ServerService interface {
|
||||
Handle(ctx context.Context, in *HandleRequest, opts ...client.CallOption) (*HandleResponse, error)
|
||||
Subscribe(ctx context.Context, in *SubscribeRequest, opts ...client.CallOption) (*SubscribeResponse, error)
|
||||
}
|
||||
|
||||
type serverService struct {
|
||||
c client.Client
|
||||
name string
|
||||
}
|
||||
|
||||
func NewServerService(name string, c client.Client) ServerService {
|
||||
return &serverService{
|
||||
c: c,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *serverService) Handle(ctx context.Context, in *HandleRequest, opts ...client.CallOption) (*HandleResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Server.Handle", in)
|
||||
out := new(HandleResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *serverService) Subscribe(ctx context.Context, in *SubscribeRequest, opts ...client.CallOption) (*SubscribeResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Server.Subscribe", in)
|
||||
out := new(SubscribeResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for Server service
|
||||
|
||||
type ServerHandler interface {
|
||||
Handle(context.Context, *HandleRequest, *HandleResponse) error
|
||||
Subscribe(context.Context, *SubscribeRequest, *SubscribeResponse) error
|
||||
}
|
||||
|
||||
func RegisterServerHandler(s server.Server, hdlr ServerHandler, opts ...server.HandlerOption) error {
|
||||
type server interface {
|
||||
Handle(ctx context.Context, in *HandleRequest, out *HandleResponse) error
|
||||
Subscribe(ctx context.Context, in *SubscribeRequest, out *SubscribeResponse) error
|
||||
}
|
||||
type Server struct {
|
||||
server
|
||||
}
|
||||
h := &serverHandler{hdlr}
|
||||
return s.Handle(s.NewHandler(&Server{h}, opts...))
|
||||
}
|
||||
|
||||
type serverHandler struct {
|
||||
ServerHandler
|
||||
}
|
||||
|
||||
func (h *serverHandler) Handle(ctx context.Context, in *HandleRequest, out *HandleResponse) error {
|
||||
return h.ServerHandler.Handle(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *serverHandler) Subscribe(ctx context.Context, in *SubscribeRequest, out *SubscribeResponse) error {
|
||||
return h.ServerHandler.Subscribe(ctx, in, out)
|
||||
}
|
@@ -1,22 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package go.micro.server;
|
||||
|
||||
service Server {
|
||||
rpc Handle(HandleRequest) returns (HandleResponse) {};
|
||||
rpc Subscribe(SubscribeRequest) returns (SubscribeResponse) {};
|
||||
}
|
||||
|
||||
message HandleRequest {
|
||||
string service = 1;
|
||||
string endpoint = 2;
|
||||
string protocol = 3;
|
||||
}
|
||||
|
||||
message HandleResponse {}
|
||||
|
||||
message SubscribeRequest {
|
||||
string topic = 1;
|
||||
}
|
||||
|
||||
message SubscribeResponse {}
|
@@ -1,126 +0,0 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
|
||||
package go_micro_server
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// 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.SupportPackageIsVersion6
|
||||
|
||||
// ServerClient is the client API for Server service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type ServerClient interface {
|
||||
Handle(ctx context.Context, in *HandleRequest, opts ...grpc.CallOption) (*HandleResponse, error)
|
||||
Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (*SubscribeResponse, error)
|
||||
}
|
||||
|
||||
type serverClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewServerClient(cc grpc.ClientConnInterface) ServerClient {
|
||||
return &serverClient{cc}
|
||||
}
|
||||
|
||||
func (c *serverClient) Handle(ctx context.Context, in *HandleRequest, opts ...grpc.CallOption) (*HandleResponse, error) {
|
||||
out := new(HandleResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.server.Server/Handle", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *serverClient) Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (*SubscribeResponse, error) {
|
||||
out := new(SubscribeResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.server.Server/Subscribe", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ServerServer is the server API for Server service.
|
||||
// All implementations must embed UnimplementedServerServer
|
||||
// for forward compatibility
|
||||
type ServerServer interface {
|
||||
Handle(context.Context, *HandleRequest) (*HandleResponse, error)
|
||||
Subscribe(context.Context, *SubscribeRequest) (*SubscribeResponse, error)
|
||||
mustEmbedUnimplementedServerServer()
|
||||
}
|
||||
|
||||
// UnimplementedServerServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedServerServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedServerServer) Handle(context.Context, *HandleRequest) (*HandleResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Handle not implemented")
|
||||
}
|
||||
func (*UnimplementedServerServer) Subscribe(context.Context, *SubscribeRequest) (*SubscribeResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Subscribe not implemented")
|
||||
}
|
||||
func (*UnimplementedServerServer) mustEmbedUnimplementedServerServer() {}
|
||||
|
||||
func RegisterServerServer(s *grpc.Server, srv ServerServer) {
|
||||
s.RegisterService(&_Server_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Server_Handle_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(HandleRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ServerServer).Handle(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.server.Server/Handle",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ServerServer).Handle(ctx, req.(*HandleRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Server_Subscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SubscribeRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ServerServer).Subscribe(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.server.Server/Subscribe",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ServerServer).Subscribe(ctx, req.(*SubscribeRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Server_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "go.micro.server.Server",
|
||||
HandlerType: (*ServerServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Handle",
|
||||
Handler: _Server_Handle_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Subscribe",
|
||||
Handler: _Server_Subscribe_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "server/proto/server.proto",
|
||||
}
|
Reference in New Issue
Block a user