2019-06-03 20:44:43 +03:00
|
|
|
// Package grpc provides a grpc server
|
2024-03-17 00:32:52 +03:00
|
|
|
package grpc
|
2019-06-03 20:44:43 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/tls"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"reflect"
|
2024-09-20 17:43:08 +03:00
|
|
|
"slices"
|
2019-06-03 20:44:43 +03:00
|
|
|
"sort"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
2024-12-02 15:55:55 +03:00
|
|
|
"sync/atomic"
|
2019-06-03 20:44:43 +03:00
|
|
|
"time"
|
|
|
|
|
2024-04-06 22:32:12 +03:00
|
|
|
greflection "google.golang.org/grpc/reflection"
|
|
|
|
reflectionv1pb "google.golang.org/grpc/reflection/grpc_reflection_v1"
|
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
// nolint: staticcheck
|
2021-10-27 01:00:27 +03:00
|
|
|
"go.unistack.org/micro/v3/broker"
|
|
|
|
"go.unistack.org/micro/v3/codec"
|
|
|
|
"go.unistack.org/micro/v3/errors"
|
|
|
|
"go.unistack.org/micro/v3/logger"
|
2024-02-27 17:08:08 +03:00
|
|
|
"go.unistack.org/micro/v3/metadata"
|
2024-04-06 22:32:12 +03:00
|
|
|
"go.unistack.org/micro/v3/meter"
|
2024-04-23 08:01:44 +03:00
|
|
|
"go.unistack.org/micro/v3/options"
|
2021-10-27 01:00:27 +03:00
|
|
|
"go.unistack.org/micro/v3/register"
|
2024-04-06 22:32:12 +03:00
|
|
|
"go.unistack.org/micro/v3/semconv"
|
2021-10-27 01:00:27 +03:00
|
|
|
"go.unistack.org/micro/v3/server"
|
2024-03-17 00:32:52 +03:00
|
|
|
msync "go.unistack.org/micro/v3/sync"
|
2024-04-23 08:01:44 +03:00
|
|
|
"go.unistack.org/micro/v3/tracer"
|
2020-02-24 16:48:56 +03:00
|
|
|
"golang.org/x/net/netutil"
|
2019-06-03 20:44:43 +03:00
|
|
|
"google.golang.org/grpc"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/encoding"
|
2021-02-12 20:36:25 +03:00
|
|
|
gmetadata "google.golang.org/grpc/metadata"
|
2019-06-27 16:53:01 +03:00
|
|
|
"google.golang.org/grpc/peer"
|
2019-06-03 20:44:43 +03:00
|
|
|
"google.golang.org/grpc/status"
|
2020-09-20 16:08:45 +03:00
|
|
|
"google.golang.org/protobuf/proto"
|
2024-12-02 15:55:55 +03:00
|
|
|
"google.golang.org/protobuf/protoadapt"
|
2019-06-03 20:44:43 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2023-01-07 23:27:53 +03:00
|
|
|
DefaultContentType = "application/grpc"
|
2019-06-03 20:44:43 +03:00
|
|
|
)
|
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
/*
|
2023-03-03 13:08:06 +03:00
|
|
|
type ServerReflection struct {
|
2020-09-20 16:08:45 +03:00
|
|
|
srv *grpc.Server
|
|
|
|
s *serverReflectionServer
|
|
|
|
}
|
2021-04-26 19:04:27 +03:00
|
|
|
*/
|
2020-09-20 16:08:45 +03:00
|
|
|
|
2024-05-06 00:28:56 +03:00
|
|
|
type streamWrapper struct {
|
|
|
|
ctx context.Context
|
|
|
|
grpc.ServerStream
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *streamWrapper) Context() context.Context {
|
|
|
|
if w.ctx != nil {
|
|
|
|
return w.ctx
|
|
|
|
}
|
|
|
|
return w.ServerStream.Context()
|
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
type Server struct {
|
2024-02-11 22:17:55 +03:00
|
|
|
handlers map[string]server.Handler
|
|
|
|
srv *grpc.Server
|
|
|
|
exit chan chan error
|
2024-03-17 00:32:52 +03:00
|
|
|
wg *msync.WaitGroup
|
2024-02-11 22:17:55 +03:00
|
|
|
rsvc *register.Service
|
|
|
|
subscribers map[*subscriber][]broker.Subscriber
|
|
|
|
rpc *rServer
|
|
|
|
opts server.Options
|
|
|
|
unknownHandler grpc.StreamHandler
|
2021-04-26 19:04:27 +03:00
|
|
|
sync.RWMutex
|
2024-12-02 15:55:55 +03:00
|
|
|
stateLive *atomic.Uint32
|
|
|
|
stateReady *atomic.Uint32
|
|
|
|
stateHealth *atomic.Uint32
|
|
|
|
started bool
|
|
|
|
registered bool
|
|
|
|
reflection bool
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func newServer(opts ...server.Option) *Server {
|
2019-06-03 20:44:43 +03:00
|
|
|
// create a grpc server
|
2023-03-03 13:08:06 +03:00
|
|
|
g := &Server{
|
2020-10-16 12:29:28 +03:00
|
|
|
opts: server.NewOptions(opts...),
|
2019-06-03 20:44:43 +03:00
|
|
|
rpc: &rServer{
|
|
|
|
serviceMap: make(map[string]*service),
|
|
|
|
},
|
|
|
|
handlers: make(map[string]server.Handler),
|
|
|
|
subscribers: make(map[*subscriber][]broker.Subscriber),
|
|
|
|
exit: make(chan chan error),
|
2024-12-02 15:55:55 +03:00
|
|
|
stateLive: &atomic.Uint32{},
|
|
|
|
stateReady: &atomic.Uint32{},
|
|
|
|
stateHealth: &atomic.Uint32{},
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2024-04-06 22:32:12 +03:00
|
|
|
g.opts.Meter = g.opts.Meter.Clone(meter.Labels("type", "grpc"))
|
|
|
|
|
2020-09-20 16:08:45 +03:00
|
|
|
return g
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2021-03-24 15:09:40 +03:00
|
|
|
/*
|
2019-06-08 21:40:44 +03:00
|
|
|
type grpcRouter struct {
|
2021-03-24 15:09:40 +03:00
|
|
|
h func(context.Context, server.Request, interface{}) error
|
|
|
|
m func(context.Context, server.Message) error
|
2019-11-25 19:31:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r grpcRouter) ProcessMessage(ctx context.Context, msg server.Message) error {
|
2021-03-24 15:09:40 +03:00
|
|
|
return r.m(ctx, msg)
|
2019-06-08 21:40:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r grpcRouter) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error {
|
2021-03-24 15:09:40 +03:00
|
|
|
return r.h(ctx, req, rsp)
|
2019-06-08 21:40:44 +03:00
|
|
|
}
|
|
|
|
|
2021-03-24 15:09:40 +03:00
|
|
|
*/
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) configure(opts ...server.Option) error {
|
2020-04-08 12:50:19 +03:00
|
|
|
g.Lock()
|
|
|
|
defer g.Unlock()
|
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
for _, o := range opts {
|
|
|
|
o(&g.opts)
|
|
|
|
}
|
|
|
|
|
2020-09-20 16:08:45 +03:00
|
|
|
if g.opts.Context != nil {
|
2020-11-26 01:17:21 +03:00
|
|
|
if codecs, ok := g.opts.Context.Value(codecsKey{}).(map[string]encoding.Codec); ok && codecs != nil {
|
|
|
|
for k, v := range codecs {
|
|
|
|
g.opts.Codecs[k] = &wrapGrpcCodec{v}
|
|
|
|
}
|
2020-09-20 16:08:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-04 16:25:50 +03:00
|
|
|
for _, k := range g.opts.Codecs {
|
|
|
|
encoding.RegisterCodec(&wrapMicroCodec{k})
|
|
|
|
}
|
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
maxMsgSize := g.getMaxMsgSize()
|
|
|
|
|
|
|
|
gopts := []grpc.ServerOption{
|
|
|
|
grpc.MaxRecvMsgSize(maxMsgSize),
|
|
|
|
grpc.MaxSendMsgSize(maxMsgSize),
|
|
|
|
grpc.UnknownServiceHandler(g.handler),
|
|
|
|
}
|
|
|
|
|
|
|
|
if opts := g.getGrpcOptions(); opts != nil {
|
2022-03-24 14:38:23 +03:00
|
|
|
gopts = append(opts, gopts...)
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2020-04-08 12:50:19 +03:00
|
|
|
g.rsvc = nil
|
2020-10-16 16:15:39 +03:00
|
|
|
restart := false
|
|
|
|
if g.started {
|
|
|
|
restart = true
|
|
|
|
if err := g.Stop(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
g.srv = grpc.NewServer(gopts...)
|
2020-09-20 16:08:45 +03:00
|
|
|
|
2024-04-06 22:32:12 +03:00
|
|
|
if v, ok := g.opts.Context.Value(reflectionKey{}).(Reflector); ok {
|
|
|
|
reflectionv1pb.RegisterServerReflectionServer(
|
|
|
|
g.srv,
|
|
|
|
greflection.NewServerV1(greflection.ServerOptions{
|
|
|
|
Services: v,
|
|
|
|
DescriptorResolver: v,
|
|
|
|
ExtensionResolver: v,
|
|
|
|
}),
|
|
|
|
)
|
2020-09-20 16:08:45 +03:00
|
|
|
}
|
|
|
|
|
2024-02-11 22:17:55 +03:00
|
|
|
if h, ok := g.opts.Context.Value(unknownServiceHandlerKey{}).(grpc.StreamHandler); ok {
|
|
|
|
g.unknownHandler = h
|
|
|
|
}
|
|
|
|
|
2020-10-16 16:15:39 +03:00
|
|
|
if restart {
|
|
|
|
return g.Start()
|
|
|
|
}
|
|
|
|
|
2020-09-20 16:08:45 +03:00
|
|
|
return nil
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) getMaxMsgSize() int {
|
2019-06-03 20:44:43 +03:00
|
|
|
s, ok := g.opts.Context.Value(maxMsgSizeKey{}).(int)
|
|
|
|
if !ok {
|
2024-09-17 12:52:41 +03:00
|
|
|
return 4 * 1024 * 1024
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) getGrpcOptions() []grpc.ServerOption {
|
2019-06-03 20:44:43 +03:00
|
|
|
if g.opts.Context == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-02-19 02:05:38 +03:00
|
|
|
opts, ok := g.opts.Context.Value(grpcOptions{}).([]grpc.ServerOption)
|
|
|
|
if !ok || opts == nil {
|
2019-06-03 20:44:43 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return opts
|
|
|
|
}
|
|
|
|
|
2024-04-06 22:32:12 +03:00
|
|
|
func (g *Server) handler(srv interface{}, stream grpc.ServerStream) error {
|
2024-04-06 22:48:21 +03:00
|
|
|
var err error
|
2024-04-23 08:01:44 +03:00
|
|
|
|
|
|
|
ctx := stream.Context()
|
|
|
|
|
2022-11-02 23:09:32 +03:00
|
|
|
fullMethod, ok := grpc.MethodFromServerStream(stream)
|
|
|
|
if !ok {
|
|
|
|
return status.Errorf(codes.Internal, "method does not exist in context")
|
|
|
|
}
|
|
|
|
|
2024-11-10 18:36:00 +03:00
|
|
|
// get grpc metadata
|
|
|
|
gmd, ok := gmetadata.FromIncomingContext(ctx)
|
|
|
|
if !ok {
|
|
|
|
gmd = gmetadata.MD{}
|
|
|
|
}
|
|
|
|
|
|
|
|
var serviceName, methodName string
|
|
|
|
serviceName, methodName, err = serviceMethod(fullMethod)
|
|
|
|
if err != nil {
|
|
|
|
err = status.New(codes.InvalidArgument, err.Error()).Err()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
endpointName := serviceName + "/" + methodName
|
|
|
|
|
2024-09-20 17:43:08 +03:00
|
|
|
ts := time.Now()
|
|
|
|
var sp tracer.Span
|
2024-11-10 18:36:00 +03:00
|
|
|
if !slices.Contains(tracer.DefaultSkipEndpoints, endpointName) {
|
|
|
|
ctx, sp = g.opts.Tracer.Start(ctx, "rpc-server",
|
2024-09-20 17:43:08 +03:00
|
|
|
tracer.WithSpanKind(tracer.SpanKindServer),
|
|
|
|
tracer.WithSpanLabels(
|
2024-11-10 18:36:00 +03:00
|
|
|
"endpoint", endpointName,
|
2024-11-10 20:16:08 +03:00
|
|
|
"server", "grpc",
|
2024-09-20 17:43:08 +03:00
|
|
|
),
|
|
|
|
)
|
|
|
|
defer func() {
|
|
|
|
st := status.Convert(err)
|
|
|
|
if st != nil || st.Code() != codes.OK {
|
|
|
|
sp.SetStatus(tracer.SpanStatusError, err.Error())
|
|
|
|
}
|
|
|
|
sp.Finish()
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2021-02-12 20:36:25 +03:00
|
|
|
md := metadata.New(len(gmd))
|
2019-06-03 20:44:43 +03:00
|
|
|
for k, v := range gmd {
|
2024-11-10 18:36:00 +03:00
|
|
|
md[k] = strings.Join(v, ", ")
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
2023-11-03 19:30:00 +03:00
|
|
|
md.Set("Path", fullMethod)
|
2023-11-04 00:05:33 +03:00
|
|
|
md.Set("Micro-Server", "grpc")
|
|
|
|
md.Set(metadata.HeaderEndpoint, methodName)
|
|
|
|
md.Set(metadata.HeaderService, serviceName)
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2022-03-21 13:03:48 +03:00
|
|
|
var td string
|
2019-06-03 20:44:43 +03:00
|
|
|
// timeout for server deadline
|
2022-03-21 13:03:48 +03:00
|
|
|
if v, ok := md.Get("timeout"); ok {
|
2021-04-16 17:04:40 +03:00
|
|
|
md.Del("timeout")
|
2022-03-21 13:03:48 +03:00
|
|
|
td = v
|
|
|
|
}
|
|
|
|
if v, ok := md.Get("Grpc-Timeout"); ok {
|
|
|
|
md.Del("Grpc-Timeout")
|
|
|
|
td = v[:len(v)-1]
|
2022-04-06 18:41:43 +03:00
|
|
|
switch v[len(v)-1:] {
|
2022-03-21 13:03:48 +03:00
|
|
|
case "S":
|
|
|
|
td += "s"
|
|
|
|
case "M":
|
|
|
|
td += "m"
|
|
|
|
case "H":
|
|
|
|
td += "h"
|
|
|
|
case "m":
|
|
|
|
td += "ms"
|
|
|
|
case "u":
|
|
|
|
td += "us"
|
|
|
|
case "n":
|
|
|
|
td += "ns"
|
|
|
|
}
|
2021-02-12 20:36:25 +03:00
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
|
|
|
|
// get content type
|
2022-03-21 13:03:48 +03:00
|
|
|
ct := DefaultContentType
|
2020-01-07 21:37:34 +03:00
|
|
|
|
2021-02-12 20:36:25 +03:00
|
|
|
if ctype, ok := md.Get("content-type"); ok {
|
2019-06-03 20:44:43 +03:00
|
|
|
ct = ctype
|
2021-02-12 20:36:25 +03:00
|
|
|
} else if ctype, ok := md.Get("x-content-type"); ok {
|
2020-01-07 21:37:34 +03:00
|
|
|
ct = ctype
|
2021-02-12 20:36:25 +03:00
|
|
|
md.Del("x-content-type")
|
2020-01-07 21:37:34 +03:00
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
|
|
|
|
// create new context
|
2024-04-23 08:01:44 +03:00
|
|
|
ctx = metadata.NewIncomingContext(ctx, md)
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2024-07-18 11:09:05 +03:00
|
|
|
stream = &streamWrapper{ctx, stream}
|
|
|
|
|
2024-11-10 18:36:00 +03:00
|
|
|
if !slices.Contains(meter.DefaultSkipEndpoints, endpointName) {
|
2024-11-10 20:16:08 +03:00
|
|
|
g.opts.Meter.Counter(semconv.ServerRequestInflight, "endpoint", endpointName, "server", "grpc").Inc()
|
2024-09-20 17:43:08 +03:00
|
|
|
defer func() {
|
|
|
|
te := time.Since(ts)
|
2024-11-10 20:16:08 +03:00
|
|
|
g.opts.Meter.Summary(semconv.ServerRequestLatencyMicroseconds, "endpoint", endpointName, "server", "grpc").Update(te.Seconds())
|
|
|
|
g.opts.Meter.Histogram(semconv.ServerRequestDurationSeconds, "endpoint", endpointName, "server", "grpc").Update(te.Seconds())
|
|
|
|
g.opts.Meter.Counter(semconv.ServerRequestInflight, "endpoint", endpointName, "server", "grpc").Dec()
|
2024-09-20 17:43:08 +03:00
|
|
|
|
|
|
|
st := status.Convert(err)
|
|
|
|
if st == nil || st.Code() == codes.OK {
|
2024-11-10 20:16:08 +03:00
|
|
|
g.opts.Meter.Counter(semconv.ServerRequestTotal, "endpoint", endpointName, "server", "grpc", "status", "success", "code", strconv.Itoa(int(codes.OK))).Inc()
|
2024-09-20 17:43:08 +03:00
|
|
|
} else {
|
2024-11-10 20:16:08 +03:00
|
|
|
g.opts.Meter.Counter(semconv.ServerRequestTotal, "endpoint", endpointName, "server", "grpc", "status", "failure", "code", strconv.Itoa(int(st.Code()))).Inc()
|
2024-09-20 17:43:08 +03:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
2024-07-18 11:09:05 +03:00
|
|
|
|
|
|
|
if g.opts.Wait != nil {
|
|
|
|
g.opts.Wait.Add(1)
|
|
|
|
defer g.opts.Wait.Done()
|
|
|
|
}
|
|
|
|
|
2019-06-27 16:53:01 +03:00
|
|
|
// get peer from context
|
2024-04-23 08:01:44 +03:00
|
|
|
if p, ok := peer.FromContext(ctx); ok {
|
2022-11-14 14:52:12 +03:00
|
|
|
md.Set("Remote", p.Addr.String())
|
2019-06-27 16:53:01 +03:00
|
|
|
ctx = peer.NewContext(ctx, p)
|
|
|
|
}
|
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
// set the timeout if we have it
|
2022-03-21 13:03:48 +03:00
|
|
|
if len(td) > 0 {
|
2024-04-06 22:32:12 +03:00
|
|
|
var n uint64
|
|
|
|
if n, err = strconv.ParseUint(td, 10, 64); err == nil {
|
2019-12-03 10:25:58 +03:00
|
|
|
var cancel context.CancelFunc
|
|
|
|
ctx, cancel = context.WithTimeout(ctx, time.Duration(n))
|
|
|
|
defer cancel()
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-20 16:08:45 +03:00
|
|
|
g.rpc.mu.RLock()
|
|
|
|
svc := g.rpc.serviceMap[serviceName]
|
|
|
|
g.rpc.mu.RUnlock()
|
|
|
|
|
|
|
|
if svc == nil {
|
2024-02-11 22:17:55 +03:00
|
|
|
if g.unknownHandler != nil {
|
2024-04-06 22:48:21 +03:00
|
|
|
err = g.unknownHandler(srv, stream)
|
|
|
|
return err
|
2022-03-24 14:38:23 +03:00
|
|
|
}
|
2024-04-06 22:48:21 +03:00
|
|
|
err = status.New(codes.Unimplemented, fmt.Sprintf("unknown service %s", serviceName)).Err()
|
|
|
|
return err
|
2019-06-08 21:40:44 +03:00
|
|
|
}
|
|
|
|
|
2020-09-20 16:08:45 +03:00
|
|
|
mtype := svc.method[methodName]
|
2019-06-08 21:40:44 +03:00
|
|
|
if mtype == nil {
|
2024-02-11 22:17:55 +03:00
|
|
|
if g.unknownHandler != nil {
|
2024-04-06 22:48:21 +03:00
|
|
|
err = g.unknownHandler(srv, stream)
|
|
|
|
return err
|
2022-03-24 14:38:23 +03:00
|
|
|
}
|
2024-04-06 22:48:21 +03:00
|
|
|
err = status.New(codes.Unimplemented, fmt.Sprintf("unknown service method %s.%s", serviceName, methodName)).Err()
|
|
|
|
return err
|
2019-06-08 21:40:44 +03:00
|
|
|
}
|
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
// process unary
|
|
|
|
if !mtype.stream {
|
2024-04-06 22:32:12 +03:00
|
|
|
err = g.processRequest(ctx, stream, svc, mtype, ct)
|
|
|
|
} else {
|
|
|
|
// process stream
|
|
|
|
err = g.processStream(ctx, stream, svc, mtype, ct)
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) processRequest(ctx context.Context, stream grpc.ServerStream, service *service, mtype *methodType, ct string) error {
|
2021-04-26 19:04:27 +03:00
|
|
|
// for {
|
2022-03-21 15:28:39 +03:00
|
|
|
var err error
|
2021-04-26 19:04:27 +03:00
|
|
|
var argv, replyv reflect.Value
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
// 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
|
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
// Unmarshal request
|
2022-04-06 18:38:38 +03:00
|
|
|
if err = stream.RecvMsg(argv.Interface()); err != nil {
|
2021-04-26 19:04:27 +03:00
|
|
|
return err
|
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
if argIsValue {
|
|
|
|
argv = argv.Elem()
|
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
// reply value
|
|
|
|
replyv = reflect.New(mtype.ReplyType.Elem())
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
function := mtype.method.Func
|
|
|
|
var returnValues []reflect.Value
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
// create a client.Request
|
|
|
|
r := &rpcRequest{
|
|
|
|
service: g.opts.Name,
|
|
|
|
contentType: ct,
|
|
|
|
method: fmt.Sprintf("%s.%s", service.name, mtype.method.Name),
|
2023-01-17 23:41:48 +03:00
|
|
|
endpoint: fmt.Sprintf("%s.%s", service.name, mtype.method.Name),
|
2021-04-26 19:04:27 +03:00
|
|
|
payload: argv.Interface(),
|
|
|
|
}
|
|
|
|
// define the handler func
|
|
|
|
fn := func(ctx context.Context, req server.Request, rsp interface{}) (err error) {
|
2022-11-14 14:52:12 +03:00
|
|
|
returnValues = function.Call([]reflect.Value{service.rcvr, mtype.prepareContext(ctx), argv, reflect.ValueOf(rsp)})
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
// The return value for the method is an error.
|
|
|
|
if rerr := returnValues[0].Interface(); rerr != nil {
|
|
|
|
err = rerr.(error)
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
return err
|
|
|
|
}
|
2020-08-09 17:43:41 +03:00
|
|
|
|
2024-04-23 08:01:44 +03:00
|
|
|
g.opts.Hooks.EachNext(func(hook options.Hook) {
|
|
|
|
if h, ok := hook.(server.HookHandler); ok {
|
|
|
|
fn = h(fn)
|
|
|
|
}
|
|
|
|
})
|
2020-03-17 14:27:20 +03:00
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
statusCode := codes.OK
|
|
|
|
statusDesc := ""
|
|
|
|
// execute the handler
|
2022-11-14 14:52:12 +03:00
|
|
|
appErr := fn(ctx, r, replyv.Interface())
|
|
|
|
if outmd, ok := metadata.FromOutgoingContext(ctx); ok {
|
|
|
|
if err = stream.SendHeader(gmetadata.New(outmd)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if appErr != nil {
|
2021-04-26 19:04:27 +03:00
|
|
|
var errStatus *status.Status
|
|
|
|
switch verr := appErr.(type) {
|
|
|
|
case *errors.Error:
|
|
|
|
statusCode = microError(verr)
|
|
|
|
statusDesc = verr.Error()
|
|
|
|
errStatus = status.New(statusCode, statusDesc)
|
|
|
|
case proto.Message:
|
|
|
|
// user defined error that proto based we can attach it to grpc status
|
|
|
|
statusCode = convertCode(appErr)
|
|
|
|
statusDesc = appErr.Error()
|
2024-12-02 15:55:55 +03:00
|
|
|
errStatus, err = status.New(statusCode, statusDesc).WithDetails(protoadapt.MessageV1Of(verr))
|
2021-04-26 19:04:27 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-04-06 18:37:00 +03:00
|
|
|
case (interface{ GRPCStatus() *status.Status }):
|
|
|
|
errStatus = verr.GRPCStatus()
|
2021-04-26 19:04:27 +03:00
|
|
|
default:
|
|
|
|
g.RLock()
|
|
|
|
config := g.opts
|
|
|
|
g.RUnlock()
|
|
|
|
if config.Logger.V(logger.ErrorLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Error(config.Context, "handler error will not be transferred properly, must return *errors.Error or proto.Message")
|
2021-04-26 19:04:27 +03:00
|
|
|
}
|
|
|
|
// default case user pass own error type that not proto based
|
|
|
|
statusCode = convertCode(verr)
|
|
|
|
statusDesc = verr.Error()
|
|
|
|
errStatus = status.New(statusCode, statusDesc)
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
2020-01-02 21:23:43 +03:00
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
return errStatus.Err()
|
|
|
|
}
|
2020-08-09 17:43:41 +03:00
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
if err := stream.SendMsg(replyv.Interface()); err != nil {
|
|
|
|
return err
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
2021-04-26 19:04:27 +03:00
|
|
|
|
|
|
|
return status.New(statusCode, statusDesc).Err()
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) processStream(ctx context.Context, stream grpc.ServerStream, service *service, mtype *methodType, ct string) error {
|
2019-06-03 20:44:43 +03:00
|
|
|
opts := g.opts
|
|
|
|
|
|
|
|
r := &rpcRequest{
|
|
|
|
service: opts.Name,
|
|
|
|
contentType: ct,
|
|
|
|
method: fmt.Sprintf("%s.%s", service.name, mtype.method.Name),
|
2023-01-17 23:41:48 +03:00
|
|
|
endpoint: fmt.Sprintf("%s.%s", service.name, mtype.method.Name),
|
2019-06-03 20:44:43 +03:00
|
|
|
stream: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
ss := &rpcStream{
|
2020-08-09 17:43:41 +03:00
|
|
|
ServerStream: stream,
|
|
|
|
request: r,
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function := mtype.method.Func
|
|
|
|
var returnValues []reflect.Value
|
|
|
|
|
|
|
|
// 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{service.rcvr, mtype.prepareContext(ctx), reflect.ValueOf(stream)})
|
|
|
|
if err := returnValues[0].Interface(); err != nil {
|
|
|
|
return err.(error)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-04-23 08:01:44 +03:00
|
|
|
opts.Hooks.EachNext(func(hook options.Hook) {
|
|
|
|
if h, ok := hook.(server.HookHandler); ok {
|
|
|
|
fn = h(fn)
|
|
|
|
}
|
|
|
|
})
|
2019-06-03 20:44:43 +03:00
|
|
|
|
|
|
|
statusCode := codes.OK
|
|
|
|
statusDesc := ""
|
|
|
|
|
2022-11-14 14:52:12 +03:00
|
|
|
appErr := fn(ctx, r, ss)
|
|
|
|
if outmd, ok := metadata.FromOutgoingContext(ctx); ok {
|
|
|
|
if err := stream.SendHeader(gmetadata.New(outmd)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if appErr != nil {
|
2020-02-06 13:18:33 +03:00
|
|
|
var err error
|
|
|
|
var errStatus *status.Status
|
|
|
|
switch verr := appErr.(type) {
|
2020-09-20 16:08:45 +03:00
|
|
|
case *errors.Error:
|
2020-02-06 13:18:33 +03:00
|
|
|
statusCode = microError(verr)
|
|
|
|
statusDesc = verr.Error()
|
2020-10-08 13:18:23 +03:00
|
|
|
errStatus = status.New(statusCode, statusDesc)
|
2020-09-20 16:08:45 +03:00
|
|
|
case proto.Message:
|
|
|
|
// user defined error that proto based we can attach it to grpc status
|
|
|
|
statusCode = convertCode(appErr)
|
|
|
|
statusDesc = appErr.Error()
|
2024-12-02 15:55:55 +03:00
|
|
|
errStatus, err = status.New(statusCode, statusDesc).WithDetails(protoadapt.MessageV1Of(verr))
|
2020-09-20 16:08:45 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-02-06 13:18:33 +03:00
|
|
|
default:
|
2021-01-16 22:20:07 +03:00
|
|
|
if g.opts.Logger.V(logger.ErrorLevel) {
|
|
|
|
g.opts.Logger.Error(g.opts.Context, "handler error will not be transferred properly, must return *errors.Error or proto.Message")
|
2020-10-08 13:42:27 +03:00
|
|
|
}
|
2020-02-06 13:18:33 +03:00
|
|
|
// default case user pass own error type that not proto based
|
|
|
|
statusCode = convertCode(verr)
|
|
|
|
statusDesc = verr.Error()
|
|
|
|
errStatus = status.New(statusCode, statusDesc)
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
2020-08-09 17:43:41 +03:00
|
|
|
|
2020-02-06 13:18:33 +03:00
|
|
|
return errStatus.Err()
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return status.New(statusCode, statusDesc).Err()
|
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) newCodec(ct string) (codec.Codec, error) {
|
2020-09-20 16:08:45 +03:00
|
|
|
g.RLock()
|
|
|
|
defer g.RUnlock()
|
|
|
|
|
2021-04-16 17:04:40 +03:00
|
|
|
if idx := strings.IndexRune(ct, ';'); idx >= 0 {
|
|
|
|
ct = ct[:idx]
|
|
|
|
}
|
|
|
|
|
2020-11-26 01:17:21 +03:00
|
|
|
if c, ok := g.opts.Codecs[ct]; ok {
|
2019-06-03 20:44:43 +03:00
|
|
|
return c, nil
|
|
|
|
}
|
2020-09-20 16:08:45 +03:00
|
|
|
|
2020-11-26 01:17:21 +03:00
|
|
|
return nil, codec.ErrUnknownContentType
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) Options() server.Options {
|
2019-08-23 17:00:29 +03:00
|
|
|
g.RLock()
|
2019-06-03 20:44:43 +03:00
|
|
|
opts := g.opts
|
2019-08-23 17:00:29 +03:00
|
|
|
g.RUnlock()
|
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
return opts
|
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) Init(opts ...server.Option) error {
|
2020-09-20 16:08:45 +03:00
|
|
|
return g.configure(opts...)
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) NewHandler(h interface{}, opts ...server.HandlerOption) server.Handler {
|
2021-04-26 19:04:27 +03:00
|
|
|
return newRPCHandler(h, opts...)
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) Handle(h server.Handler) error {
|
2019-06-03 20:44:43 +03:00
|
|
|
if err := g.rpc.register(h.Handler()); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
g.handlers[h.Name()] = h
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) NewSubscriber(topic string, sb interface{}, opts ...server.SubscriberOption) server.Subscriber {
|
2019-06-03 20:44:43 +03:00
|
|
|
return newSubscriber(topic, sb, opts...)
|
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) Subscribe(sb server.Subscriber) error {
|
2019-06-03 20:44:43 +03:00
|
|
|
sub, ok := sb.(*subscriber)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("invalid subscriber: expected *subscriber")
|
|
|
|
}
|
|
|
|
if len(sub.handlers) == 0 {
|
|
|
|
return fmt.Errorf("invalid subscriber: no handler functions")
|
|
|
|
}
|
|
|
|
|
2020-10-09 16:26:35 +03:00
|
|
|
if err := server.ValidateSubscriber(sb); err != nil {
|
2019-06-03 20:44:43 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
g.Lock()
|
2020-02-19 02:05:38 +03:00
|
|
|
if _, ok = g.subscribers[sub]; ok {
|
2020-02-26 21:34:40 +03:00
|
|
|
g.Unlock()
|
2019-06-03 20:44:43 +03:00
|
|
|
return fmt.Errorf("subscriber %v already exists", sub)
|
|
|
|
}
|
2020-02-19 02:05:38 +03:00
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
g.subscribers[sub] = nil
|
|
|
|
g.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) Register() error {
|
2020-04-08 12:50:19 +03:00
|
|
|
g.RLock()
|
|
|
|
rsvc := g.rsvc
|
2019-06-03 20:44:43 +03:00
|
|
|
config := g.opts
|
2020-04-08 12:50:19 +03:00
|
|
|
g.RUnlock()
|
|
|
|
|
|
|
|
// if service already filled, reuse it and return early
|
|
|
|
if rsvc != nil {
|
2020-11-05 01:23:36 +03:00
|
|
|
if err := server.DefaultRegisterFunc(rsvc, config); err != nil {
|
2020-04-08 12:50:19 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-01-29 15:13:56 +03:00
|
|
|
service, err := server.NewRegisterService(g)
|
2019-06-03 20:44:43 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
g.RLock()
|
|
|
|
// Maps are ordered randomly, sort the keys for consistency
|
2021-04-26 19:04:27 +03:00
|
|
|
handlerList := make([]string, 0, len(g.handlers))
|
|
|
|
for n := range g.handlers {
|
2019-06-03 20:44:43 +03:00
|
|
|
// Only advertise non internal handlers
|
2021-04-20 12:55:27 +03:00
|
|
|
handlerList = append(handlerList, n)
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
2020-09-20 16:08:45 +03:00
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
sort.Strings(handlerList)
|
|
|
|
|
2021-04-26 19:04:27 +03:00
|
|
|
subscriberList := make([]*subscriber, 0, len(g.subscribers))
|
2019-06-03 20:44:43 +03:00
|
|
|
for e := range g.subscribers {
|
|
|
|
// Only advertise non internal subscribers
|
2021-04-20 12:55:27 +03:00
|
|
|
subscriberList = append(subscriberList, e)
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
sort.Slice(subscriberList, func(i, j int) bool {
|
|
|
|
return subscriberList[i].topic > subscriberList[j].topic
|
|
|
|
})
|
|
|
|
|
2021-01-29 15:13:56 +03:00
|
|
|
endpoints := make([]*register.Endpoint, 0, len(handlerList)+len(subscriberList))
|
2019-06-03 20:44:43 +03:00
|
|
|
for _, n := range handlerList {
|
|
|
|
endpoints = append(endpoints, g.handlers[n].Endpoints()...)
|
|
|
|
}
|
|
|
|
for _, e := range subscriberList {
|
|
|
|
endpoints = append(endpoints, e.Endpoints()...)
|
|
|
|
}
|
|
|
|
g.RUnlock()
|
|
|
|
|
2020-10-29 21:11:24 +03:00
|
|
|
service.Nodes[0].Metadata["protocol"] = "grpc"
|
2021-04-26 19:04:27 +03:00
|
|
|
service.Nodes[0].Metadata["transport"] = service.Nodes[0].Metadata["protocol"]
|
2020-10-09 17:42:55 +03:00
|
|
|
service.Endpoints = endpoints
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2020-04-08 12:50:19 +03:00
|
|
|
g.RLock()
|
2019-06-03 20:44:43 +03:00
|
|
|
registered := g.registered
|
2020-04-08 12:50:19 +03:00
|
|
|
g.RUnlock()
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2020-03-13 12:30:44 +03:00
|
|
|
if !registered {
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.InfoLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Info(config.Context, fmt.Sprintf("Register [%s] Registering node: %s", config.Register.String(), service.Nodes[0].ID))
|
2020-03-13 12:30:44 +03:00
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2020-05-20 13:49:09 +03:00
|
|
|
// register the service
|
2020-11-05 01:23:36 +03:00
|
|
|
if err := server.DefaultRegisterFunc(service, config); err != nil {
|
2019-06-03 20:44:43 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-13 12:30:44 +03:00
|
|
|
// already registered? don't need to register subscribers
|
|
|
|
if registered {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
g.Lock()
|
|
|
|
defer g.Unlock()
|
|
|
|
|
2020-04-21 23:01:59 +03:00
|
|
|
g.registered = true
|
2020-11-05 01:43:34 +03:00
|
|
|
g.rsvc = service
|
2020-04-21 23:01:59 +03:00
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) Deregister() error {
|
2019-07-17 10:38:50 +03:00
|
|
|
var err error
|
|
|
|
|
2020-04-08 12:50:19 +03:00
|
|
|
g.RLock()
|
2019-06-03 20:44:43 +03:00
|
|
|
config := g.opts
|
2020-04-08 12:50:19 +03:00
|
|
|
g.RUnlock()
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2021-01-29 15:13:56 +03:00
|
|
|
service, err := server.NewRegisterService(g)
|
2019-06-03 20:44:43 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.InfoLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Info(config.Context, "Deregistering node: "+service.Nodes[0].ID)
|
2020-03-11 20:55:39 +03:00
|
|
|
}
|
2020-06-25 13:25:43 +03:00
|
|
|
|
2020-11-05 01:23:36 +03:00
|
|
|
if err := server.DefaultDeregisterFunc(service, config); err != nil {
|
2019-06-03 20:44:43 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
g.Lock()
|
2020-04-08 12:50:19 +03:00
|
|
|
g.rsvc = nil
|
2019-06-03 20:44:43 +03:00
|
|
|
|
|
|
|
if !g.registered {
|
|
|
|
g.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
g.registered = false
|
|
|
|
|
2020-04-30 12:42:13 +03:00
|
|
|
wg := sync.WaitGroup{}
|
2019-06-03 20:44:43 +03:00
|
|
|
for sb, subs := range g.subscribers {
|
|
|
|
for _, sub := range subs {
|
2020-04-30 12:42:13 +03:00
|
|
|
wg.Add(1)
|
|
|
|
go func(s broker.Subscriber) {
|
|
|
|
defer wg.Done()
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.InfoLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Info(config.Context, "Unsubscribing from topic: "+s.Topic())
|
2020-04-30 12:42:13 +03:00
|
|
|
}
|
2020-10-16 12:29:28 +03:00
|
|
|
if err := s.Unsubscribe(g.opts.Context); err != nil {
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.ErrorLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Error(config.Context, "Unsubscribing from topic: "+s.Topic(), err)
|
2020-09-20 16:08:45 +03:00
|
|
|
}
|
|
|
|
}
|
2020-04-30 12:42:13 +03:00
|
|
|
}(sub)
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
g.subscribers[sb] = nil
|
|
|
|
}
|
2020-04-30 12:42:13 +03:00
|
|
|
wg.Wait()
|
2019-06-03 20:44:43 +03:00
|
|
|
|
|
|
|
g.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) Start() error {
|
2019-08-23 17:00:29 +03:00
|
|
|
g.RLock()
|
|
|
|
if g.started {
|
|
|
|
g.RUnlock()
|
|
|
|
return nil
|
|
|
|
}
|
2020-03-13 01:04:11 +03:00
|
|
|
g.RUnlock()
|
|
|
|
|
2020-03-13 12:30:44 +03:00
|
|
|
config := g.Options()
|
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
// micro: config.Transport.Listen(config.Address)
|
2020-02-15 17:09:24 +03:00
|
|
|
var ts net.Listener
|
2021-06-17 14:12:26 +03:00
|
|
|
var err error
|
2020-02-15 17:09:24 +03:00
|
|
|
|
2020-12-15 11:56:11 +03:00
|
|
|
if l := config.Listener; l != nil {
|
2020-02-15 17:09:24 +03:00
|
|
|
ts = l
|
|
|
|
} else {
|
2020-02-15 18:10:26 +03:00
|
|
|
// check the tls config for secure connect
|
|
|
|
if tc := config.TLSConfig; tc != nil {
|
|
|
|
ts, err = tls.Listen("tcp", config.Address, tc)
|
|
|
|
// otherwise just plain tcp listener
|
|
|
|
} else {
|
|
|
|
ts, err = net.Listen("tcp", config.Address)
|
|
|
|
}
|
2020-02-15 17:09:24 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2020-12-15 11:56:11 +03:00
|
|
|
if config.MaxConn > 0 {
|
|
|
|
ts = netutil.LimitListener(ts, config.MaxConn)
|
2020-02-24 16:48:56 +03:00
|
|
|
}
|
|
|
|
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.InfoLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Info(config.Context, "Server [grpc] Listening on "+ts.Addr().String())
|
2020-03-11 20:55:39 +03:00
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
g.Lock()
|
|
|
|
g.opts.Address = ts.Addr().String()
|
2020-09-20 16:08:45 +03:00
|
|
|
if len(g.opts.Advertise) == 0 {
|
|
|
|
g.opts.Advertise = ts.Addr().String()
|
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
g.Unlock()
|
|
|
|
|
2020-01-19 16:45:28 +03:00
|
|
|
// only connect if we're subscribed
|
2020-03-13 12:30:44 +03:00
|
|
|
if len(g.subscribers) > 0 {
|
2020-01-19 16:45:28 +03:00
|
|
|
// connect to the broker
|
2021-06-17 14:12:26 +03:00
|
|
|
if err = config.Broker.Connect(config.Context); err != nil {
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.ErrorLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Error(config.Context, fmt.Sprintf("broker [%s] connect error", config.Broker.String()), err)
|
2020-04-08 12:50:19 +03:00
|
|
|
}
|
2020-01-19 16:45:28 +03:00
|
|
|
return err
|
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.InfoLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Info(config.Context, fmt.Sprintf("broker [%s] Connected to %s", config.Broker.String(), config.Broker.Address()))
|
2020-03-11 20:55:39 +03:00
|
|
|
}
|
2020-01-19 16:45:28 +03:00
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
|
2020-09-20 16:08:45 +03:00
|
|
|
// use RegisterCheck func before register
|
2021-04-26 19:04:27 +03:00
|
|
|
// nolint: nestif
|
2021-06-17 14:12:26 +03:00
|
|
|
if err = g.opts.RegisterCheck(config.Context); err != nil {
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.ErrorLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Error(config.Context, fmt.Sprintf("Server %s-%s register check error", config.Name, config.ID), err)
|
2020-09-20 16:08:45 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// announce self to the world
|
2021-06-17 14:12:26 +03:00
|
|
|
if err = g.Register(); err != nil {
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.ErrorLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Error(config.Context, "Server register error", err)
|
2020-09-20 16:08:45 +03:00
|
|
|
}
|
2020-03-11 20:55:39 +03:00
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2023-05-13 16:06:37 +03:00
|
|
|
if err = g.subscribe(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
// micro: go ts.Accept(s.accept)
|
|
|
|
go func() {
|
2021-06-17 14:12:26 +03:00
|
|
|
if err = g.srv.Serve(ts); err != nil {
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.ErrorLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Error(config.Context, "gRPC Server start error", err)
|
2020-03-11 20:55:39 +03:00
|
|
|
}
|
2021-06-17 14:12:26 +03:00
|
|
|
if err = g.Stop(); err != nil {
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.ErrorLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Error(config.Context, "gRPC Server stop error", err)
|
2020-09-20 16:08:45 +03:00
|
|
|
}
|
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
2024-12-02 15:55:55 +03:00
|
|
|
g.stateLive.Store(1)
|
|
|
|
g.stateReady.Store(1)
|
|
|
|
g.stateHealth.Store(1)
|
2019-06-03 20:44:43 +03:00
|
|
|
}()
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
t := new(time.Ticker)
|
|
|
|
|
|
|
|
// only process if it exists
|
|
|
|
if g.opts.RegisterInterval > time.Duration(0) {
|
|
|
|
// new ticker
|
|
|
|
t = time.NewTicker(g.opts.RegisterInterval)
|
|
|
|
}
|
|
|
|
|
|
|
|
// return error chan
|
|
|
|
var ch chan error
|
|
|
|
|
|
|
|
Loop:
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
// register self on interval
|
|
|
|
case <-t.C:
|
2020-09-20 16:08:45 +03:00
|
|
|
g.RLock()
|
|
|
|
registered := g.registered
|
|
|
|
g.RUnlock()
|
|
|
|
rerr := g.opts.RegisterCheck(g.opts.Context)
|
2021-04-26 19:04:27 +03:00
|
|
|
// nolint: nestif
|
2020-09-20 16:08:45 +03:00
|
|
|
if rerr != nil && registered {
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.ErrorLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Error(config.Context, fmt.Sprintf("Server %s-%s register check error, deregister it", config.Name, config.ID), rerr)
|
2020-09-20 16:08:45 +03:00
|
|
|
}
|
|
|
|
// deregister self in case of error
|
2021-06-17 14:12:26 +03:00
|
|
|
if err = g.Deregister(); err != nil {
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.ErrorLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Error(config.Context, fmt.Sprintf("Server %s-%s deregister error", config.Name, config.ID), err)
|
2020-09-20 16:08:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if rerr != nil && !registered {
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.ErrorLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Error(config.Context, fmt.Sprintf("Server %s-%s register check error", config.Name, config.ID), rerr)
|
2020-09-20 16:08:45 +03:00
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
2021-06-17 14:12:26 +03:00
|
|
|
if err = g.Register(); err != nil {
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.ErrorLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Error(config.Context, fmt.Sprintf("Server %s-%s register error", config.Name, config.ID), err)
|
2020-03-11 20:55:39 +03:00
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
// wait for exit
|
|
|
|
case ch = <-g.exit:
|
|
|
|
break Loop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// deregister self
|
2021-06-17 14:12:26 +03:00
|
|
|
if err = g.Deregister(); err != nil {
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.ErrorLevel) {
|
2024-10-12 13:18:36 +03:00
|
|
|
config.Logger.Error(config.Context, "Server deregister error", err)
|
2020-03-11 20:55:39 +03:00
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// wait for waitgroup
|
2024-03-17 00:32:52 +03:00
|
|
|
if g.opts.Wait != nil {
|
|
|
|
g.opts.Wait.Wait()
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// stop the grpc server
|
2020-01-18 13:18:23 +03:00
|
|
|
exit := make(chan bool)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
g.srv.GracefulStop()
|
|
|
|
close(exit)
|
2024-12-02 15:55:55 +03:00
|
|
|
g.stateLive.Store(0)
|
|
|
|
g.stateReady.Store(0)
|
|
|
|
g.stateHealth.Store(0)
|
2020-01-18 13:18:23 +03:00
|
|
|
}()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-exit:
|
2024-03-07 21:52:36 +03:00
|
|
|
case <-time.After(g.opts.GracefulTimeout):
|
2020-01-18 13:18:23 +03:00
|
|
|
g.srv.Stop()
|
2024-12-02 15:55:55 +03:00
|
|
|
g.stateLive.Store(0)
|
|
|
|
g.stateReady.Store(0)
|
|
|
|
g.stateHealth.Store(0)
|
2020-01-18 13:18:23 +03:00
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
|
|
|
|
// close transport
|
|
|
|
ch <- nil
|
|
|
|
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.InfoLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Info(config.Context, fmt.Sprintf("broker [%s] Disconnected from %s", config.Broker.String(), config.Broker.Address()))
|
2020-03-11 20:55:39 +03:00
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
// disconnect broker
|
2021-06-17 14:12:26 +03:00
|
|
|
if err = config.Broker.Disconnect(config.Context); err != nil {
|
2020-11-05 00:50:40 +03:00
|
|
|
if config.Logger.V(logger.ErrorLevel) {
|
2024-04-23 08:01:44 +03:00
|
|
|
config.Logger.Error(config.Context, fmt.Sprintf("broker [%s] disconnect error", config.Broker.String()), err)
|
2020-04-08 12:50:19 +03:00
|
|
|
}
|
|
|
|
}
|
2019-06-03 20:44:43 +03:00
|
|
|
}()
|
|
|
|
|
2019-08-23 17:00:29 +03:00
|
|
|
// mark the server as started
|
|
|
|
g.Lock()
|
|
|
|
g.started = true
|
|
|
|
g.Unlock()
|
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) Stop() error {
|
2019-08-23 17:00:29 +03:00
|
|
|
g.RLock()
|
|
|
|
if !g.started {
|
|
|
|
g.RUnlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
g.RUnlock()
|
|
|
|
|
2019-06-03 20:44:43 +03:00
|
|
|
ch := make(chan error)
|
|
|
|
g.exit <- ch
|
2019-08-23 17:00:29 +03:00
|
|
|
|
2020-09-20 16:08:45 +03:00
|
|
|
err := <-ch
|
|
|
|
g.Lock()
|
|
|
|
g.rsvc = nil
|
|
|
|
g.started = false
|
|
|
|
g.Unlock()
|
2019-08-23 17:00:29 +03:00
|
|
|
|
|
|
|
return err
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) String() string {
|
2019-06-03 20:44:43 +03:00
|
|
|
return "grpc"
|
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) Name() string {
|
2021-01-29 15:13:56 +03:00
|
|
|
return g.opts.Name
|
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func (g *Server) GRPCServer() *grpc.Server {
|
|
|
|
return g.srv
|
|
|
|
}
|
|
|
|
|
2024-12-02 15:55:55 +03:00
|
|
|
func (g *Server) Live() bool {
|
|
|
|
return g.stateLive.Load() == 1
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *Server) Ready() bool {
|
|
|
|
return g.stateReady.Load() == 1
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *Server) Health() bool {
|
|
|
|
return g.stateHealth.Load() == 1
|
|
|
|
}
|
|
|
|
|
2023-03-03 13:08:06 +03:00
|
|
|
func NewServer(opts ...server.Option) *Server {
|
|
|
|
return newServer(opts...)
|
2019-06-03 20:44:43 +03:00
|
|
|
}
|