go-micro.dev/v5@v5.12.0/server/rpc_events.go (about)

     1  package server
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"go-micro.dev/v5/broker"
     8  	raw "go-micro.dev/v5/codec/bytes"
     9  	log "go-micro.dev/v5/logger"
    10  	"go-micro.dev/v5/metadata"
    11  	"go-micro.dev/v5/transport/headers"
    12  )
    13  
    14  // HandleEvent handles inbound messages to the service directly.
    15  // These events are a result of registering to the topic with the service name.
    16  // TODO: handle requests from an event. We won't send a response.
    17  func (s *rpcServer) HandleEvent(subscriber string) func(e broker.Event) error {
    18  	return func(e broker.Event) error {
    19  		// formatting horrible cruft
    20  		msg := e.Message()
    21  
    22  		if msg.Header == nil {
    23  			msg.Header = make(map[string]string)
    24  		}
    25  
    26  		contentType, ok := msg.Header["Content-Type"]
    27  		if !ok || len(contentType) == 0 {
    28  			msg.Header["Content-Type"] = DefaultContentType
    29  			contentType = DefaultContentType
    30  		}
    31  
    32  		cf, err := s.newCodec(contentType)
    33  		if err != nil {
    34  			return err
    35  		}
    36  
    37  		header := make(map[string]string, len(msg.Header))
    38  		for k, v := range msg.Header {
    39  			header[k] = v
    40  		}
    41  
    42  		// create context
    43  		ctx := metadata.NewContext(context.Background(), header)
    44  
    45  		// TODO: inspect message header for Micro-Service & Micro-Topic
    46  		rpcMsg := &rpcMessage{
    47  			topic:       msg.Header[headers.Message],
    48  			contentType: contentType,
    49  			payload:     &raw.Frame{Data: msg.Body},
    50  			codec:       cf,
    51  			header:      msg.Header,
    52  			body:        msg.Body,
    53  		}
    54  
    55  		// if the router is present then execute it
    56  		r := Router(s.router)
    57  		if s.opts.Router != nil {
    58  			// create a wrapped function
    59  			// create a wrapped function
    60  			handler := func(ctx context.Context, msg Message) error {
    61  				return s.opts.Router.ProcessMessage(ctx, subscriber, msg)
    62  			}
    63  
    64  			// execute the wrapper for it
    65  			for i := len(s.opts.SubWrappers); i > 0; i-- {
    66  				handler = s.opts.SubWrappers[i-1](handler)
    67  			}
    68  
    69  			// set the router
    70  			r = rpcRouter{m: func(ctx context.Context, _ string, msg Message) error {
    71  				return handler(ctx, msg)
    72  			}}
    73  		}
    74  
    75  		return r.ProcessMessage(ctx, subscriber, rpcMsg)
    76  	}
    77  }
    78  
    79  func (s *rpcServer) NewSubscriber(topic string, sb interface{}, opts ...SubscriberOption) Subscriber {
    80  	return s.router.NewSubscriber(topic, sb, opts...)
    81  }
    82  
    83  func (s *rpcServer) Subscribe(sb Subscriber) error {
    84  	s.Lock()
    85  	defer s.Unlock()
    86  
    87  	sub, ok := sb.(*subscriber)
    88  	if !ok {
    89  		return fmt.Errorf("invalid subscriber: expected *subscriber")
    90  	}
    91  	if len(sub.handlers) == 0 {
    92  		return fmt.Errorf("invalid subscriber: no handler functions")
    93  	}
    94  
    95  	if err := validateSubscriber(sub); err != nil {
    96  		return err
    97  	}
    98  
    99  	// append to subscribers
   100  	// subs := s.subscribers[sub.Topic()]
   101  	// subs = append(subs, sub)
   102  	// router.subscribers[sub.Topic()] = subs
   103  
   104  	s.subscribers[sb] = nil
   105  
   106  	return nil
   107  }
   108  
   109  // subscribeServer will subscribe the server to the topic with its own name.
   110  func (s *rpcServer) subscribeServer(config Options) error {
   111  	if s.opts.Router != nil && s.subscriber == nil {
   112  		sub, err := s.opts.Broker.Subscribe(config.Name, s.HandleEvent(config.Name))
   113  		if err != nil {
   114  			return err
   115  		}
   116  
   117  		// Save the subscriber
   118  		s.subscriber = sub
   119  	}
   120  
   121  	return nil
   122  }
   123  
   124  // reSubscribe itterates over subscribers and re-subscribes then.
   125  func (s *rpcServer) reSubscribe(config Options) {
   126  	for sb := range s.subscribers {
   127  		if s.subscribers[sb] != nil {
   128  			continue
   129  		}
   130  		// If we've already created a broker subscription for this topic
   131  		// (from a different Subscriber entry) then don't create another
   132  		// broker.Subscribe. We still need to register the subscriber with
   133  		// the router so it receives dispatched messages.
   134  		var already bool
   135  		for other, subs := range s.subscribers {
   136  			if other.Topic() == sb.Topic() && subs != nil {
   137  				already = true
   138  				break
   139  			}
   140  		}
   141  		if already {
   142  			// register with router only
   143  			if err := s.router.Subscribe(sb); err != nil {
   144  				config.Logger.Logf(log.WarnLevel, "Unable to subscribing to topic: %s, error: %s", sb.Topic(), err)
   145  				continue
   146  			}
   147  			// mark this subscriber as having no broker subscription
   148  			s.subscribers[sb] = nil
   149  			continue
   150  		}
   151  		var opts []broker.SubscribeOption
   152  		if queue := sb.Options().Queue; len(queue) > 0 {
   153  			opts = append(opts, broker.Queue(queue))
   154  		}
   155  
   156  		if ctx := sb.Options().Context; ctx != nil {
   157  			opts = append(opts, broker.SubscribeContext(ctx))
   158  		}
   159  
   160  		if !sb.Options().AutoAck {
   161  			opts = append(opts, broker.DisableAutoAck())
   162  		}
   163  
   164  		config.Logger.Logf(log.InfoLevel, "Subscribing to topic: %s", sb.Topic())
   165  		sub, err := config.Broker.Subscribe(sb.Topic(), s.HandleEvent(sb.Topic()), opts...)
   166  		if err != nil {
   167  			config.Logger.Logf(log.WarnLevel, "Unable to subscribing to topic: %s, error: %s", sb.Topic(), err)
   168  			continue
   169  		}
   170  		err = s.router.Subscribe(sb)
   171  		if err != nil {
   172  			config.Logger.Logf(log.WarnLevel, "Unable to subscribing to topic: %s, error: %s", sb.Topic(), err)
   173  			sub.Unsubscribe()
   174  			continue
   175  		}
   176  		s.subscribers[sb] = []broker.Subscriber{sub}
   177  	}
   178  }