Compare commits
	
		
			20 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d463eb20cb | |||
| 8d5e25f8cf | |||
| 27e8043fed | |||
| 4e86df1721 | |||
| 03de1ec38f | |||
| 819ad1117a | |||
| a2a383606d | |||
| 55ce58617b | |||
| 0e587d923e | |||
| fa0248c80c | |||
| 054bd02b59 | |||
| 0cf246d2d6 | |||
| af278bd7d3 | |||
| 814b90efe5 | |||
| e403ae3d8e | |||
| c9816a3957 | |||
| 5691238a6a | |||
| 963a0fa7b7 | |||
| 485257035c | |||
| ebd8ddf05b | 
| @@ -1,4 +1,4 @@ | ||||
| # Micro [](https://opensource.org/licenses/Apache-2.0) [](https://pkg.go.dev/github.com/unistack-org/micro/v3?tab=overview) [](https://github.com/unistack-org/micro/actions?query=workflow%3Abuild+branch%3Amaster+event%3Apush) [](https://goreportcard.com/report/go.unistack.org/micro/v3) [](https://codecov.io/gh/unistack-org/micro) | ||||
| # Micro [](https://opensource.org/licenses/Apache-2.0) [](https://pkg.go.dev/go.unistack.org/micro/v4?tab=overview) [](https://github.com/unistack-org/micro/actions?query=workflow%3Abuild+branch%3Amaster+event%3Apush) [](https://goreportcard.com/report/go.unistack.org/micro/v4) [](https://codecov.io/gh/unistack-org/micro) | ||||
|  | ||||
| Micro is a standard library for microservices. | ||||
|  | ||||
|   | ||||
| @@ -1,22 +1,24 @@ | ||||
| // Package broker is an interface used for asynchronous messaging | ||||
| package broker // import "go.unistack.org/micro/v3/broker" | ||||
| package broker // import "go.unistack.org/micro/v4/broker" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| ) | ||||
|  | ||||
| // DefaultBroker default memory broker | ||||
| var DefaultBroker = NewBroker() | ||||
| var DefaultBroker Broker // =  NewBroker() | ||||
|  | ||||
| var ( | ||||
| 	// ErrNotConnected returns when broker used but not connected yet | ||||
| 	ErrNotConnected = errors.New("broker not connected") | ||||
| 	// ErrDisconnected returns when broker disconnected | ||||
| 	ErrDisconnected = errors.New("broker disconnected") | ||||
| 	// ErrInvalidMessage returns when message has nvalid format | ||||
| 	ErrInvalidMessage = errors.New("broker message has invalid format") | ||||
| ) | ||||
|  | ||||
| // Broker is an interface used for asynchronous messaging. | ||||
| @@ -33,61 +35,33 @@ type Broker interface { | ||||
| 	Connect(ctx context.Context) error | ||||
| 	// Disconnect disconnect from broker | ||||
| 	Disconnect(ctx context.Context) error | ||||
| 	// NewMessage creates new broker message | ||||
| 	NewMessage(endpoint string, req interface{}, opts ...MessageOption) Message | ||||
| 	// Publish message to broker topic | ||||
| 	Publish(ctx context.Context, topic string, msg *Message, opts ...PublishOption) error | ||||
| 	Publish(ctx context.Context, msg interface{}, opts ...PublishOption) error | ||||
| 	// Subscribe subscribes to topic message via handler | ||||
| 	Subscribe(ctx context.Context, topic string, h Handler, opts ...SubscribeOption) (Subscriber, error) | ||||
| 	// BatchPublish messages to broker with multiple topics | ||||
| 	BatchPublish(ctx context.Context, msgs []*Message, opts ...PublishOption) error | ||||
| 	// BatchSubscribe subscribes to topic messages via handler | ||||
| 	BatchSubscribe(ctx context.Context, topic string, h BatchHandler, opts ...SubscribeOption) (Subscriber, error) | ||||
| 	Subscribe(ctx context.Context, topic string, handler interface{}, opts ...SubscribeOption) (Subscriber, error) | ||||
| 	// String type of broker | ||||
| 	String() string | ||||
| } | ||||
|  | ||||
| // Handler is used to process messages via a subscription of a topic. | ||||
| type Handler func(Event) error | ||||
|  | ||||
| // Events contains multiple events | ||||
| type Events []Event | ||||
|  | ||||
| // Ack try to ack all events and return | ||||
| func (evs Events) Ack() error { | ||||
| 	var err error | ||||
| 	for _, ev := range evs { | ||||
| 		if err = ev.Ack(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // SetError sets error on event | ||||
| func (evs Events) SetError(err error) { | ||||
| 	for _, ev := range evs { | ||||
| 		ev.SetError(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // BatchHandler is used to process messages in batches via a subscription of a topic. | ||||
| type BatchHandler func(Events) error | ||||
|  | ||||
| // Event is given to a subscription handler for processing | ||||
| type Event interface { | ||||
| // Message is given to a subscription handler for processing | ||||
| type Message interface { | ||||
| 	// Context for the message | ||||
| 	Context() context.Context | ||||
| 	// Topic returns event topic | ||||
| 	Topic() string | ||||
| 	// Message returns broker message | ||||
| 	Message() *Message | ||||
| 	// Body returns broker message | ||||
| 	Body() interface{} | ||||
| 	// Ack acknowledge message | ||||
| 	Ack() error | ||||
| 	// Error returns message error (like decoding errors or some other) | ||||
| 	// In this case Body contains raw []byte from broker | ||||
| 	Error() error | ||||
| 	// SetError set event processing error | ||||
| 	SetError(err error) | ||||
| } | ||||
|  | ||||
| // Message is used to transfer data | ||||
| type Message struct { | ||||
| // RawMessage is used to transfer data | ||||
| type RawMessage struct { | ||||
| 	// Header contains message metadata | ||||
| 	Header metadata.Metadata | ||||
| 	// Body contains message body | ||||
| @@ -95,8 +69,8 @@ type Message struct { | ||||
| } | ||||
|  | ||||
| // NewMessage create broker message with topic filled | ||||
| func NewMessage(topic string) *Message { | ||||
| 	m := &Message{Header: metadata.New(2)} | ||||
| func NewRawMessage(topic string) *RawMessage { | ||||
| 	m := &RawMessage{Header: metadata.New(2)} | ||||
| 	m.Header.Set(metadata.HeaderTopic, topic) | ||||
| 	return m | ||||
| } | ||||
|   | ||||
							
								
								
									
										211
									
								
								broker/memory.go
									
									
									
									
									
								
							
							
						
						
									
										211
									
								
								broker/memory.go
									
									
									
									
									
								
							| @@ -1,15 +1,17 @@ | ||||
| //go:build ignore | ||||
|  | ||||
| package broker | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	maddr "go.unistack.org/micro/v3/util/addr" | ||||
| 	"go.unistack.org/micro/v3/util/id" | ||||
| 	mnet "go.unistack.org/micro/v3/util/net" | ||||
| 	"go.unistack.org/micro/v3/util/rand" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	maddr "go.unistack.org/micro/v4/util/addr" | ||||
| 	"go.unistack.org/micro/v4/util/id" | ||||
| 	mnet "go.unistack.org/micro/v4/util/net" | ||||
| 	"go.unistack.org/micro/v4/util/rand" | ||||
| ) | ||||
|  | ||||
| type memoryBroker struct { | ||||
| @@ -20,23 +22,6 @@ type memoryBroker struct { | ||||
| 	connected bool | ||||
| } | ||||
|  | ||||
| type memoryEvent struct { | ||||
| 	err     error | ||||
| 	message interface{} | ||||
| 	topic   string | ||||
| 	opts    Options | ||||
| } | ||||
|  | ||||
| type memorySubscriber struct { | ||||
| 	ctx          context.Context | ||||
| 	exit         chan bool | ||||
| 	handler      Handler | ||||
| 	batchhandler BatchHandler | ||||
| 	id           string | ||||
| 	topic        string | ||||
| 	opts         SubscribeOptions | ||||
| } | ||||
|  | ||||
| func (m *memoryBroker) Options() Options { | ||||
| 	return m.opts | ||||
| } | ||||
| @@ -88,16 +73,11 @@ func (m *memoryBroker) Init(opts ...Option) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *memoryBroker) Publish(ctx context.Context, topic string, msg *Message, opts ...PublishOption) error { | ||||
| 	msg.Header.Set(metadata.HeaderTopic, topic) | ||||
| 	return m.publish(ctx, []*Message{msg}, opts...) | ||||
| func (m *memoryBroker) NewMessage(endpoint string, req interface{}, opts ...MessageOption) Message { | ||||
| 	return &memoryMessage{} | ||||
| } | ||||
|  | ||||
| func (m *memoryBroker) BatchPublish(ctx context.Context, msgs []*Message, opts ...PublishOption) error { | ||||
| 	return m.publish(ctx, msgs, opts...) | ||||
| } | ||||
|  | ||||
| func (m *memoryBroker) publish(ctx context.Context, msgs []*Message, opts ...PublishOption) error { | ||||
| func (m *memoryBroker) Publish(ctx context.Context, message interface{}, opts ...PublishOption) error { | ||||
| 	m.RLock() | ||||
| 	if !m.connected { | ||||
| 		m.RUnlock() | ||||
| @@ -112,13 +92,20 @@ func (m *memoryBroker) publish(ctx context.Context, msgs []*Message, opts ...Pub | ||||
| 		return ctx.Err() | ||||
| 	default: | ||||
| 		options := NewPublishOptions(opts...) | ||||
|  | ||||
| 		msgTopicMap := make(map[string]Events) | ||||
| 		for _, v := range msgs { | ||||
| 			p := &memoryEvent{opts: m.opts} | ||||
|  | ||||
| 			if m.opts.Codec == nil || options.BodyOnly { | ||||
| 				p.topic, _ = v.Header.Get(metadata.HeaderTopic) | ||||
| 		var msgs []*memoryMessage | ||||
| 		switch v := message.(type) { | ||||
| 		case *memoryMessage: | ||||
| 			msgs = []*memoryMessage{v} | ||||
| 		case []*memoryMessage: | ||||
| 			msgs = v | ||||
| 		default: | ||||
| 			return ErrInvalidMessage | ||||
| 		} | ||||
| 		msgTopicMap := make(map[string][]*memoryMessage) | ||||
| 		for _, msg := range msgs { | ||||
| 			p := &memoryMessage{opts: options} | ||||
| 			/* | ||||
| 				if mb, ok := msg.Body().(*codec.Frame); ok { | ||||
| 					p.message = v.Body | ||||
| 				} else { | ||||
| 					p.topic, _ = v.Header.Get(metadata.HeaderTopic) | ||||
| @@ -127,113 +114,72 @@ func (m *memoryBroker) publish(ctx context.Context, msgs []*Message, opts ...Pub | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 			msgTopicMap[p.topic] = append(msgTopicMap[p.topic], p) | ||||
| 			*/ | ||||
| 			msgTopicMap[msg.Topic()] = append(msgTopicMap[p.topic], p) | ||||
| 		} | ||||
|  | ||||
| 		beh := m.opts.BatchErrorHandler | ||||
| 		eh := m.opts.ErrorHandler | ||||
|  | ||||
| 		for t, ms := range msgTopicMap { | ||||
| 			ts := time.Now() | ||||
|  | ||||
| 			m.opts.Meter.Counter(PublishMessageInflight, "endpoint", t).Add(len(ms)) | ||||
| 			m.opts.Meter.Counter(SubscribeMessageInflight, "endpoint", t).Add(len(ms)) | ||||
|  | ||||
| 			m.RLock() | ||||
| 			subs, ok := m.subscribers[t] | ||||
| 			m.RUnlock() | ||||
| 			if !ok { | ||||
| 				m.opts.Meter.Counter(PublishMessageTotal, "endpoint", t, "status", "failure").Add(len(ms)) | ||||
| 				m.opts.Meter.Counter(PublishMessageInflight, "endpoint", t).Add(-len(ms)) | ||||
| 				m.opts.Meter.Counter(SubscribeMessageInflight, "endpoint", t).Add(-len(ms)) | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			m.opts.Meter.Counter(PublishMessageTotal, "endpoint", t, "status", "success").Add(len(ms)) | ||||
| 			for _, sub := range subs { | ||||
| 				if sub.opts.BatchErrorHandler != nil { | ||||
| 					beh = sub.opts.BatchErrorHandler | ||||
| 				} | ||||
| 				if sub.opts.ErrorHandler != nil { | ||||
| 					eh = sub.opts.ErrorHandler | ||||
| 				} | ||||
|  | ||||
| 				switch { | ||||
| 				// batch processing | ||||
| 				case sub.batchhandler != nil: | ||||
| 					if err = sub.batchhandler(ms); err != nil { | ||||
| 						ms.SetError(err) | ||||
| 						if beh != nil { | ||||
| 							_ = beh(ms) | ||||
| 						} else if m.opts.Logger.V(logger.ErrorLevel) { | ||||
| 							m.opts.Logger.Error(m.opts.Context, err.Error()) | ||||
| 						} | ||||
| 					} else if sub.opts.AutoAck { | ||||
| 						if err = ms.Ack(); err != nil { | ||||
| 							m.opts.Logger.Errorf(m.opts.Context, "ack failed: %v", err) | ||||
| 						} | ||||
| 					} | ||||
| 					// single processing | ||||
| 				case sub.handler != nil: | ||||
| 				for _, p := range ms { | ||||
| 					if err = sub.handler(p); err != nil { | ||||
| 							p.SetError(err) | ||||
| 						m.opts.Meter.Counter(SubscribeMessageTotal, "endpoint", t, "status", "failure").Inc() | ||||
| 						if eh != nil { | ||||
| 							_ = eh(p) | ||||
| 						} else if m.opts.Logger.V(logger.ErrorLevel) { | ||||
| 							m.opts.Logger.Error(m.opts.Context, err.Error()) | ||||
| 						} | ||||
| 						} else if sub.opts.AutoAck { | ||||
| 					} else { | ||||
| 						if sub.opts.AutoAck { | ||||
| 							if err = p.Ack(); err != nil { | ||||
| 								m.opts.Logger.Errorf(m.opts.Context, "ack failed: %v", err) | ||||
| 								m.opts.Meter.Counter(SubscribeMessageTotal, "endpoint", t, "status", "failure").Inc() | ||||
| 							} else { | ||||
| 								m.opts.Meter.Counter(SubscribeMessageTotal, "endpoint", t, "status", "success").Inc() | ||||
| 							} | ||||
| 						} else { | ||||
| 							m.opts.Meter.Counter(SubscribeMessageTotal, "endpoint", t, "status", "success").Inc() | ||||
| 						} | ||||
| 					} | ||||
| 					m.opts.Meter.Counter(PublishMessageInflight, "endpoint", t).Add(-1) | ||||
| 					m.opts.Meter.Counter(SubscribeMessageInflight, "endpoint", t).Add(-1) | ||||
| 				} | ||||
|  | ||||
| 			} | ||||
| 			te := time.Since(ts) | ||||
| 			m.opts.Meter.Summary(PublishMessageLatencyMicroseconds, "endpoint", t).Update(te.Seconds()) | ||||
| 			m.opts.Meter.Histogram(PublishMessageDurationSeconds, "endpoint", t).Update(te.Seconds()) | ||||
| 			m.opts.Meter.Summary(SubscribeMessageLatencyMicroseconds, "endpoint", t).Update(te.Seconds()) | ||||
| 			m.opts.Meter.Histogram(SubscribeMessageDurationSeconds, "endpoint", t).Update(te.Seconds()) | ||||
| 		} | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *memoryBroker) BatchSubscribe(ctx context.Context, topic string, handler BatchHandler, opts ...SubscribeOption) (Subscriber, error) { | ||||
| 	m.RLock() | ||||
| 	if !m.connected { | ||||
| 		m.RUnlock() | ||||
| 		return nil, ErrNotConnected | ||||
| 	} | ||||
| 	m.RUnlock() | ||||
|  | ||||
| 	sid, err := id.New() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	options := NewSubscribeOptions(opts...) | ||||
|  | ||||
| 	sub := &memorySubscriber{ | ||||
| 		exit:         make(chan bool, 1), | ||||
| 		id:           sid, | ||||
| 		topic:        topic, | ||||
| 		batchhandler: handler, | ||||
| 		opts:         options, | ||||
| 		ctx:          ctx, | ||||
| 	} | ||||
|  | ||||
| 	m.Lock() | ||||
| 	m.subscribers[topic] = append(m.subscribers[topic], sub) | ||||
| 	m.Unlock() | ||||
|  | ||||
| 	go func() { | ||||
| 		<-sub.exit | ||||
| 		m.Lock() | ||||
| 		newSubscribers := make([]*memorySubscriber, 0, len(m.subscribers)-1) | ||||
| 		for _, sb := range m.subscribers[topic] { | ||||
| 			if sb.id == sub.id { | ||||
| 				continue | ||||
| 			} | ||||
| 			newSubscribers = append(newSubscribers, sb) | ||||
| 		} | ||||
| 		m.subscribers[topic] = newSubscribers | ||||
| 		m.Unlock() | ||||
| 	}() | ||||
|  | ||||
| 	return sub, nil | ||||
| } | ||||
|  | ||||
| func (m *memoryBroker) Subscribe(ctx context.Context, topic string, handler Handler, opts ...SubscribeOption) (Subscriber, error) { | ||||
| func (m *memoryBroker) Subscribe(ctx context.Context, topic string, handler interface{}, opts ...SubscribeOption) (Subscriber, error) { | ||||
| 	m.RLock() | ||||
| 	if !m.connected { | ||||
| 		m.RUnlock() | ||||
| @@ -286,38 +232,41 @@ func (m *memoryBroker) Name() string { | ||||
| 	return m.opts.Name | ||||
| } | ||||
|  | ||||
| func (m *memoryEvent) Topic() string { | ||||
| type memoryMessage struct { | ||||
| 	err   error | ||||
| 	body  interface{} | ||||
| 	topic string | ||||
| 	opts  PublishOptions | ||||
| 	ctx   context.Context | ||||
| } | ||||
|  | ||||
| func (m *memoryMessage) Topic() string { | ||||
| 	return m.topic | ||||
| } | ||||
|  | ||||
| func (m *memoryEvent) Message() *Message { | ||||
| 	switch v := m.message.(type) { | ||||
| 	case *Message: | ||||
| 		return v | ||||
| 	case []byte: | ||||
| 		msg := &Message{} | ||||
| 		if err := m.opts.Codec.Unmarshal(v, msg); err != nil { | ||||
| 			if m.opts.Logger.V(logger.ErrorLevel) { | ||||
| 				m.opts.Logger.Error(m.opts.Context, "[memory]: failed to unmarshal: %v", err) | ||||
| 			} | ||||
| 			return nil | ||||
| 		} | ||||
| 		return msg | ||||
| func (m *memoryMessage) Body() interface{} { | ||||
| 	return m.body | ||||
| } | ||||
|  | ||||
| func (m *memoryMessage) Ack() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *memoryEvent) Ack() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *memoryEvent) Error() error { | ||||
| func (m *memoryMessage) Error() error { | ||||
| 	return m.err | ||||
| } | ||||
|  | ||||
| func (m *memoryEvent) SetError(err error) { | ||||
| 	m.err = err | ||||
| func (m *memoryMessage) Context() context.Context { | ||||
| 	return m.ctx | ||||
| } | ||||
|  | ||||
| type memorySubscriber struct { | ||||
| 	ctx     context.Context | ||||
| 	exit    chan bool | ||||
| 	handler interface{} | ||||
| 	id      string | ||||
| 	topic   string | ||||
| 	opts    SubscribeOptions | ||||
| } | ||||
|  | ||||
| func (m *memorySubscriber) Options() SubscribeOptions { | ||||
| @@ -334,7 +283,7 @@ func (m *memorySubscriber) Unsubscribe(ctx context.Context) error { | ||||
| } | ||||
|  | ||||
| // NewBroker return new memory broker | ||||
| func NewBroker(opts ...Option) Broker { | ||||
| func NewBroker(opts ...Option) *memoryBroker { | ||||
| 	return &memoryBroker{ | ||||
| 		opts:        NewOptions(opts...), | ||||
| 		subscribers: make(map[string][]*memorySubscriber), | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"testing" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| ) | ||||
|  | ||||
| func TestMemoryBatchBroker(t *testing.T) { | ||||
|   | ||||
| @@ -5,11 +5,31 @@ import ( | ||||
| 	"crypto/tls" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/register" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// PublishMessageDurationSeconds specifies meter metric name | ||||
| 	PublishMessageDurationSeconds = "publish_message_duration_seconds" | ||||
| 	// PublishMessageLatencyMicroseconds specifies meter metric name | ||||
| 	PublishMessageLatencyMicroseconds = "publish_message_latency_microseconds" | ||||
| 	// PublishMessageTotal specifies meter metric name | ||||
| 	PublishMessageTotal = "publish_message_total" | ||||
| 	// PublishMessageInflight specifies meter metric name | ||||
| 	PublishMessageInflight = "publish_message_inflight" | ||||
| 	// SubscribeMessageDurationSeconds specifies meter metric name | ||||
| 	SubscribeMessageDurationSeconds = "subscribe_message_duration_seconds" | ||||
| 	// SubscribeMessageLatencyMicroseconds specifies meter metric name | ||||
| 	SubscribeMessageLatencyMicroseconds = "subscribe_message_latency_microseconds" | ||||
| 	// SubscribeMessageTotal specifies meter metric name | ||||
| 	SubscribeMessageTotal = "subscribe_message_total" | ||||
| 	// SubscribeMessageInflight specifies meter metric name | ||||
| 	SubscribeMessageInflight = "subscribe_message_inflight" | ||||
| ) | ||||
|  | ||||
| // Options struct | ||||
| @@ -18,8 +38,8 @@ type Options struct { | ||||
| 	Tracer tracer.Tracer | ||||
| 	// Register can be used for clustering | ||||
| 	Register register.Register | ||||
| 	// Codec holds the codec for marshal/unmarshal | ||||
| 	Codec codec.Codec | ||||
| 	// Codecs holds the codec for marshal/unmarshal | ||||
| 	Codecs map[string]codec.Codec | ||||
| 	// Logger used for logging | ||||
| 	Logger logger.Logger | ||||
| 	// Meter used for metrics | ||||
| @@ -29,15 +49,16 @@ type Options struct { | ||||
| 	// TLSConfig holds tls.TLSConfig options | ||||
| 	TLSConfig *tls.Config | ||||
| 	// ErrorHandler used when broker can't unmarshal incoming message | ||||
| 	ErrorHandler Handler | ||||
| 	// BatchErrorHandler used when broker can't unmashal incoming messages | ||||
| 	BatchErrorHandler BatchHandler | ||||
| 	ErrorHandler func(Message) | ||||
| 	// Name holds the broker name | ||||
| 	Name string | ||||
| 	// Addrs holds the broker address | ||||
| 	Addrs []string | ||||
| } | ||||
|  | ||||
| // Option func | ||||
| type Option func(*Options) | ||||
|  | ||||
| // NewOptions create new Options | ||||
| func NewOptions(opts ...Option) Options { | ||||
| 	options := Options{ | ||||
| @@ -45,7 +66,7 @@ func NewOptions(opts ...Option) Options { | ||||
| 		Logger:   logger.DefaultLogger, | ||||
| 		Context:  context.Background(), | ||||
| 		Meter:    meter.DefaultMeter, | ||||
| 		Codec:    codec.DefaultCodec, | ||||
| 		Codecs:   make(map[string]codec.Codec), | ||||
| 		Tracer:   tracer.DefaultTracer, | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
| @@ -61,6 +82,32 @@ func Context(ctx context.Context) Option { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // MessageOption func | ||||
| type MessageOption func(*MessageOptions) | ||||
|  | ||||
| // MessageOptions struct | ||||
| type MessageOptions struct { | ||||
| 	Metadata    metadata.Metadata | ||||
| 	ContentType string | ||||
| } | ||||
|  | ||||
| // MessageMetadata pass additional message metadata | ||||
| func MessageMetadata(md metadata.Metadata) MessageOption { | ||||
| 	return func(o *MessageOptions) { | ||||
| 		o.Metadata = md | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // MessageContentType pass ContentType for message data | ||||
| func MessageContentType(ct string) MessageOption { | ||||
| 	return func(o *MessageOptions) { | ||||
| 		o.ContentType = ct | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // PublishOption func | ||||
| type PublishOption func(*PublishOptions) | ||||
|  | ||||
| // PublishOptions struct | ||||
| type PublishOptions struct { | ||||
| 	// Context holds external options | ||||
| @@ -85,11 +132,9 @@ type SubscribeOptions struct { | ||||
| 	// Context holds external options | ||||
| 	Context context.Context | ||||
| 	// ErrorHandler used when broker can't unmarshal incoming message | ||||
| 	ErrorHandler Handler | ||||
| 	// BatchErrorHandler used when broker can't unmashal incoming messages | ||||
| 	BatchErrorHandler BatchHandler | ||||
| 	// Group holds consumer group | ||||
| 	Group string | ||||
| 	ErrorHandler func(Message) | ||||
| 	// QueueGroup holds consumer group | ||||
| 	QueueGroup string | ||||
| 	// AutoAck flag specifies auto ack of incoming message when no error happens | ||||
| 	AutoAck bool | ||||
| 	// BodyOnly flag specifies that message contains only body bytes without header | ||||
| @@ -100,12 +145,6 @@ type SubscribeOptions struct { | ||||
| 	BatchWait time.Duration | ||||
| } | ||||
|  | ||||
| // Option func | ||||
| type Option func(*Options) | ||||
|  | ||||
| // PublishOption func | ||||
| type PublishOption func(*PublishOptions) | ||||
|  | ||||
| // PublishBodyOnly publish only body of the message | ||||
| func PublishBodyOnly(b bool) PublishOption { | ||||
| 	return func(o *PublishOptions) { | ||||
| @@ -129,59 +168,29 @@ func Addrs(addrs ...string) Option { | ||||
|  | ||||
| // Codec sets the codec used for encoding/decoding used where | ||||
| // a broker does not support headers | ||||
| func Codec(c codec.Codec) Option { | ||||
| // Codec to be used to encode/decode requests for a given content type | ||||
| func Codec(contentType string, c codec.Codec) Option { | ||||
| 	return func(o *Options) { | ||||
| 		o.Codec = c | ||||
| 		o.Codecs[contentType] = c | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ErrorHandler will catch all broker errors that cant be handled | ||||
| // in normal way, for example Codec errors | ||||
| func ErrorHandler(h Handler) Option { | ||||
| func ErrorHandler(h func(Message)) Option { | ||||
| 	return func(o *Options) { | ||||
| 		o.ErrorHandler = h | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // BatchErrorHandler will catch all broker errors that cant be handled | ||||
| // in normal way, for example Codec errors | ||||
| func BatchErrorHandler(h BatchHandler) Option { | ||||
| 	return func(o *Options) { | ||||
| 		o.BatchErrorHandler = h | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscribeErrorHandler will catch all broker errors that cant be handled | ||||
| // in normal way, for example Codec errors | ||||
| func SubscribeErrorHandler(h Handler) SubscribeOption { | ||||
| func SubscribeErrorHandler(h func(Message)) SubscribeOption { | ||||
| 	return func(o *SubscribeOptions) { | ||||
| 		o.ErrorHandler = h | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscribeBatchErrorHandler will catch all broker errors that cant be handled | ||||
| // in normal way, for example Codec errors | ||||
| func SubscribeBatchErrorHandler(h BatchHandler) SubscribeOption { | ||||
| 	return func(o *SubscribeOptions) { | ||||
| 		o.BatchErrorHandler = h | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Queue sets the subscribers queue | ||||
| // Deprecated | ||||
| func Queue(name string) SubscribeOption { | ||||
| 	return func(o *SubscribeOptions) { | ||||
| 		o.Group = name | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscribeGroup sets the name of the queue to share messages on | ||||
| func SubscribeGroup(name string) SubscribeOption { | ||||
| 	return func(o *SubscribeOptions) { | ||||
| 		o.Group = name | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Register sets register option | ||||
| func Register(r register.Register) Option { | ||||
| 	return func(o *Options) { | ||||
| @@ -224,6 +233,21 @@ func Name(n string) Option { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscribeOption func signature | ||||
| type SubscribeOption func(*SubscribeOptions) | ||||
|  | ||||
| // NewSubscribeOptions creates new SubscribeOptions | ||||
| func NewSubscribeOptions(opts ...SubscribeOption) SubscribeOptions { | ||||
| 	options := SubscribeOptions{ | ||||
| 		AutoAck: true, | ||||
| 		Context: context.Background(), | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| 	} | ||||
| 	return options | ||||
| } | ||||
|  | ||||
| // SubscribeContext set context | ||||
| func SubscribeContext(ctx context.Context) SubscribeOption { | ||||
| 	return func(o *SubscribeOptions) { | ||||
| @@ -231,14 +255,6 @@ func SubscribeContext(ctx context.Context) SubscribeOption { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DisableAutoAck disables auto ack | ||||
| // Deprecated | ||||
| func DisableAutoAck() SubscribeOption { | ||||
| 	return func(o *SubscribeOptions) { | ||||
| 		o.AutoAck = false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscribeAutoAck contol auto acking of messages | ||||
| // after they have been handled. | ||||
| func SubscribeAutoAck(b bool) SubscribeOption { | ||||
| @@ -268,17 +284,16 @@ func SubscribeBatchWait(td time.Duration) SubscribeOption { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscribeOption func | ||||
| type SubscribeOption func(*SubscribeOptions) | ||||
| // SubscribeQueueGroup sets the shared queue name distributed messages across subscribers | ||||
| func SubscribeQueueGroup(n string) SubscribeOption { | ||||
| 	return func(o *SubscribeOptions) { | ||||
| 		o.QueueGroup = n | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // NewSubscribeOptions creates new SubscribeOptions | ||||
| func NewSubscribeOptions(opts ...SubscribeOption) SubscribeOptions { | ||||
| 	options := SubscribeOptions{ | ||||
| 		AutoAck: true, | ||||
| 		Context: context.Background(), | ||||
| // SubscribeAutoAck control auto ack processing for handler | ||||
| func SubscribeAuthAck(b bool) SubscribeOption { | ||||
| 	return func(o *SubscribeOptions) { | ||||
| 		o.AutoAck = b | ||||
| 	} | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| 	} | ||||
| 	return options | ||||
| } | ||||
|   | ||||
							
								
								
									
										98
									
								
								broker/subscriber.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								broker/subscriber.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| package broker | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	subSig      = "func(context.Context, interface{}) error" | ||||
| 	batchSubSig = "func([]context.Context, []interface{}) error" | ||||
| ) | ||||
|  | ||||
| // Precompute the reflect type for error. Can't use error directly | ||||
| // because Typeof takes an empty interface value. This is annoying. | ||||
| var typeOfError = reflect.TypeOf((*error)(nil)).Elem() | ||||
|  | ||||
| // 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() == "" | ||||
| } | ||||
|  | ||||
| // ValidateSubscriber func signature | ||||
| func ValidateSubscriber(sub interface{}) error { | ||||
| 	typ := reflect.TypeOf(sub) | ||||
| 	var argType reflect.Type | ||||
| 	switch typ.Kind() { | ||||
| 	case reflect.Func: | ||||
| 		name := "Func" | ||||
| 		switch typ.NumIn() { | ||||
| 		case 1: // func(Message) error | ||||
|  | ||||
| 		case 2: // func(context.Context, Message) error or func(context.Context, []Message) error | ||||
| 			argType = typ.In(2) | ||||
| 			// if sub.Options().Batch { | ||||
| 			if argType.Kind() != reflect.Slice { | ||||
| 				return fmt.Errorf("subscriber %v dont have required signature %s", name, batchSubSig) | ||||
| 			} | ||||
| 			if strings.Compare(fmt.Sprintf("%v", argType), "[]interface{}") == 0 { | ||||
| 				return fmt.Errorf("subscriber %v dont have required signaure %s", name, batchSubSig) | ||||
| 			} | ||||
| 		//	} | ||||
| 		default: | ||||
| 			return fmt.Errorf("subscriber %v takes wrong number of args: %v required signature %s or %s", name, typ.NumIn(), subSig, batchSubSig) | ||||
| 		} | ||||
| 		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 return values: %v require signature %s or %s", | ||||
| 				name, typ.NumOut(), subSig, batchSubSig) | ||||
| 		} | ||||
| 		if returnType := typ.Out(0); returnType != typeOfError { | ||||
| 			return fmt.Errorf("subscriber %v returns %v not error", name, returnType.String()) | ||||
| 		} | ||||
| 	default: | ||||
| 		hdlr := reflect.ValueOf(sub) | ||||
| 		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 or %s", | ||||
| 					name, method.Name, method.Type.NumIn(), subSig, batchSubSig) | ||||
| 			} | ||||
|  | ||||
| 			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 return values: %v require signature %s or %s", | ||||
| 					name, method.Name, method.Type.NumOut(), subSig, batchSubSig) | ||||
| 			} | ||||
| 			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 | ||||
| } | ||||
| @@ -5,7 +5,7 @@ import ( | ||||
| 	"math" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/util/backoff" | ||||
| 	"go.unistack.org/micro/v4/util/backoff" | ||||
| ) | ||||
|  | ||||
| // BackoffFunc is the backoff call func | ||||
|   | ||||
| @@ -1,12 +1,11 @@ | ||||
| // Package client is an interface for an RPC client | ||||
| package client // import "go.unistack.org/micro/v3/client" | ||||
| package client // import "go.unistack.org/micro/v4/client" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| @@ -35,23 +34,12 @@ type Client interface { | ||||
| 	Name() string | ||||
| 	Init(opts ...Option) error | ||||
| 	Options() Options | ||||
| 	NewMessage(topic string, msg interface{}, opts ...MessageOption) Message | ||||
| 	NewRequest(service string, endpoint string, req interface{}, opts ...RequestOption) Request | ||||
| 	Call(ctx context.Context, req Request, rsp interface{}, opts ...CallOption) error | ||||
| 	Stream(ctx context.Context, req Request, opts ...CallOption) (Stream, error) | ||||
| 	Publish(ctx context.Context, msg Message, opts ...PublishOption) error | ||||
| 	BatchPublish(ctx context.Context, msg []Message, opts ...PublishOption) error | ||||
| 	String() string | ||||
| } | ||||
|  | ||||
| // Message is the interface for publishing asynchronously | ||||
| type Message interface { | ||||
| 	Topic() string | ||||
| 	Payload() interface{} | ||||
| 	ContentType() string | ||||
| 	Metadata() metadata.Metadata | ||||
| } | ||||
|  | ||||
| // Request is the interface for a synchronous request used by Call or Stream | ||||
| type Request interface { | ||||
| 	// The service to call | ||||
| @@ -68,16 +56,22 @@ type Request interface { | ||||
| 	Codec() codec.Codec | ||||
| 	// indicates whether the request will be a streaming one rather than unary | ||||
| 	Stream() bool | ||||
| 	// Header data | ||||
| 	// Header() metadata.Metadata | ||||
| } | ||||
|  | ||||
| // Response is the response received from a service | ||||
| type Response interface { | ||||
| 	// Read the response | ||||
| 	Codec() codec.Codec | ||||
| 	// The content type | ||||
| 	// ContentType() string | ||||
| 	// Header data | ||||
| 	Header() metadata.Metadata | ||||
| 	// Header() metadata.Metadata | ||||
| 	// Read the undecoded response | ||||
| 	Read() ([]byte, error) | ||||
| 	// The unencoded request body | ||||
| 	// Body() interface{} | ||||
| } | ||||
|  | ||||
| // Stream is the interface for a bidirectional synchronous stream | ||||
|   | ||||
| @@ -4,8 +4,8 @@ import ( | ||||
| 	"context" | ||||
| 	"sort" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/errors" | ||||
| 	"go.unistack.org/micro/v3/router" | ||||
| 	"go.unistack.org/micro/v4/errors" | ||||
| 	"go.unistack.org/micro/v4/router" | ||||
| ) | ||||
|  | ||||
| // LookupFunc is used to lookup routes for a service | ||||
|   | ||||
| @@ -5,11 +5,10 @@ import ( | ||||
| 	"fmt" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/broker" | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/errors" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/selector" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| 	"go.unistack.org/micro/v4/errors" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| 	"go.unistack.org/micro/v4/selector" | ||||
| ) | ||||
|  | ||||
| // DefaultCodecs will be used to encode/decode data | ||||
| @@ -285,6 +284,9 @@ func (n *noopClient) Call(ctx context.Context, req Request, rsp interface{}, opt | ||||
| 	ch := make(chan error, callOpts.Retries) | ||||
| 	var gerr error | ||||
|  | ||||
| 	ts := time.Now() | ||||
| 	endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()) | ||||
| 	n.opts.Meter.Counter(ClientRequestInflight, "endpoint", endpoint).Inc() | ||||
| 	for i := 0; i <= callOpts.Retries; i++ { | ||||
| 		go func() { | ||||
| 			ch <- call(i) | ||||
| @@ -312,6 +314,16 @@ func (n *noopClient) Call(ctx context.Context, req Request, rsp interface{}, opt | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if gerr != nil { | ||||
| 		n.opts.Meter.Counter(ClientRequestTotal, "endpoint", endpoint, "status", "failure").Inc() | ||||
| 	} else { | ||||
| 		n.opts.Meter.Counter(ClientRequestTotal, "endpoint", endpoint, "status", "success").Inc() | ||||
| 	} | ||||
| 	n.opts.Meter.Counter(ClientRequestInflight, "endpoint", endpoint).Dec() | ||||
| 	te := time.Since(ts) | ||||
| 	n.opts.Meter.Summary(ClientRequestLatencyMicroseconds, "endpoint", endpoint).Update(te.Seconds()) | ||||
| 	n.opts.Meter.Histogram(ClientRequestDurationSeconds, "endpoint", endpoint).Update(te.Seconds()) | ||||
|  | ||||
| 	return gerr | ||||
| } | ||||
|  | ||||
| @@ -323,11 +335,6 @@ func (n *noopClient) NewRequest(service, endpoint string, req interface{}, opts | ||||
| 	return &noopRequest{service: service, endpoint: endpoint} | ||||
| } | ||||
|  | ||||
| func (n *noopClient) NewMessage(topic string, msg interface{}, opts ...MessageOption) Message { | ||||
| 	options := NewMessageOptions(append([]MessageOption{MessageContentType(n.opts.ContentType)}, opts...)...) | ||||
| 	return &noopMessage{topic: topic, payload: msg, opts: options} | ||||
| } | ||||
|  | ||||
| func (n *noopClient) Stream(ctx context.Context, req Request, opts ...CallOption) (Stream, error) { | ||||
| 	var err error | ||||
|  | ||||
| @@ -414,7 +421,15 @@ func (n *noopClient) Stream(ctx context.Context, req Request, opts ...CallOption | ||||
|  | ||||
| 		node := next() | ||||
|  | ||||
| 		// ts := time.Now() | ||||
| 		endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint()) | ||||
| 		n.opts.Meter.Counter(ClientRequestInflight, "endpoint", endpoint).Inc() | ||||
| 		stream, cerr := n.stream(ctx, node, req, callOpts) | ||||
| 		if cerr != nil { | ||||
| 			n.opts.Meter.Counter(ClientRequestTotal, "endpoint", endpoint, "status", "failure").Inc() | ||||
| 		} else { | ||||
| 			n.opts.Meter.Counter(ClientRequestTotal, "endpoint", endpoint, "status", "success").Inc() | ||||
| 		} | ||||
|  | ||||
| 		// record the result of the call to inform future routing decisions | ||||
| 		if verr := n.opts.Selector.Record(node, cerr); verr != nil { | ||||
| @@ -468,64 +483,6 @@ func (n *noopClient) Stream(ctx context.Context, req Request, opts ...CallOption | ||||
| 	return nil, grr | ||||
| } | ||||
|  | ||||
| func (n *noopClient) stream(ctx context.Context, addr string, req Request, opts CallOptions) (Stream, error) { | ||||
| func (n *noopClient) stream(ctx context.Context, addr string, req Request, opts CallOptions) (*noopStream, error) { | ||||
| 	return &noopStream{}, nil | ||||
| } | ||||
|  | ||||
| func (n *noopClient) BatchPublish(ctx context.Context, ps []Message, opts ...PublishOption) error { | ||||
| 	return n.publish(ctx, ps, opts...) | ||||
| } | ||||
|  | ||||
| func (n *noopClient) Publish(ctx context.Context, p Message, opts ...PublishOption) error { | ||||
| 	return n.publish(ctx, []Message{p}, opts...) | ||||
| } | ||||
|  | ||||
| func (n *noopClient) publish(ctx context.Context, ps []Message, opts ...PublishOption) error { | ||||
| 	options := NewPublishOptions(opts...) | ||||
|  | ||||
| 	msgs := make([]*broker.Message, 0, len(ps)) | ||||
|  | ||||
| 	for _, p := range ps { | ||||
| 		md, ok := metadata.FromOutgoingContext(ctx) | ||||
| 		if !ok { | ||||
| 			md = metadata.New(0) | ||||
| 		} | ||||
| 		md[metadata.HeaderContentType] = p.ContentType() | ||||
|  | ||||
| 		topic := p.Topic() | ||||
|  | ||||
| 		// get the exchange | ||||
| 		if len(options.Exchange) > 0 { | ||||
| 			topic = options.Exchange | ||||
| 		} | ||||
|  | ||||
| 		md[metadata.HeaderTopic] = topic | ||||
|  | ||||
| 		var body []byte | ||||
|  | ||||
| 		// passed in raw data | ||||
| 		if d, ok := p.Payload().(*codec.Frame); ok { | ||||
| 			body = d.Data | ||||
| 		} else { | ||||
| 			// use codec for payload | ||||
| 			cf, err := n.newCodec(p.ContentType()) | ||||
| 			if err != nil { | ||||
| 				return errors.InternalServerError("go.micro.client", err.Error()) | ||||
| 			} | ||||
|  | ||||
| 			// set the body | ||||
| 			b, err := cf.Marshal(p.Payload()) | ||||
| 			if err != nil { | ||||
| 				return errors.InternalServerError("go.micro.client", err.Error()) | ||||
| 			} | ||||
| 			body = b | ||||
| 		} | ||||
|  | ||||
| 		msgs = append(msgs, &broker.Message{Header: md, Body: body}) | ||||
| 	} | ||||
|  | ||||
| 	return n.opts.Broker.BatchPublish(ctx, msgs, | ||||
| 		broker.PublishContext(options.Context), | ||||
| 		broker.PublishBodyOnly(options.BodyOnly), | ||||
| 	) | ||||
| } | ||||
|   | ||||
| @@ -6,17 +6,27 @@ import ( | ||||
| 	"net" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/broker" | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/network/transport" | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| 	"go.unistack.org/micro/v3/router" | ||||
| 	"go.unistack.org/micro/v3/selector" | ||||
| 	"go.unistack.org/micro/v3/selector/random" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/network/transport" | ||||
| 	"go.unistack.org/micro/v4/register" | ||||
| 	"go.unistack.org/micro/v4/router" | ||||
| 	"go.unistack.org/micro/v4/selector" | ||||
| 	"go.unistack.org/micro/v4/selector/random" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// ClientRequestDurationSeconds specifies meter metric name | ||||
| 	ClientRequestDurationSeconds = "client_request_duration_seconds" | ||||
| 	// ClientRequestLatencyMicroseconds specifies meter metric name | ||||
| 	ClientRequestLatencyMicroseconds = "client_request_latency_microseconds" | ||||
| 	// ClientRequestTotal specifies meter metric name | ||||
| 	ClientRequestTotal = "client_request_total" | ||||
| 	// ClientRequestInflight specifies meter metric name | ||||
| 	ClientRequestInflight = "client_request_inflight" | ||||
| ) | ||||
|  | ||||
| // Options holds client options | ||||
| @@ -29,8 +39,6 @@ type Options struct { | ||||
| 	Logger logger.Logger | ||||
| 	// Tracer used for tracing | ||||
| 	Tracer tracer.Tracer | ||||
| 	// Broker used to publish messages | ||||
| 	Broker broker.Broker | ||||
| 	// Meter used for metrics | ||||
| 	Meter meter.Meter | ||||
| 	// Context is used for external options | ||||
| @@ -199,7 +207,6 @@ func NewOptions(opts ...Option) Options { | ||||
| 		PoolTTL:   DefaultPoolTTL, | ||||
| 		Selector:  random.NewSelector(), | ||||
| 		Logger:    logger.DefaultLogger, | ||||
| 		Broker:    broker.DefaultBroker, | ||||
| 		Meter:     meter.DefaultMeter, | ||||
| 		Tracer:    tracer.DefaultTracer, | ||||
| 		Router:    router.DefaultRouter, | ||||
| @@ -213,13 +220,6 @@ func NewOptions(opts ...Option) Options { | ||||
| 	return options | ||||
| } | ||||
|  | ||||
| // Broker to be used for pub/sub | ||||
| func Broker(b broker.Broker) Option { | ||||
| 	return func(o *Options) { | ||||
| 		o.Broker = b | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Tracer to be used for tracing | ||||
| func Tracer(t tracer.Tracer) Option { | ||||
| 	return func(o *Options) { | ||||
|   | ||||
| @@ -3,7 +3,7 @@ package client | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/errors" | ||||
| 	"go.unistack.org/micro/v4/errors" | ||||
| ) | ||||
|  | ||||
| // RetryFunc that returning either false or a non-nil error will result in the call not being retried | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"testing" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/errors" | ||||
| 	"go.unistack.org/micro/v4/errors" | ||||
| ) | ||||
|  | ||||
| func TestRetryAlways(t *testing.T) { | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| package client | ||||
|  | ||||
| import ( | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| ) | ||||
|  | ||||
| type testRequest struct { | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| // Package codec is an interface for encoding messages | ||||
| package codec // import "go.unistack.org/micro/v3/codec" | ||||
| package codec // import "go.unistack.org/micro/v4/codec" | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"io" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| ) | ||||
|  | ||||
| // Message types | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2021 Unistack LLC | ||||
| // Copyright 2021-2023 Unistack LLC | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| @@ -17,7 +17,7 @@ syntax = "proto3"; | ||||
| package micro.codec; | ||||
|  | ||||
| option cc_enable_arenas = true; | ||||
| option go_package = "go.unistack.org/micro/v3/codec;codec"; | ||||
| option go_package = "go.unistack.org/micro/v4/codec;codec"; | ||||
| option java_multiple_files = true; | ||||
| option java_outer_classname = "MicroCodec"; | ||||
| option java_package = "micro.codec"; | ||||
|   | ||||
| @@ -3,9 +3,9 @@ package codec | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| // Option func | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package config is an interface for dynamic configuration. | ||||
| package config // import "go.unistack.org/micro/v3/config" | ||||
| package config // import "go.unistack.org/micro/v4/config" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|   | ||||
| @@ -8,8 +8,8 @@ import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/imdario/mergo" | ||||
| 	rutil "go.unistack.org/micro/v3/util/reflect" | ||||
| 	mtime "go.unistack.org/micro/v3/util/time" | ||||
| 	rutil "go.unistack.org/micro/v4/util/reflect" | ||||
| 	mtime "go.unistack.org/micro/v4/util/time" | ||||
| ) | ||||
|  | ||||
| type defaultConfig struct { | ||||
| @@ -169,7 +169,7 @@ func fillValue(value reflect.Value, val string) error { | ||||
| 				return err | ||||
| 			} | ||||
| 			value.Set(reflect.ValueOf(v)) | ||||
| 		case value.Type().String() == "time.Duration" && value.Type().PkgPath() == "go.unistack.org/micro/v3/util/time": | ||||
| 		case value.Type().String() == "time.Duration" && value.Type().PkgPath() == "go.unistack.org/micro/v4/util/time": | ||||
| 			v, err := mtime.ParseDuration(val) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
|   | ||||
| @@ -6,8 +6,8 @@ import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/config" | ||||
| 	mtime "go.unistack.org/micro/v3/util/time" | ||||
| 	"go.unistack.org/micro/v4/config" | ||||
| 	mtime "go.unistack.org/micro/v4/util/time" | ||||
| ) | ||||
|  | ||||
| type cfg struct { | ||||
| @@ -17,6 +17,7 @@ type cfg struct { | ||||
| 	IntValue       int             `default:"99"` | ||||
| 	DurationValue  time.Duration   `default:"10s"` | ||||
| 	MDurationValue mtime.Duration  `default:"10s"` | ||||
| 	MapValue       map[string]bool `default:"key1=true,key2=false"` | ||||
| } | ||||
|  | ||||
| type cfgStructValue struct { | ||||
| @@ -67,6 +68,9 @@ func TestDefault(t *testing.T) { | ||||
| 	if conf.StringValue != "after_load" { | ||||
| 		t.Fatal("AfterLoad option not working") | ||||
| 	} | ||||
| 	if len(conf.MapValue) != 2 { | ||||
| 		t.Fatalf("map value invalid: %#+v\n", conf.MapValue) | ||||
| 	} | ||||
| 	_ = conf | ||||
| 	// t.Logf("%#+v\n", conf) | ||||
| } | ||||
|   | ||||
| @@ -4,10 +4,10 @@ import ( | ||||
| 	"context" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| // Options hold the config options | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| // Package errors provides a way to return detailed information | ||||
| // for an RPC request error. The error is normally JSON encoded. | ||||
| package errors // import "go.unistack.org/micro/v3/errors" | ||||
| package errors // import "go.unistack.org/micro/v4/errors" | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2021 Unistack LLC | ||||
| // Copyright 2021-2023 Unistack LLC | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| @@ -17,7 +17,7 @@ syntax = "proto3"; | ||||
| package micro.errors; | ||||
|  | ||||
| option cc_enable_arenas = true; | ||||
| option go_package = "go.unistack.org/micro/v3/errors;errors"; | ||||
| option go_package = "go.unistack.org/micro/v4/errors;errors"; | ||||
| option java_multiple_files = true; | ||||
| option java_outer_classname = "MicroErrors"; | ||||
| option java_package = "micro.errors"; | ||||
|   | ||||
							
								
								
									
										27
									
								
								event.go
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								event.go
									
									
									
									
									
								
							| @@ -1,27 +0,0 @@ | ||||
| package micro | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| ) | ||||
|  | ||||
| // Event is used to publish messages to a topic | ||||
| type Event interface { | ||||
| 	// Publish publishes a message to the event topic | ||||
| 	Publish(ctx context.Context, msg interface{}, opts ...client.PublishOption) error | ||||
| } | ||||
|  | ||||
| type event struct { | ||||
| 	c     client.Client | ||||
| 	topic string | ||||
| } | ||||
|  | ||||
| // NewEvent creates a new event publisher | ||||
| func NewEvent(topic string, c client.Client) Event { | ||||
| 	return &event{c, topic} | ||||
| } | ||||
|  | ||||
| func (e *event) Publish(ctx context.Context, msg interface{}, opts ...client.PublishOption) error { | ||||
| 	return e.c.Publish(ctx, e.c.NewMessage(e.topic, msg), opts...) | ||||
| } | ||||
| @@ -6,12 +6,12 @@ import ( | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/silas/dag" | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/store" | ||||
| 	"go.unistack.org/micro/v3/util/id" | ||||
| 	"go.unistack.org/micro/v4/client" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| 	"go.unistack.org/micro/v4/store" | ||||
| 	"go.unistack.org/micro/v4/util/id" | ||||
| ) | ||||
|  | ||||
| type microFlow struct { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package flow is an interface used for saga pattern microservice workflow | ||||
| package flow // import "go.unistack.org/micro/v3/flow" | ||||
| package flow // import "go.unistack.org/micro/v4/flow" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| @@ -7,7 +7,7 @@ import ( | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|   | ||||
| @@ -4,11 +4,11 @@ import ( | ||||
| 	"context" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/store" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/client" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/store" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| // Option func | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| package fsm // import "go.unistack.org/micro/v3/fsm" | ||||
| package fsm // import "go.unistack.org/micro/v4/fsm" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"testing" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| ) | ||||
|  | ||||
| func TestFSMStart(t *testing.T) { | ||||
|   | ||||
							
								
								
									
										18
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								go.mod
									
									
									
									
									
								
							| @@ -1,9 +1,19 @@ | ||||
| module go.unistack.org/micro/v3 | ||||
| module go.unistack.org/micro/v4 | ||||
|  | ||||
| go 1.19 | ||||
| go 1.20 | ||||
|  | ||||
| require ( | ||||
| 	github.com/imdario/mergo v0.3.14 | ||||
| 	github.com/DATA-DOG/go-sqlmock v1.5.0 | ||||
| 	github.com/imdario/mergo v0.3.15 | ||||
| 	github.com/patrickmn/go-cache v2.1.0+incompatible | ||||
| 	github.com/silas/dag v0.0.0-20211117232152-9d50aa809f35 | ||||
| 	github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5 | ||||
| 	golang.org/x/sync v0.1.0 | ||||
| 	golang.org/x/sys v0.7.0 | ||||
| 	google.golang.org/grpc v1.54.0 | ||||
| 	google.golang.org/protobuf v1.30.0 | ||||
| ) | ||||
|  | ||||
| require ( | ||||
| 	github.com/golang/protobuf v1.5.3 // indirect | ||||
| 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect | ||||
| ) | ||||
|   | ||||
							
								
								
									
										30
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								go.sum
									
									
									
									
									
								
							| @@ -1,9 +1,31 @@ | ||||
| github.com/imdario/mergo v0.3.14 h1:fOqeC1+nCuuk6PKQdg9YmosXX7Y7mHX6R/0ZldI9iHo= | ||||
| github.com/imdario/mergo v0.3.14/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= | ||||
| github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= | ||||
| github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= | ||||
| github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= | ||||
| github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= | ||||
| github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= | ||||
| github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||
| github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= | ||||
| github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= | ||||
| github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= | ||||
| github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= | ||||
| github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= | ||||
| github.com/silas/dag v0.0.0-20211117232152-9d50aa809f35 h1:4mohWoM/UGg1BvFFiqSPRl5uwJY3rVV0HQX0ETqauqQ= | ||||
| github.com/silas/dag v0.0.0-20211117232152-9d50aa809f35/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I= | ||||
| github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5 h1:G/FZtUu7a6NTWl3KUHMV9jkLAh/Rvtf03NWMHaEDl+E= | ||||
| github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I= | ||||
| golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= | ||||
| golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= | ||||
| golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= | ||||
| golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= | ||||
| golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= | ||||
| google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= | ||||
| google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= | ||||
| google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= | ||||
| google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= | ||||
| google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= | ||||
| google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= | ||||
| google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package logger provides a log interface | ||||
| package logger // import "go.unistack.org/micro/v3/logger" | ||||
| package logger // import "go.unistack.org/micro/v4/logger" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|   | ||||
| @@ -8,7 +8,7 @@ import ( | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| ) | ||||
|  | ||||
| const sf = "0-+# " | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| ) | ||||
|  | ||||
| func TestUnwrap(t *testing.T) { | ||||
|   | ||||
| @@ -5,9 +5,9 @@ import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/server" | ||||
| 	"go.unistack.org/micro/v4/client" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/server" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package metadata is a way of defining message headers | ||||
| package metadata // import "go.unistack.org/micro/v3/metadata" | ||||
| package metadata // import "go.unistack.org/micro/v4/metadata" | ||||
|  | ||||
| import ( | ||||
| 	"net/textproto" | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package meter is for instrumentation | ||||
| package meter // import "go.unistack.org/micro/v3/meter" | ||||
| package meter // import "go.unistack.org/micro/v4/meter" | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
|   | ||||
| @@ -3,7 +3,7 @@ package meter | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| ) | ||||
|  | ||||
| // Option powers the configuration for metrics implementations: | ||||
|   | ||||
| @@ -1,49 +1,16 @@ | ||||
| package wrapper // import "go.unistack.org/micro/v3/meter/wrapper" | ||||
| package wrapper // import "go.unistack.org/micro/v4/meter/wrapper" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/server" | ||||
| 	"go.unistack.org/micro/v4/client" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/server" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// ClientRequestDurationSeconds specifies meter metric name | ||||
| 	ClientRequestDurationSeconds = "client_request_duration_seconds" | ||||
| 	// ClientRequestLatencyMicroseconds specifies meter metric name | ||||
| 	ClientRequestLatencyMicroseconds = "client_request_latency_microseconds" | ||||
| 	// ClientRequestTotal specifies meter metric name | ||||
| 	ClientRequestTotal = "client_request_total" | ||||
| 	// ClientRequestInflight specifies meter metric name | ||||
| 	ClientRequestInflight = "client_request_inflight" | ||||
| 	// ServerRequestDurationSeconds specifies meter metric name | ||||
| 	ServerRequestDurationSeconds = "server_request_duration_seconds" | ||||
| 	// ServerRequestLatencyMicroseconds specifies meter metric name | ||||
| 	ServerRequestLatencyMicroseconds = "server_request_latency_microseconds" | ||||
| 	// ServerRequestTotal specifies meter metric name | ||||
| 	ServerRequestTotal = "server_request_total" | ||||
| 	// ServerRequestInflight specifies meter metric name | ||||
| 	ServerRequestInflight = "server_request_inflight" | ||||
| 	// PublishMessageDurationSeconds specifies meter metric name | ||||
| 	PublishMessageDurationSeconds = "publish_message_duration_seconds" | ||||
| 	// PublishMessageLatencyMicroseconds specifies meter metric name | ||||
| 	PublishMessageLatencyMicroseconds = "publish_message_latency_microseconds" | ||||
| 	// PublishMessageTotal specifies meter metric name | ||||
| 	PublishMessageTotal = "publish_message_total" | ||||
| 	// PublishMessageInflight specifies meter metric name | ||||
| 	PublishMessageInflight = "publish_message_inflight" | ||||
| 	// SubscribeMessageDurationSeconds specifies meter metric name | ||||
| 	SubscribeMessageDurationSeconds = "subscribe_message_duration_seconds" | ||||
| 	// SubscribeMessageLatencyMicroseconds specifies meter metric name | ||||
| 	SubscribeMessageLatencyMicroseconds = "subscribe_message_latency_microseconds" | ||||
| 	// SubscribeMessageTotal specifies meter metric name | ||||
| 	SubscribeMessageTotal = "subscribe_message_total" | ||||
| 	// SubscribeMessageInflight specifies meter metric name | ||||
| 	SubscribeMessageInflight = "subscribe_message_inflight" | ||||
|  | ||||
| 	labelSuccess  = "success" | ||||
| 	labelFailure  = "failure" | ||||
| 	labelStatus   = "status" | ||||
| @@ -230,37 +197,7 @@ func (w *wrapper) Stream(ctx context.Context, req client.Request, opts ...client | ||||
| } | ||||
|  | ||||
| func (w *wrapper) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error { | ||||
| 	endpoint := p.Topic() | ||||
|  | ||||
| 	labels := make([]string, 0, 4) | ||||
| 	labels = append(labels, labelEndpoint, endpoint) | ||||
|  | ||||
| 	w.opts.Meter.Counter(PublishMessageInflight, labels...).Inc() | ||||
| 	ts := time.Now() | ||||
| 	err := w.Client.Publish(ctx, p, opts...) | ||||
| 	te := time.Since(ts) | ||||
| 	w.opts.Meter.Counter(PublishMessageInflight, labels...).Dec() | ||||
|  | ||||
| 	w.opts.Meter.Summary(PublishMessageLatencyMicroseconds, labels...).Update(te.Seconds()) | ||||
| 	w.opts.Meter.Histogram(PublishMessageDurationSeconds, labels...).Update(te.Seconds()) | ||||
|  | ||||
| 	if err == nil { | ||||
| 		labels = append(labels, labelStatus, labelSuccess) | ||||
| 	} else { | ||||
| 		labels = append(labels, labelStatus, labelFailure) | ||||
| 	} | ||||
| 	w.opts.Meter.Counter(PublishMessageTotal, labels...).Inc() | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // NewHandlerWrapper create new server handler wrapper | ||||
| // deprecated | ||||
| func NewHandlerWrapper(opts ...Option) server.HandlerWrapper { | ||||
| 	handler := &wrapper{ | ||||
| 		opts: NewOptions(opts...), | ||||
| 	} | ||||
| 	return handler.HandlerFunc | ||||
| 	return w.Client.Publish(ctx, p, opts...) | ||||
| } | ||||
|  | ||||
| // NewServerHandlerWrapper create new server handler wrapper | ||||
| @@ -302,46 +239,3 @@ func (w *wrapper) HandlerFunc(fn server.HandlerFunc) server.HandlerFunc { | ||||
| 		return err | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // NewSubscriberWrapper create server subscribe wrapper | ||||
| // deprecated | ||||
| func NewSubscriberWrapper(opts ...Option) server.SubscriberWrapper { | ||||
| 	handler := &wrapper{ | ||||
| 		opts: NewOptions(opts...), | ||||
| 	} | ||||
| 	return handler.SubscriberFunc | ||||
| } | ||||
|  | ||||
| func NewServerSubscriberWrapper(opts ...Option) server.SubscriberWrapper { | ||||
| 	handler := &wrapper{ | ||||
| 		opts: NewOptions(opts...), | ||||
| 	} | ||||
| 	return handler.SubscriberFunc | ||||
| } | ||||
|  | ||||
| func (w *wrapper) SubscriberFunc(fn server.SubscriberFunc) server.SubscriberFunc { | ||||
| 	return func(ctx context.Context, msg server.Message) error { | ||||
| 		endpoint := msg.Topic() | ||||
|  | ||||
| 		labels := make([]string, 0, 4) | ||||
| 		labels = append(labels, labelEndpoint, endpoint) | ||||
|  | ||||
| 		w.opts.Meter.Counter(SubscribeMessageInflight, labels...).Inc() | ||||
| 		ts := time.Now() | ||||
| 		err := fn(ctx, msg) | ||||
| 		te := time.Since(ts) | ||||
| 		w.opts.Meter.Counter(SubscribeMessageInflight, labels...).Dec() | ||||
|  | ||||
| 		w.opts.Meter.Summary(SubscribeMessageLatencyMicroseconds, labels...).Update(te.Seconds()) | ||||
| 		w.opts.Meter.Histogram(SubscribeMessageDurationSeconds, labels...).Update(te.Seconds()) | ||||
|  | ||||
| 		if err == nil { | ||||
| 			labels = append(labels, labelStatus, labelSuccess) | ||||
| 		} else { | ||||
| 			labels = append(labels, labelStatus, labelFailure) | ||||
| 		} | ||||
| 		w.opts.Meter.Counter(SubscribeMessageTotal, labels...).Inc() | ||||
|  | ||||
| 		return err | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| package mtls // import "go.unistack.org/micro/v3/mtls" | ||||
| package mtls // import "go.unistack.org/micro/v4/mtls" | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| // Package network is for creating internetworks | ||||
| package network // import "go.unistack.org/micro/v3/network" | ||||
| package network // import "go.unistack.org/micro/v4/network" | ||||
|  | ||||
| import ( | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/server" | ||||
| 	"go.unistack.org/micro/v4/client" | ||||
| 	"go.unistack.org/micro/v4/server" | ||||
| ) | ||||
|  | ||||
| // Error is network node errors | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| package network | ||||
|  | ||||
| import ( | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/network/tunnel" | ||||
| 	"go.unistack.org/micro/v3/proxy" | ||||
| 	"go.unistack.org/micro/v3/router" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v3/util/id" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/network/tunnel" | ||||
| 	"go.unistack.org/micro/v4/proxy" | ||||
| 	"go.unistack.org/micro/v4/router" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| 	"go.unistack.org/micro/v4/util/id" | ||||
| ) | ||||
|  | ||||
| // Option func | ||||
|   | ||||
| @@ -8,9 +8,9 @@ import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	maddr "go.unistack.org/micro/v3/util/addr" | ||||
| 	mnet "go.unistack.org/micro/v3/util/net" | ||||
| 	"go.unistack.org/micro/v3/util/rand" | ||||
| 	maddr "go.unistack.org/micro/v4/util/addr" | ||||
| 	mnet "go.unistack.org/micro/v4/util/net" | ||||
| 	"go.unistack.org/micro/v4/util/rand" | ||||
| ) | ||||
|  | ||||
| type memorySocket struct { | ||||
|   | ||||
| @@ -5,10 +5,10 @@ import ( | ||||
| 	"crypto/tls" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| // Options struct holds the transport options | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| // Package transport is an interface for synchronous connection based communication | ||||
| package transport // import "go.unistack.org/micro/v3/network/transport" | ||||
| package transport // import "go.unistack.org/micro/v4/network/transport" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
| // Package broker is a tunnel broker | ||||
| package broker // import "go.unistack.org/micro/v3/network/tunnel/broker" | ||||
| package broker // import "go.unistack.org/micro/v4/network/tunnel/broker" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/broker" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/network/transport" | ||||
| 	"go.unistack.org/micro/v3/network/tunnel" | ||||
| 	"go.unistack.org/micro/v4/broker" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| 	"go.unistack.org/micro/v4/network/transport" | ||||
| 	"go.unistack.org/micro/v4/network/tunnel" | ||||
| ) | ||||
|  | ||||
| type tunBroker struct { | ||||
|   | ||||
| @@ -3,11 +3,11 @@ package tunnel | ||||
| import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/network/transport" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v3/util/id" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/network/transport" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| 	"go.unistack.org/micro/v4/util/id" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| package transport | ||||
|  | ||||
| import ( | ||||
| 	"go.unistack.org/micro/v3/network/transport" | ||||
| 	"go.unistack.org/micro/v3/network/tunnel" | ||||
| 	"go.unistack.org/micro/v4/network/transport" | ||||
| 	"go.unistack.org/micro/v4/network/tunnel" | ||||
| ) | ||||
|  | ||||
| type tunListener struct { | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| // Package transport provides a tunnel transport | ||||
| package transport // import "go.unistack.org/micro/v3/network/tunnel/transport" | ||||
| package transport // import "go.unistack.org/micro/v4/network/tunnel/transport" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/network/transport" | ||||
| 	"go.unistack.org/micro/v3/network/tunnel" | ||||
| 	"go.unistack.org/micro/v4/network/transport" | ||||
| 	"go.unistack.org/micro/v4/network/tunnel" | ||||
| ) | ||||
|  | ||||
| type tunTransport struct { | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| // Package tunnel provides gre network tunnelling | ||||
| package tunnel // import "go.unistack.org/micro/v3/network/transport/tunnel" | ||||
| package tunnel // import "go.unistack.org/micro/v4/network/transport/tunnel" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/network/transport" | ||||
| 	"go.unistack.org/micro/v4/network/transport" | ||||
| ) | ||||
|  | ||||
| // DefaultTunnel contains default tunnel implementation | ||||
|   | ||||
							
								
								
									
										50
									
								
								options.go
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								options.go
									
									
									
									
									
								
							| @@ -5,17 +5,17 @@ import ( | ||||
| 	"fmt" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/broker" | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/config" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| 	"go.unistack.org/micro/v3/router" | ||||
| 	"go.unistack.org/micro/v3/server" | ||||
| 	"go.unistack.org/micro/v3/store" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/broker" | ||||
| 	"go.unistack.org/micro/v4/client" | ||||
| 	"go.unistack.org/micro/v4/config" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/register" | ||||
| 	"go.unistack.org/micro/v4/router" | ||||
| 	"go.unistack.org/micro/v4/server" | ||||
| 	"go.unistack.org/micro/v4/store" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| // Options for micro service | ||||
| @@ -90,33 +90,7 @@ type Option func(*Options) error | ||||
| // Broker to be used for client and server | ||||
| func Broker(b broker.Broker, opts ...BrokerOption) Option { | ||||
| 	return func(o *Options) error { | ||||
| 		var err error | ||||
| 		bopts := brokerOptions{} | ||||
| 		for _, opt := range opts { | ||||
| 			opt(&bopts) | ||||
| 		} | ||||
| 		all := false | ||||
| 		if len(opts) == 0 { | ||||
| 			all = true | ||||
| 		} | ||||
| 		for _, srv := range o.Servers { | ||||
| 			for _, os := range bopts.servers { | ||||
| 				if srv.Name() == os || all { | ||||
| 					if err = srv.Init(server.Broker(b)); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		for _, cli := range o.Clients { | ||||
| 			for _, oc := range bopts.clients { | ||||
| 				if cli.Name() == oc || all { | ||||
| 					if err = cli.Init(client.Broker(b)); err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		o.Brokers = []broker.Broker{b} | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| package options // import "go.unistack.org/micro/v3/options" | ||||
| package options // import "go.unistack.org/micro/v4/options" | ||||
|  | ||||
| // Hook func interface | ||||
| type Hook interface{} | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package http enables the http profiler | ||||
| package http // import "go.unistack.org/micro/v3/profiler/http" | ||||
| package http // import "go.unistack.org/micro/v4/profiler/http" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| @@ -7,7 +7,7 @@ import ( | ||||
| 	"net/http/pprof" | ||||
| 	"sync" | ||||
|  | ||||
| 	profile "go.unistack.org/micro/v3/profiler" | ||||
| 	profile "go.unistack.org/micro/v4/profiler" | ||||
| ) | ||||
|  | ||||
| type httpProfile struct { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package pprof provides a pprof profiler which writes output to /tmp/[name].{cpu,mem}.pprof | ||||
| package pprof // import "go.unistack.org/micro/v3/profiler/pprof" | ||||
| package pprof // import "go.unistack.org/micro/v4/profiler/pprof" | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| @@ -9,7 +9,7 @@ import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	profile "go.unistack.org/micro/v3/profiler" | ||||
| 	profile "go.unistack.org/micro/v4/profiler" | ||||
| ) | ||||
|  | ||||
| type profiler struct { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package profiler is for profilers | ||||
| package profiler // import "go.unistack.org/micro/v3/profiler" | ||||
| package profiler // import "go.unistack.org/micro/v4/profiler" | ||||
|  | ||||
| // Profiler interface | ||||
| type Profiler interface { | ||||
|   | ||||
| @@ -2,11 +2,11 @@ | ||||
| package proxy | ||||
|  | ||||
| import ( | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/router" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/client" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/router" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| // Options for proxy | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| // Package proxy is a transparent proxy built on the micro/server | ||||
| package proxy // import "go.unistack.org/micro/v3/proxy" | ||||
| package proxy // import "go.unistack.org/micro/v4/proxy" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/server" | ||||
| 	"go.unistack.org/micro/v4/server" | ||||
| ) | ||||
|  | ||||
| // DefaultEndpoint holds default proxy address | ||||
|   | ||||
| @@ -6,7 +6,7 @@ import ( | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| ) | ||||
|  | ||||
| // ExtractValue from reflect.Type from specified depth | ||||
|   | ||||
| @@ -5,8 +5,8 @@ import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/util/id" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/util/id" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|   | ||||
| @@ -5,9 +5,9 @@ import ( | ||||
| 	"crypto/tls" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| // Options holds options for register | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| // Package register is an interface for service discovery | ||||
| package register // import "go.unistack.org/micro/v3/register" | ||||
| package register // import "go.unistack.org/micro/v4/register" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package dns resolves names to dns records | ||||
| package dns // import "go.unistack.org/micro/v3/resolver/dns" | ||||
| package dns // import "go.unistack.org/micro/v4/resolver/dns" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| @@ -7,7 +7,7 @@ import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/resolver" | ||||
| 	"go.unistack.org/micro/v4/resolver" | ||||
| ) | ||||
|  | ||||
| // Resolver is a DNS network resolve | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| // Package dnssrv resolves names to dns srv records | ||||
| package dnssrv // import "go.unistack.org/micro/v3/resolver/dnssrv" | ||||
| package dnssrv // import "go.unistack.org/micro/v4/resolver/dnssrv" | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/resolver" | ||||
| 	"go.unistack.org/micro/v4/resolver" | ||||
| ) | ||||
|  | ||||
| // Resolver is a DNS network resolve | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package http resolves names to network addresses using a http request | ||||
| package http // import "go.unistack.org/micro/v3/resolver/http" | ||||
| package http // import "go.unistack.org/micro/v4/resolver/http" | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| @@ -8,7 +8,7 @@ import ( | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/resolver" | ||||
| 	"go.unistack.org/micro/v4/resolver" | ||||
| ) | ||||
|  | ||||
| // nolint: golint,revive | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| // Package noop is a noop resolver | ||||
| package noop // import "go.unistack.org/micro/v3/resolver/noop" | ||||
| package noop // import "go.unistack.org/micro/v4/resolver/noop" | ||||
|  | ||||
| import ( | ||||
| 	"go.unistack.org/micro/v3/resolver" | ||||
| 	"go.unistack.org/micro/v4/resolver" | ||||
| ) | ||||
|  | ||||
| // Resolver contains noop resolver | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| // Package register resolves names using the micro register | ||||
| package register // import "go.unistack.org/micro/v3/resolver/registry" | ||||
| package register // import "go.unistack.org/micro/v4/resolver/registry" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| 	"go.unistack.org/micro/v3/resolver" | ||||
| 	"go.unistack.org/micro/v4/register" | ||||
| 	"go.unistack.org/micro/v4/resolver" | ||||
| ) | ||||
|  | ||||
| // Resolver is a register network resolver | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package resolver resolves network names to addresses | ||||
| package resolver // import "go.unistack.org/micro/v3/resolver" | ||||
| package resolver // import "go.unistack.org/micro/v4/resolver" | ||||
|  | ||||
| // Resolver is network resolver. It's used to find network nodes | ||||
| // via the name to connect to. This is done based on Network.Name(). | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| // Package static is a static resolver | ||||
| package static // import "go.unistack.org/micro/v3/resolver/static" | ||||
| package static // import "go.unistack.org/micro/v4/resolver/static" | ||||
|  | ||||
| import ( | ||||
| 	"go.unistack.org/micro/v3/resolver" | ||||
| 	"go.unistack.org/micro/v4/resolver" | ||||
| ) | ||||
|  | ||||
| // Resolver returns a static list of nodes. In the event the node list | ||||
|   | ||||
| @@ -3,9 +3,9 @@ package router | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| 	"go.unistack.org/micro/v3/util/id" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/register" | ||||
| 	"go.unistack.org/micro/v4/util/id" | ||||
| ) | ||||
|  | ||||
| // Options are router options | ||||
|   | ||||
| @@ -3,7 +3,7 @@ package router | ||||
| import ( | ||||
| 	"hash/fnv" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package router provides a network routing control plane | ||||
| package router // import "go.unistack.org/micro/v3/router" | ||||
| package router // import "go.unistack.org/micro/v4/router" | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| package random // import "go.unistack.org/micro/v3/selector/random" | ||||
| package random // import "go.unistack.org/micro/v4/selector/random" | ||||
|  | ||||
| import ( | ||||
| 	"go.unistack.org/micro/v3/selector" | ||||
| 	"go.unistack.org/micro/v3/util/rand" | ||||
| 	"go.unistack.org/micro/v4/selector" | ||||
| 	"go.unistack.org/micro/v4/util/rand" | ||||
| ) | ||||
|  | ||||
| type random struct{} | ||||
|   | ||||
| @@ -3,7 +3,7 @@ package random | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/selector" | ||||
| 	"go.unistack.org/micro/v4/selector" | ||||
| ) | ||||
|  | ||||
| func TestRandom(t *testing.T) { | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| package roundrobin // import "go.unistack.org/micro/v3/selector/roundrobin" | ||||
| package roundrobin // import "go.unistack.org/micro/v4/selector/roundrobin" | ||||
|  | ||||
| import ( | ||||
| 	"go.unistack.org/micro/v3/selector" | ||||
| 	"go.unistack.org/micro/v3/util/rand" | ||||
| 	"go.unistack.org/micro/v4/selector" | ||||
| 	"go.unistack.org/micro/v4/util/rand" | ||||
| ) | ||||
|  | ||||
| // NewSelector returns an initialised round robin selector | ||||
|   | ||||
| @@ -3,7 +3,7 @@ package roundrobin | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/selector" | ||||
| 	"go.unistack.org/micro/v4/selector" | ||||
| ) | ||||
|  | ||||
| func TestRoundRobin(t *testing.T) { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package selector is for node selection and load balancing | ||||
| package selector // import "go.unistack.org/micro/v3/selector" | ||||
| package selector // import "go.unistack.org/micro/v4/selector" | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
|   | ||||
| @@ -33,16 +33,6 @@ func SetOption(k, v interface{}) Option { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SetSubscriberOption returns a function to setup a context with given value | ||||
| func SetSubscriberOption(k, v interface{}) SubscriberOption { | ||||
| 	return func(o *SubscriberOptions) { | ||||
| 		if o.Context == nil { | ||||
| 			o.Context = context.Background() | ||||
| 		} | ||||
| 		o.Context = context.WithValue(o.Context, k, v) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SetHandlerOption returns a function to setup a context with given value | ||||
| func SetHandlerOption(k, v interface{}) HandlerOption { | ||||
| 	return func(o *HandlerOptions) { | ||||
|   | ||||
| @@ -51,14 +51,3 @@ func TestSetOption(t *testing.T) { | ||||
| 		t.Fatal("SetOption not works") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSetSubscriberOption(t *testing.T) { | ||||
| 	type key struct{} | ||||
| 	o := SetSubscriberOption(key{}, "test") | ||||
| 	opts := &SubscriberOptions{} | ||||
| 	o(opts) | ||||
|  | ||||
| 	if v, ok := opts.Context.Value(key{}).(string); !ok || v == "" { | ||||
| 		t.Fatal("SetSubscriberOption not works") | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| package server | ||||
|  | ||||
| import "go.unistack.org/micro/v3/errors" | ||||
| import "go.unistack.org/micro/v4/errors" | ||||
|  | ||||
| type Error struct { | ||||
| 	id string | ||||
|   | ||||
| @@ -3,7 +3,7 @@ package server | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/errors" | ||||
| 	"go.unistack.org/micro/v4/errors" | ||||
| ) | ||||
|  | ||||
| func TestError(t *testing.T) { | ||||
|   | ||||
| @@ -1,59 +0,0 @@ | ||||
| package server | ||||
|  | ||||
| import ( | ||||
| 	"reflect" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| ) | ||||
|  | ||||
| type rpcHandler struct { | ||||
| 	opts      HandlerOptions | ||||
| 	handler   interface{} | ||||
| 	name      string | ||||
| 	endpoints []*register.Endpoint | ||||
| } | ||||
|  | ||||
| func newRPCHandler(handler interface{}, opts ...HandlerOption) Handler { | ||||
| 	options := NewHandlerOptions(opts...) | ||||
|  | ||||
| 	typ := reflect.TypeOf(handler) | ||||
| 	hdlr := reflect.ValueOf(handler) | ||||
| 	name := reflect.Indirect(hdlr).Type().Name() | ||||
|  | ||||
| 	var endpoints []*register.Endpoint | ||||
|  | ||||
| 	for m := 0; m < typ.NumMethod(); m++ { | ||||
| 		if e := register.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() []*register.Endpoint { | ||||
| 	return r.endpoints | ||||
| } | ||||
|  | ||||
| func (r *rpcHandler) Options() HandlerOptions { | ||||
| 	return r.opts | ||||
| } | ||||
							
								
								
									
										199
									
								
								server/noop.go
									
									
									
									
									
								
							
							
						
						
									
										199
									
								
								server/noop.go
									
									
									
									
									
								
							| @@ -1,18 +1,17 @@ | ||||
| package server | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/broker" | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| 	maddr "go.unistack.org/micro/v3/util/addr" | ||||
| 	mnet "go.unistack.org/micro/v3/util/net" | ||||
| 	"go.unistack.org/micro/v3/util/rand" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/register" | ||||
| 	maddr "go.unistack.org/micro/v4/util/addr" | ||||
| 	mnet "go.unistack.org/micro/v4/util/net" | ||||
| 	"go.unistack.org/micro/v4/util/rand" | ||||
| ) | ||||
|  | ||||
| // DefaultCodecs will be used to encode/decode | ||||
| @@ -29,7 +28,6 @@ type noopServer struct { | ||||
| 	wg       *sync.WaitGroup | ||||
| 	rsvc     *register.Service | ||||
| 	handlers map[string]Handler | ||||
| 	subscribers map[*subscriber][]broker.Subscriber | ||||
| 	exit     chan chan error | ||||
| 	opts     Options | ||||
| 	sync.RWMutex | ||||
| @@ -43,9 +41,6 @@ func NewServer(opts ...Option) Server { | ||||
| 	if n.handlers == nil { | ||||
| 		n.handlers = make(map[string]Handler) | ||||
| 	} | ||||
| 	if n.subscribers == nil { | ||||
| 		n.subscribers = make(map[*subscriber][]broker.Subscriber) | ||||
| 	} | ||||
| 	if n.exit == nil { | ||||
| 		n.exit = make(chan chan error) | ||||
| 	} | ||||
| @@ -71,37 +66,10 @@ func (n *noopServer) Name() string { | ||||
| 	return n.opts.Name | ||||
| } | ||||
|  | ||||
| func (n *noopServer) Subscribe(sb Subscriber) error { | ||||
| 	sub, ok := sb.(*subscriber) | ||||
| 	if !ok { | ||||
| 		return fmt.Errorf("invalid subscriber: expected *subscriber") | ||||
| 	} else if len(sub.handlers) == 0 { | ||||
| 		return fmt.Errorf("invalid subscriber: no handler functions") | ||||
| 	} | ||||
|  | ||||
| 	if err := ValidateSubscriber(sb); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	n.Lock() | ||||
| 	if _, ok = n.subscribers[sub]; ok { | ||||
| 		n.Unlock() | ||||
| 		return fmt.Errorf("subscriber %v already exists", sub) | ||||
| 	} | ||||
|  | ||||
| 	n.subscribers[sub] = nil | ||||
| 	n.Unlock() | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (n *noopServer) NewHandler(h interface{}, opts ...HandlerOption) Handler { | ||||
| 	return newRPCHandler(h, opts...) | ||||
| } | ||||
|  | ||||
| func (n *noopServer) NewSubscriber(topic string, sb interface{}, opts ...SubscriberOption) Subscriber { | ||||
| 	return newSubscriber(topic, sb, opts...) | ||||
| } | ||||
|  | ||||
| func (n *noopServer) Init(opts ...Option) error { | ||||
| 	for _, o := range opts { | ||||
| 		o(&n.opts) | ||||
| @@ -110,9 +78,6 @@ func (n *noopServer) Init(opts ...Option) error { | ||||
| 	if n.handlers == nil { | ||||
| 		n.handlers = make(map[string]Handler, 1) | ||||
| 	} | ||||
| 	if n.subscribers == nil { | ||||
| 		n.subscribers = make(map[*subscriber][]broker.Subscriber, 1) | ||||
| 	} | ||||
|  | ||||
| 	if n.exit == nil { | ||||
| 		n.exit = make(chan chan error) | ||||
| @@ -158,21 +123,10 @@ func (n *noopServer) Register() error { | ||||
|  | ||||
| 	sort.Strings(handlerList) | ||||
|  | ||||
| 	subscriberList := make([]*subscriber, 0, len(n.subscribers)) | ||||
| 	for e := range n.subscribers { | ||||
| 		subscriberList = append(subscriberList, e) | ||||
| 	} | ||||
| 	sort.Slice(subscriberList, func(i, j int) bool { | ||||
| 		return subscriberList[i].topic > subscriberList[j].topic | ||||
| 	}) | ||||
|  | ||||
| 	endpoints := make([]*register.Endpoint, 0, len(handlerList)+len(subscriberList)) | ||||
| 	endpoints := make([]*register.Endpoint, 0, len(handlerList)) | ||||
| 	for _, h := range handlerList { | ||||
| 		endpoints = append(endpoints, n.handlers[h].Endpoints()...) | ||||
| 	} | ||||
| 	for _, e := range subscriberList { | ||||
| 		endpoints = append(endpoints, e.Endpoints()...) | ||||
| 	} | ||||
| 	n.RUnlock() | ||||
|  | ||||
| 	service.Nodes[0].Metadata["protocol"] = "noop" | ||||
| @@ -202,39 +156,6 @@ func (n *noopServer) Register() error { | ||||
| 	n.Lock() | ||||
| 	defer n.Unlock() | ||||
|  | ||||
| 	cx := config.Context | ||||
|  | ||||
| 	var sub broker.Subscriber | ||||
|  | ||||
| 	for sb := range n.subscribers { | ||||
| 		if sb.Options().Context != nil { | ||||
| 			cx = sb.Options().Context | ||||
| 		} | ||||
|  | ||||
| 		opts := []broker.SubscribeOption{broker.SubscribeContext(cx), broker.SubscribeAutoAck(sb.Options().AutoAck)} | ||||
| 		if queue := sb.Options().Queue; len(queue) > 0 { | ||||
| 			opts = append(opts, broker.SubscribeGroup(queue)) | ||||
| 		} | ||||
|  | ||||
| 		if sb.Options().Batch { | ||||
| 			// batch processing handler | ||||
| 			sub, err = config.Broker.BatchSubscribe(cx, sb.Topic(), n.newBatchSubHandler(sb, config), opts...) | ||||
| 		} else { | ||||
| 			// single processing handler | ||||
| 			sub, err = config.Broker.Subscribe(cx, sb.Topic(), n.newSubHandler(sb, config), opts...) | ||||
| 		} | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		if config.Logger.V(logger.InfoLevel) { | ||||
| 			config.Logger.Infof(n.opts.Context, "subscribing to topic: %s", sb.Topic()) | ||||
| 		} | ||||
|  | ||||
| 		n.subscribers[sb] = []broker.Subscriber{sub} | ||||
| 	} | ||||
|  | ||||
| 	n.registered = true | ||||
| 	if cacheService { | ||||
| 		n.rsvc = service | ||||
| @@ -273,33 +194,6 @@ func (n *noopServer) Deregister() error { | ||||
|  | ||||
| 	n.registered = false | ||||
|  | ||||
| 	cx := config.Context | ||||
|  | ||||
| 	wg := sync.WaitGroup{} | ||||
| 	for sb, subs := range n.subscribers { | ||||
| 		for idx := range subs { | ||||
| 			if sb.Options().Context != nil { | ||||
| 				cx = sb.Options().Context | ||||
| 			} | ||||
|  | ||||
| 			ncx := cx | ||||
| 			wg.Add(1) | ||||
| 			go func(s broker.Subscriber) { | ||||
| 				defer wg.Done() | ||||
| 				if config.Logger.V(logger.InfoLevel) { | ||||
| 					config.Logger.Infof(n.opts.Context, "unsubscribing from topic: %s", s.Topic()) | ||||
| 				} | ||||
| 				if err := s.Unsubscribe(ncx); err != nil { | ||||
| 					if config.Logger.V(logger.ErrorLevel) { | ||||
| 						config.Logger.Errorf(n.opts.Context, "unsubscribing from topic: %s err: %v", s.Topic(), err) | ||||
| 					} | ||||
| 				} | ||||
| 			}(subs[idx]) | ||||
| 		} | ||||
| 		n.subscribers[sb] = nil | ||||
| 	} | ||||
| 	wg.Wait() | ||||
|  | ||||
| 	n.Unlock() | ||||
| 	return nil | ||||
| } | ||||
| @@ -336,21 +230,6 @@ func (n *noopServer) Start() error { | ||||
| 	} | ||||
| 	n.Unlock() | ||||
|  | ||||
| 	// only connect if we're subscribed | ||||
| 	if len(n.subscribers) > 0 { | ||||
| 		// connect to the broker | ||||
| 		if err := config.Broker.Connect(config.Context); err != nil { | ||||
| 			if config.Logger.V(logger.ErrorLevel) { | ||||
| 				config.Logger.Errorf(n.opts.Context, "broker [%s] connect error: %v", config.Broker.String(), err) | ||||
| 			} | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		if config.Logger.V(logger.InfoLevel) { | ||||
| 			config.Logger.Infof(n.opts.Context, "broker [%s] Connected to %s", config.Broker.String(), config.Broker.Address()) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// use RegisterCheck func before register | ||||
| 	// nolint: nestif | ||||
| 	if err := config.RegisterCheck(config.Context); err != nil { | ||||
| @@ -429,16 +308,6 @@ func (n *noopServer) Start() error { | ||||
|  | ||||
| 		// close transport | ||||
| 		ch <- nil | ||||
|  | ||||
| 		if config.Logger.V(logger.InfoLevel) { | ||||
| 			config.Logger.Infof(n.opts.Context, "broker [%s] Disconnected from %s", config.Broker.String(), config.Broker.Address()) | ||||
| 		} | ||||
| 		// disconnect broker | ||||
| 		if err := config.Broker.Disconnect(config.Context); err != nil { | ||||
| 			if config.Logger.V(logger.ErrorLevel) { | ||||
| 				config.Logger.Errorf(n.opts.Context, "broker [%s] disconnect error: %v", config.Broker.String(), err) | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	// mark the server as started | ||||
| @@ -468,3 +337,55 @@ func (n *noopServer) Stop() error { | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| type rpcHandler struct { | ||||
| 	opts      HandlerOptions | ||||
| 	handler   interface{} | ||||
| 	name      string | ||||
| 	endpoints []*register.Endpoint | ||||
| } | ||||
|  | ||||
| func newRPCHandler(handler interface{}, opts ...HandlerOption) Handler { | ||||
| 	options := NewHandlerOptions(opts...) | ||||
|  | ||||
| 	typ := reflect.TypeOf(handler) | ||||
| 	hdlr := reflect.ValueOf(handler) | ||||
| 	name := reflect.Indirect(hdlr).Type().Name() | ||||
|  | ||||
| 	var endpoints []*register.Endpoint | ||||
|  | ||||
| 	for m := 0; m < typ.NumMethod(); m++ { | ||||
| 		if e := register.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() []*register.Endpoint { | ||||
| 	return r.endpoints | ||||
| } | ||||
|  | ||||
| func (r *rpcHandler) Options() HandlerOptions { | ||||
| 	return r.opts | ||||
| } | ||||
|   | ||||
| @@ -1,104 +0,0 @@ | ||||
| package server_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"testing" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/broker" | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/server" | ||||
| ) | ||||
|  | ||||
| type TestHandler struct { | ||||
| 	t *testing.T | ||||
| } | ||||
|  | ||||
| type TestMessage struct { | ||||
| 	Name string | ||||
| } | ||||
|  | ||||
| func (h *TestHandler) SingleSubHandler(ctx context.Context, msg *codec.Frame) error { | ||||
| 	// fmt.Printf("msg %s\n", msg.Data) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (h *TestHandler) BatchSubHandler(ctxs []context.Context, msgs []*codec.Frame) error { | ||||
| 	if len(msgs) != 8 { | ||||
| 		h.t.Fatal("invalid number of messages received") | ||||
| 	} | ||||
| 	for idx := 0; idx < len(msgs); idx++ { | ||||
| 		md, _ := metadata.FromIncomingContext(ctxs[idx]) | ||||
| 		_ = md | ||||
| 		//	fmt.Printf("msg md %v\n", md) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func TestNoopSub(t *testing.T) { | ||||
| 	ctx := context.Background() | ||||
|  | ||||
| 	b := broker.NewBroker() | ||||
|  | ||||
| 	if err := b.Init(); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if err := b.Connect(ctx); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	logger.DefaultLogger.Init(logger.WithLevel(logger.ErrorLevel)) | ||||
| 	s := server.NewServer( | ||||
| 		server.Broker(b), | ||||
| 		server.Codec("application/octet-stream", codec.NewCodec()), | ||||
| 	) | ||||
| 	if err := s.Init(); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	c := client.NewClient( | ||||
| 		client.Broker(b), | ||||
| 		client.Codec("application/octet-stream", codec.NewCodec()), | ||||
| 		client.ContentType("application/octet-stream"), | ||||
| 	) | ||||
| 	if err := c.Init(); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	h := &TestHandler{t: t} | ||||
|  | ||||
| 	if err := s.Subscribe(s.NewSubscriber("single_topic", h.SingleSubHandler, | ||||
| 		server.SubscriberQueue("queue"), | ||||
| 	)); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if err := s.Subscribe(s.NewSubscriber("batch_topic", h.BatchSubHandler, | ||||
| 		server.SubscriberQueue("queue"), | ||||
| 		server.SubscriberBatch(true), | ||||
| 	)); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if err := s.Start(); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	msgs := make([]client.Message, 0, 8) | ||||
| 	for i := 0; i < 8; i++ { | ||||
| 		msgs = append(msgs, c.NewMessage("batch_topic", &codec.Frame{Data: []byte(fmt.Sprintf(`{"name": "test_name %d"}`, i))})) | ||||
| 	} | ||||
|  | ||||
| 	if err := c.BatchPublish(ctx, msgs); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	defer func() { | ||||
| 		if err := s.Stop(); err != nil { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
| 	}() | ||||
| } | ||||
| @@ -7,16 +7,26 @@ import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/broker" | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/network/transport" | ||||
| 	"go.unistack.org/micro/v3/options" | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v3/util/id" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/network/transport" | ||||
| 	"go.unistack.org/micro/v4/options" | ||||
| 	"go.unistack.org/micro/v4/register" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| 	"go.unistack.org/micro/v4/util/id" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// ServerRequestDurationSeconds specifies meter metric name | ||||
| 	ServerRequestDurationSeconds = "server_request_duration_seconds" | ||||
| 	// ServerRequestLatencyMicroseconds specifies meter metric name | ||||
| 	ServerRequestLatencyMicroseconds = "server_request_latency_microseconds" | ||||
| 	// ServerRequestTotal specifies meter metric name | ||||
| 	ServerRequestTotal = "server_request_total" | ||||
| 	// ServerRequestInflight specifies meter metric name | ||||
| 	ServerRequestInflight = "server_request_inflight" | ||||
| ) | ||||
|  | ||||
| // Option func | ||||
| @@ -26,8 +36,6 @@ type Option func(*Options) | ||||
| type Options struct { | ||||
| 	// Context holds the external options and can be used for server shutdown | ||||
| 	Context context.Context | ||||
| 	// Broker holds the server broker | ||||
| 	Broker broker.Broker | ||||
| 	// Register holds the register | ||||
| 	Register register.Register | ||||
| 	// Tracer holds the tracer | ||||
| @@ -38,12 +46,6 @@ type Options struct { | ||||
| 	Meter meter.Meter | ||||
| 	// Transport holds the transport | ||||
| 	Transport transport.Transport | ||||
|  | ||||
| 	/* | ||||
| 		// Router for requests | ||||
| 		Router Router | ||||
| 	*/ | ||||
|  | ||||
| 	// Listener may be passed if already created | ||||
| 	Listener net.Listener | ||||
| 	// Wait group | ||||
| @@ -68,10 +70,6 @@ type Options struct { | ||||
| 	Advertise string | ||||
| 	// Version holds the server version | ||||
| 	Version string | ||||
| 	// SubWrappers holds the server subscribe wrappers | ||||
| 	SubWrappers []SubscriberWrapper | ||||
| 	// BatchSubWrappers holds the server batch subscribe wrappers | ||||
| 	BatchSubWrappers []BatchSubscriberWrapper | ||||
| 	// HdlrWrappers holds the handler wrappers | ||||
| 	HdlrWrappers []HandlerWrapper | ||||
| 	// RegisterAttempts holds the number of register attempts before error | ||||
| @@ -84,7 +82,7 @@ type Options struct { | ||||
| 	MaxConn int | ||||
| 	// DeregisterAttempts holds the number of deregister attempts before error | ||||
| 	DeregisterAttempts int | ||||
| 	// Hooks may contains SubscriberWrapper, HandlerWrapper or Server func wrapper | ||||
| 	// Hooks may contains HandlerWrapper or Server func wrapper | ||||
| 	Hooks options.Hooks | ||||
| } | ||||
|  | ||||
| @@ -100,7 +98,6 @@ func NewOptions(opts ...Option) Options { | ||||
| 		Logger:           logger.DefaultLogger, | ||||
| 		Meter:            meter.DefaultMeter, | ||||
| 		Tracer:           tracer.DefaultTracer, | ||||
| 		Broker:           broker.DefaultBroker, | ||||
| 		Register:         register.DefaultRegister, | ||||
| 		Transport:        transport.DefaultTransport, | ||||
| 		Address:          DefaultAddress, | ||||
| @@ -173,13 +170,6 @@ func Advertise(a string) Option { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Broker to use for pub/sub | ||||
| func Broker(b broker.Broker) Option { | ||||
| 	return func(o *Options) { | ||||
| 		o.Broker = b | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Codec to use to encode/decode requests for a given content type | ||||
| func Codec(contentType string, c codec.Codec) Option { | ||||
| 	return func(o *Options) { | ||||
| @@ -261,15 +251,6 @@ func TLSConfig(t *tls.Config) Option { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
| // WithRouter sets the request router | ||||
| func WithRouter(r Router) Option { | ||||
| 	return func(o *Options) { | ||||
| 		o.Router = r | ||||
| 	} | ||||
| } | ||||
| */ | ||||
|  | ||||
| // Wait tells the server to wait for requests to finish before exiting | ||||
| // If `wg` is nil, server only wait for completion of rpc handler. | ||||
| // For user need finer grained control, pass a concrete `wg` here, server will | ||||
| @@ -290,20 +271,6 @@ func WrapHandler(w HandlerWrapper) Option { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WrapSubscriber adds a subscriber Wrapper to a list of options passed into the server | ||||
| func WrapSubscriber(w SubscriberWrapper) Option { | ||||
| 	return func(o *Options) { | ||||
| 		o.SubWrappers = append(o.SubWrappers, w) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WrapBatchSubscriber adds a batch subscriber Wrapper to a list of options passed into the server | ||||
| func WrapBatchSubscriber(w BatchSubscriberWrapper) Option { | ||||
| 	return func(o *Options) { | ||||
| 		o.BatchSubWrappers = append(o.BatchSubWrappers, w) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // MaxConn specifies maximum number of max simultaneous connections to server | ||||
| func MaxConn(n int) Option { | ||||
| 	return func(o *Options) { | ||||
| @@ -343,41 +310,6 @@ func NewHandlerOptions(opts ...HandlerOption) HandlerOptions { | ||||
| 	return options | ||||
| } | ||||
|  | ||||
| // SubscriberOption func | ||||
| type SubscriberOption func(*SubscriberOptions) | ||||
|  | ||||
| // SubscriberOptions struct | ||||
| type SubscriberOptions struct { | ||||
| 	// Context holds the external options | ||||
| 	Context context.Context | ||||
| 	// Queue holds the subscription queue | ||||
| 	Queue string | ||||
| 	// AutoAck flag for auto ack messages after processing | ||||
| 	AutoAck bool | ||||
| 	// BodyOnly flag specifies that message without headers | ||||
| 	BodyOnly bool | ||||
| 	// Batch flag specifies that message processed in batches | ||||
| 	Batch bool | ||||
| 	// BatchSize flag specifies max size of batch | ||||
| 	BatchSize int | ||||
| 	// BatchWait flag specifies max wait time for batch filling | ||||
| 	BatchWait time.Duration | ||||
| } | ||||
|  | ||||
| // NewSubscriberOptions create new SubscriberOptions | ||||
| func NewSubscriberOptions(opts ...SubscriberOption) SubscriberOptions { | ||||
| 	options := SubscriberOptions{ | ||||
| 		AutoAck: true, | ||||
| 		Context: context.Background(), | ||||
| 	} | ||||
|  | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| 	} | ||||
|  | ||||
| 	return options | ||||
| } | ||||
|  | ||||
| // EndpointMetadata is a Handler option that allows metadata to be added to | ||||
| // individual endpoints. | ||||
| func EndpointMetadata(name string, md metadata.Metadata) HandlerOption { | ||||
| @@ -385,68 +317,3 @@ func EndpointMetadata(name string, md metadata.Metadata) HandlerOption { | ||||
| 		o.Metadata[name] = metadata.Copy(md) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DisableAutoAck will disable auto acking of messages | ||||
| // after they have been handled. | ||||
| func DisableAutoAck() SubscriberOption { | ||||
| 	return func(o *SubscriberOptions) { | ||||
| 		o.AutoAck = false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscriberQueue sets the shared queue name distributed messages across subscribers | ||||
| func SubscriberQueue(n string) SubscriberOption { | ||||
| 	return func(o *SubscriberOptions) { | ||||
| 		o.Queue = n | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscriberGroup sets the shared group name distributed messages across subscribers | ||||
| func SubscriberGroup(n string) SubscriberOption { | ||||
| 	return func(o *SubscriberOptions) { | ||||
| 		o.Queue = n | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscriberBodyOnly says broker that message contains raw data with absence of micro broker.Message format | ||||
| func SubscriberBodyOnly(b bool) SubscriberOption { | ||||
| 	return func(o *SubscriberOptions) { | ||||
| 		o.BodyOnly = b | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscriberContext set context options to allow broker SubscriberOption passed | ||||
| func SubscriberContext(ctx context.Context) SubscriberOption { | ||||
| 	return func(o *SubscriberOptions) { | ||||
| 		o.Context = ctx | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscriberAck control auto ack processing for handler | ||||
| func SubscriberAck(b bool) SubscriberOption { | ||||
| 	return func(o *SubscriberOptions) { | ||||
| 		o.AutoAck = b | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscriberBatch control batch processing for handler | ||||
| func SubscriberBatch(b bool) SubscriberOption { | ||||
| 	return func(o *SubscriberOptions) { | ||||
| 		o.Batch = b | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscriberBatchSize control batch filling size for handler | ||||
| // Batch filling max waiting time controlled by SubscriberBatchWait | ||||
| func SubscriberBatchSize(n int) SubscriberOption { | ||||
| 	return func(o *SubscriberOptions) { | ||||
| 		o.BatchSize = n | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SubscriberBatchWait control batch filling wait time for handler | ||||
| func SubscriberBatchWait(td time.Duration) SubscriberOption { | ||||
| 	return func(o *SubscriberOptions) { | ||||
| 		o.BatchWait = td | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -4,10 +4,10 @@ import ( | ||||
| 	"net" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| 	"go.unistack.org/micro/v3/util/addr" | ||||
| 	"go.unistack.org/micro/v3/util/backoff" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| 	"go.unistack.org/micro/v4/register" | ||||
| 	"go.unistack.org/micro/v4/util/addr" | ||||
| 	"go.unistack.org/micro/v4/util/backoff" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| @@ -78,7 +78,6 @@ func NewRegisterService(s Server) (*register.Service, error) { | ||||
| 	node.Metadata = metadata.Copy(opts.Metadata) | ||||
|  | ||||
| 	node.Metadata["server"] = s.String() | ||||
| 	node.Metadata["broker"] = opts.Broker.String() | ||||
| 	node.Metadata["register"] = opts.Register.String() | ||||
|  | ||||
| 	return ®ister.Service{ | ||||
|   | ||||
| @@ -1,35 +0,0 @@ | ||||
| package server | ||||
|  | ||||
| import ( | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| ) | ||||
|  | ||||
| type rpcMessage struct { | ||||
| 	payload     interface{} | ||||
| 	codec       codec.Codec | ||||
| 	header      metadata.Metadata | ||||
| 	topic       string | ||||
| 	contentType string | ||||
| 	body        []byte | ||||
| } | ||||
|  | ||||
| func (r *rpcMessage) ContentType() string { | ||||
| 	return r.contentType | ||||
| } | ||||
|  | ||||
| func (r *rpcMessage) Topic() string { | ||||
| 	return r.topic | ||||
| } | ||||
|  | ||||
| func (r *rpcMessage) Body() interface{} { | ||||
| 	return r.payload | ||||
| } | ||||
|  | ||||
| func (r *rpcMessage) Header() metadata.Metadata { | ||||
| 	return r.header | ||||
| } | ||||
|  | ||||
| func (r *rpcMessage) Codec() codec.Codec { | ||||
| 	return r.codec | ||||
| } | ||||
| @@ -1,13 +1,13 @@ | ||||
| // Package server is an interface for a micro server | ||||
| package server // import "go.unistack.org/micro/v3/server" | ||||
| package server // import "go.unistack.org/micro/v4/server" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| 	"go.unistack.org/micro/v4/register" | ||||
| ) | ||||
|  | ||||
| // DefaultServer default server | ||||
| @@ -48,10 +48,6 @@ type Server interface { | ||||
| 	Handle(h Handler) error | ||||
| 	// Create a new handler | ||||
| 	NewHandler(h interface{}, opts ...HandlerOption) Handler | ||||
| 	// Create a new subscriber | ||||
| 	NewSubscriber(topic string, h interface{}, opts ...SubscriberOption) Subscriber | ||||
| 	// Register a subscriber | ||||
| 	Subscribe(s Subscriber) error | ||||
| 	// Start the server | ||||
| 	Start() error | ||||
| 	// Stop the server | ||||
| @@ -60,30 +56,6 @@ type Server interface { | ||||
| 	String() string | ||||
| } | ||||
|  | ||||
| /* | ||||
| // Router handle serving messages | ||||
| type Router interface { | ||||
| 	// ProcessMessage processes a message | ||||
| 	ProcessMessage(ctx context.Context, msg Message) error | ||||
| 	// ServeRequest processes a request to completion | ||||
| 	ServeRequest(ctx context.Context, req Request, rsp Response) error | ||||
| } | ||||
| */ | ||||
|  | ||||
| // Message is an async message interface | ||||
| type Message interface { | ||||
| 	// Topic of the message | ||||
| 	Topic() string | ||||
| 	// The decoded payload value | ||||
| 	Body() interface{} | ||||
| 	// The content type of the payload | ||||
| 	ContentType() string | ||||
| 	// The raw headers of the message | ||||
| 	Header() metadata.Metadata | ||||
| 	// Codec used to decode the message | ||||
| 	Codec() codec.Codec | ||||
| } | ||||
|  | ||||
| // Request is a synchronous request interface | ||||
| type Request interface { | ||||
| 	// Service name requested | ||||
| @@ -150,20 +122,9 @@ type Stream interface { | ||||
| //	func (g *Greeter) Hello(context, request, response) error { | ||||
| //	        return nil | ||||
| //	} | ||||
| // | ||||
| type Handler interface { | ||||
| 	Name() string | ||||
| 	Handler() interface{} | ||||
| 	Endpoints() []*register.Endpoint | ||||
| 	Options() HandlerOptions | ||||
| } | ||||
|  | ||||
| // Subscriber interface represents a subscription to a given topic using | ||||
| // a specific subscriber function or object with endpoints. It mirrors | ||||
| // the handler in its behaviour. | ||||
| type Subscriber interface { | ||||
| 	Topic() string | ||||
| 	Subscriber() interface{} | ||||
| 	Endpoints() []*register.Endpoint | ||||
| 	Options() SubscriberOptions | ||||
| } | ||||
|   | ||||
| @@ -1,440 +0,0 @@ | ||||
| package server | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"runtime/debug" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/broker" | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/errors" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	subSig      = "func(context.Context, interface{}) error" | ||||
| 	batchSubSig = "func([]context.Context, []interface{}) error" | ||||
| ) | ||||
|  | ||||
| // Precompute the reflect type for error. Can't use error directly | ||||
| // because Typeof takes an empty interface value. This is annoying. | ||||
| var typeOfError = reflect.TypeOf((*error)(nil)).Elem() | ||||
|  | ||||
| type handler struct { | ||||
| 	reqType reflect.Type | ||||
| 	ctxType reflect.Type | ||||
| 	method  reflect.Value | ||||
| } | ||||
|  | ||||
| type subscriber struct { | ||||
| 	typ        reflect.Type | ||||
| 	subscriber interface{} | ||||
| 	topic      string | ||||
| 	endpoints  []*register.Endpoint | ||||
| 	handlers   []*handler | ||||
| 	opts       SubscriberOptions | ||||
| 	rcvr       reflect.Value | ||||
| } | ||||
|  | ||||
| // 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() == "" | ||||
| } | ||||
|  | ||||
| // ValidateSubscriber func signature | ||||
| func ValidateSubscriber(sub Subscriber) error { | ||||
| 	typ := reflect.TypeOf(sub.Subscriber()) | ||||
| 	var argType reflect.Type | ||||
| 	switch typ.Kind() { | ||||
| 	case reflect.Func: | ||||
| 		name := "Func" | ||||
| 		switch typ.NumIn() { | ||||
| 		case 2: | ||||
| 			argType = typ.In(1) | ||||
| 			if sub.Options().Batch { | ||||
| 				if argType.Kind() != reflect.Slice { | ||||
| 					return fmt.Errorf("subscriber %v dont have required signature %s", name, batchSubSig) | ||||
| 				} | ||||
| 				if strings.Compare(fmt.Sprintf("%v", argType), "[]interface{}") == 0 { | ||||
| 					return fmt.Errorf("subscriber %v dont have required signaure %s", name, batchSubSig) | ||||
| 				} | ||||
| 			} | ||||
| 		default: | ||||
| 			return fmt.Errorf("subscriber %v takes wrong number of args: %v required signature %s or %s", name, typ.NumIn(), subSig, batchSubSig) | ||||
| 		} | ||||
| 		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 return values: %v require signature %s or %s", | ||||
| 				name, typ.NumOut(), subSig, batchSubSig) | ||||
| 		} | ||||
| 		if returnType := typ.Out(0); returnType != typeOfError { | ||||
| 			return fmt.Errorf("subscriber %v returns %v not error", name, returnType.String()) | ||||
| 		} | ||||
| 	default: | ||||
| 		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 or %s", | ||||
| 					name, method.Name, method.Type.NumIn(), subSig, batchSubSig) | ||||
| 			} | ||||
|  | ||||
| 			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 return values: %v require signature %s or %s", | ||||
| 					name, method.Name, method.Type.NumOut(), subSig, batchSubSig) | ||||
| 			} | ||||
| 			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 newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subscriber { | ||||
| 	var endpoints []*register.Endpoint | ||||
| 	var handlers []*handler | ||||
|  | ||||
| 	options := NewSubscriberOptions(opts...) | ||||
|  | ||||
| 	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) | ||||
| 		ep := ®ister.Endpoint{ | ||||
| 			Name:     "Func", | ||||
| 			Request:  register.ExtractSubValue(typ), | ||||
| 			Metadata: metadata.New(2), | ||||
| 		} | ||||
| 		ep.Metadata.Set("topic", topic) | ||||
| 		ep.Metadata.Set("subscriber", "true") | ||||
| 		endpoints = append(endpoints, ep) | ||||
| 	} 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) | ||||
| 			ep := ®ister.Endpoint{ | ||||
| 				Name:     name + "." + method.Name, | ||||
| 				Request:  register.ExtractSubValue(method.Type), | ||||
| 				Metadata: metadata.New(2), | ||||
| 			} | ||||
| 			ep.Metadata.Set("topic", topic) | ||||
| 			ep.Metadata.Set("subscriber", "true") | ||||
| 			endpoints = append(endpoints, ep) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return &subscriber{ | ||||
| 		rcvr:       reflect.ValueOf(sub), | ||||
| 		typ:        reflect.TypeOf(sub), | ||||
| 		topic:      topic, | ||||
| 		subscriber: sub, | ||||
| 		handlers:   handlers, | ||||
| 		endpoints:  endpoints, | ||||
| 		opts:       options, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| //nolint:gocyclo | ||||
| func (n *noopServer) newBatchSubHandler(sb *subscriber, opts Options) broker.BatchHandler { | ||||
| 	return func(ps broker.Events) (err error) { | ||||
| 		defer func() { | ||||
| 			if r := recover(); r != nil { | ||||
| 				n.RLock() | ||||
| 				config := n.opts | ||||
| 				n.RUnlock() | ||||
| 				if config.Logger.V(logger.ErrorLevel) { | ||||
| 					config.Logger.Error(n.opts.Context, "panic recovered: ", r) | ||||
| 					config.Logger.Error(n.opts.Context, string(debug.Stack())) | ||||
| 				} | ||||
| 				err = errors.InternalServerError(n.opts.Name+".subscriber", "panic recovered: %v", r) | ||||
| 			} | ||||
| 		}() | ||||
|  | ||||
| 		msgs := make([]Message, 0, len(ps)) | ||||
| 		ctxs := make([]context.Context, 0, len(ps)) | ||||
| 		for _, p := range ps { | ||||
| 			msg := p.Message() | ||||
| 			// if we don't have headers, create empty map | ||||
| 			if msg.Header == nil { | ||||
| 				msg.Header = metadata.New(2) | ||||
| 			} | ||||
|  | ||||
| 			ct, _ := msg.Header.Get(metadata.HeaderContentType) | ||||
| 			if len(ct) == 0 { | ||||
| 				msg.Header.Set(metadata.HeaderContentType, defaultContentType) | ||||
| 				ct = defaultContentType | ||||
| 			} | ||||
| 			hdr := metadata.Copy(msg.Header) | ||||
| 			topic, _ := msg.Header.Get(metadata.HeaderTopic) | ||||
| 			ctxs = append(ctxs, metadata.NewIncomingContext(sb.opts.Context, hdr)) | ||||
| 			msgs = append(msgs, &rpcMessage{ | ||||
| 				topic:       topic, | ||||
| 				contentType: ct, | ||||
| 				header:      msg.Header, | ||||
| 				body:        msg.Body, | ||||
| 			}) | ||||
| 		} | ||||
| 		results := make(chan error, len(sb.handlers)) | ||||
|  | ||||
| 		for i := 0; i < len(sb.handlers); i++ { | ||||
| 			handler := sb.handlers[i] | ||||
|  | ||||
| 			var req reflect.Value | ||||
|  | ||||
| 			switch handler.reqType.Kind() { | ||||
| 			case reflect.Ptr: | ||||
| 				req = reflect.New(handler.reqType.Elem()) | ||||
| 			default: | ||||
| 				req = reflect.New(handler.reqType.Elem()).Elem() | ||||
| 			} | ||||
|  | ||||
| 			reqType := handler.reqType | ||||
| 			var cf codec.Codec | ||||
| 			for _, msg := range msgs { | ||||
| 				cf, err = n.newCodec(msg.ContentType()) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				rb := reflect.New(req.Type().Elem()) | ||||
| 				if err = cf.ReadBody(bytes.NewReader(msg.(*rpcMessage).body), rb.Interface()); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				msg.(*rpcMessage).codec = cf | ||||
| 				msg.(*rpcMessage).payload = rb.Interface() | ||||
| 			} | ||||
|  | ||||
| 			fn := func(ctxs []context.Context, ms []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(ctxs)) | ||||
| 				} | ||||
| 				payloads := reflect.MakeSlice(reqType, 0, len(ms)) | ||||
| 				for _, m := range ms { | ||||
| 					payloads = reflect.Append(payloads, reflect.ValueOf(m.Body())) | ||||
| 				} | ||||
| 				vals = append(vals, payloads) | ||||
|  | ||||
| 				returnValues := handler.method.Call(vals) | ||||
| 				if rerr := returnValues[0].Interface(); rerr != nil { | ||||
| 					return rerr.(error) | ||||
| 				} | ||||
| 				return nil | ||||
| 			} | ||||
|  | ||||
| 			for i := len(opts.BatchSubWrappers); i > 0; i-- { | ||||
| 				fn = opts.BatchSubWrappers[i-1](fn) | ||||
| 			} | ||||
|  | ||||
| 			if n.wg != nil { | ||||
| 				n.wg.Add(1) | ||||
| 			} | ||||
| 			go func() { | ||||
| 				if n.wg != nil { | ||||
| 					defer n.wg.Done() | ||||
| 				} | ||||
| 				results <- fn(ctxs, msgs) | ||||
| 			}() | ||||
| 		} | ||||
|  | ||||
| 		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 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| //nolint:gocyclo | ||||
| func (n *noopServer) newSubHandler(sb *subscriber, opts Options) broker.Handler { | ||||
| 	return func(p broker.Event) (err error) { | ||||
| 		defer func() { | ||||
| 			if r := recover(); r != nil { | ||||
| 				n.RLock() | ||||
| 				config := n.opts | ||||
| 				n.RUnlock() | ||||
| 				if config.Logger.V(logger.ErrorLevel) { | ||||
| 					config.Logger.Error(n.opts.Context, "panic recovered: ", r) | ||||
| 					config.Logger.Error(n.opts.Context, string(debug.Stack())) | ||||
| 				} | ||||
| 				err = errors.InternalServerError(n.opts.Name+".subscriber", "panic recovered: %v", r) | ||||
| 			} | ||||
| 		}() | ||||
|  | ||||
| 		msg := p.Message() | ||||
| 		// if we don't have headers, create empty map | ||||
| 		if msg.Header == nil { | ||||
| 			msg.Header = metadata.New(2) | ||||
| 		} | ||||
|  | ||||
| 		ct := msg.Header["Content-Type"] | ||||
| 		if len(ct) == 0 { | ||||
| 			msg.Header.Set(metadata.HeaderContentType, defaultContentType) | ||||
| 			ct = defaultContentType | ||||
| 		} | ||||
| 		cf, err := n.newCodec(ct) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		hdr := metadata.New(len(msg.Header)) | ||||
| 		for k, v := range msg.Header { | ||||
| 			if k == "Content-Type" { | ||||
| 				continue | ||||
| 			} | ||||
| 			hdr.Set(k, v) | ||||
| 		} | ||||
|  | ||||
| 		ctx := metadata.NewIncomingContext(sb.opts.Context, 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.ReadBody(bytes.NewBuffer(msg.Body), req.Interface()); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			fn := func(ctx context.Context, msg 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.Body())) | ||||
|  | ||||
| 				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 n.wg != nil { | ||||
| 				n.wg.Add(1) | ||||
| 			} | ||||
| 			go func() { | ||||
| 				if n.wg != nil { | ||||
| 					defer n.wg.Done() | ||||
| 				} | ||||
| 				cerr := fn(ctx, &rpcMessage{ | ||||
| 					topic:       sb.topic, | ||||
| 					contentType: ct, | ||||
| 					payload:     req.Interface(), | ||||
| 					header:      msg.Header, | ||||
| 				}) | ||||
| 				results <- cerr | ||||
| 			}() | ||||
| 		} | ||||
| 		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() []*register.Endpoint { | ||||
| 	return s.endpoints | ||||
| } | ||||
|  | ||||
| func (s *subscriber) Options() SubscriberOptions { | ||||
| 	return s.opts | ||||
| } | ||||
| @@ -9,25 +9,9 @@ import ( | ||||
| // request and response types. | ||||
| type HandlerFunc func(ctx context.Context, req Request, rsp interface{}) error | ||||
|  | ||||
| // SubscriberFunc represents a single method of a subscriber. It's used primarily | ||||
| // for the wrappers. What's handed to the actual method is the concrete | ||||
| // publication message. | ||||
| type SubscriberFunc func(ctx context.Context, msg Message) error | ||||
|  | ||||
| // BatchSubscriberFunc represents a single method of a subscriber. It's used primarily | ||||
| // for the wrappers. What's handed to the actual method is the concrete | ||||
| // publication message. This func used by batch subscribers | ||||
| type BatchSubscriberFunc func(ctxs []context.Context, msgs []Message) error | ||||
|  | ||||
| // HandlerWrapper wraps the HandlerFunc and returns the equivalent | ||||
| type HandlerWrapper func(HandlerFunc) HandlerFunc | ||||
|  | ||||
| // SubscriberWrapper wraps the SubscriberFunc and returns the equivalent | ||||
| type SubscriberWrapper func(SubscriberFunc) SubscriberFunc | ||||
|  | ||||
| // BatchSubscriberWrapper wraps the SubscriberFunc and returns the equivalent | ||||
| type BatchSubscriberWrapper func(BatchSubscriberFunc) BatchSubscriberFunc | ||||
|  | ||||
| // StreamWrapper wraps a Stream interface and returns the equivalent. | ||||
| // Because streams exist for the lifetime of a method invocation this | ||||
| // is a convenient way to wrap a Stream as its in use for trace, monitoring, | ||||
|   | ||||
							
								
								
									
										28
									
								
								service.go
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								service.go
									
									
									
									
									
								
							| @@ -1,20 +1,20 @@ | ||||
| // Package micro is a pluggable framework for microservices | ||||
| package micro // import "go.unistack.org/micro/v3" | ||||
| package micro // import "go.unistack.org/micro/v4" | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"sync" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/broker" | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/config" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| 	"go.unistack.org/micro/v3/router" | ||||
| 	"go.unistack.org/micro/v3/server" | ||||
| 	"go.unistack.org/micro/v3/store" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/broker" | ||||
| 	"go.unistack.org/micro/v4/client" | ||||
| 	"go.unistack.org/micro/v4/config" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/register" | ||||
| 	"go.unistack.org/micro/v4/router" | ||||
| 	"go.unistack.org/micro/v4/server" | ||||
| 	"go.unistack.org/micro/v4/store" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| // Service is an interface that wraps the lower level components. | ||||
| @@ -66,11 +66,6 @@ func RegisterHandler(s server.Server, h interface{}, opts ...server.HandlerOptio | ||||
| 	return s.Handle(s.NewHandler(h, opts...)) | ||||
| } | ||||
|  | ||||
| // RegisterSubscriber is syntactic sugar for registering a subscriber | ||||
| func RegisterSubscriber(topic string, s server.Server, h interface{}, opts ...server.SubscriberOption) error { | ||||
| 	return s.Subscribe(s.NewSubscriber(topic, h, opts...)) | ||||
| } | ||||
|  | ||||
| type service struct { | ||||
| 	sync.RWMutex | ||||
| 	opts Options | ||||
| @@ -88,6 +83,7 @@ func (s *service) Name() string { | ||||
| // Init initialises options. Additionally it calls cmd.Init | ||||
| // which parses command line flags. cmd.Init is only called | ||||
| // on first Init. | ||||
| // | ||||
| //nolint:gocyclo | ||||
| func (s *service) Init(opts ...Option) error { | ||||
| 	var err error | ||||
|   | ||||
| @@ -1,20 +1,19 @@ | ||||
| package micro | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/broker" | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/config" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/register" | ||||
| 	"go.unistack.org/micro/v3/router" | ||||
| 	"go.unistack.org/micro/v3/server" | ||||
| 	"go.unistack.org/micro/v3/store" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/broker" | ||||
| 	"go.unistack.org/micro/v4/client" | ||||
| 	"go.unistack.org/micro/v4/config" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/register" | ||||
| 	"go.unistack.org/micro/v4/router" | ||||
| 	"go.unistack.org/micro/v4/server" | ||||
| 	"go.unistack.org/micro/v4/store" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| type testItem struct { | ||||
| @@ -65,41 +64,6 @@ func TestRegisterHandler(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestRegisterSubscriber(t *testing.T) { | ||||
| 	type args struct { | ||||
| 		topic string | ||||
| 		s     server.Server | ||||
| 		h     interface{} | ||||
| 		opts  []server.SubscriberOption | ||||
| 	} | ||||
| 	h := func(_ context.Context, _ interface{}) error { | ||||
| 		return nil | ||||
| 	} | ||||
| 	tests := []struct { | ||||
| 		name    string | ||||
| 		args    args | ||||
| 		wantErr bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "RegisterSubscriber", | ||||
| 			args: args{ | ||||
| 				topic: "test", | ||||
| 				s:     server.DefaultServer, | ||||
| 				h:     h, | ||||
| 				opts:  nil, | ||||
| 			}, | ||||
| 			wantErr: false, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 			if err := RegisterSubscriber(tt.args.topic, tt.args.s, tt.args.h, tt.args.opts...); (err != nil) != tt.wantErr { | ||||
| 				t.Errorf("RegisterSubscriber() error = %v, wantErr %v", err, tt.wantErr) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestNewService(t *testing.T) { | ||||
| 	type args struct { | ||||
| 		opts []Option | ||||
| @@ -222,7 +186,6 @@ func Test_service_Options(t *testing.T) { | ||||
| } | ||||
|  | ||||
| func Test_service_Broker(t *testing.T) { | ||||
| 	b := broker.NewBroker() | ||||
| 	type fields struct { | ||||
| 		opts Options | ||||
| 	} | ||||
| @@ -238,12 +201,12 @@ func Test_service_Broker(t *testing.T) { | ||||
| 		{ | ||||
| 			name: "service.Broker", | ||||
| 			fields: fields{ | ||||
| 				opts: Options{Brokers: []broker.Broker{b}}, | ||||
| 				opts: Options{Brokers: []broker.Broker{broker.DefaultBroker}}, | ||||
| 			}, | ||||
| 			args: args{ | ||||
| 				names: []string{"noop"}, | ||||
| 			}, | ||||
| 			want: b, | ||||
| 			want: broker.DefaultBroker, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/store" | ||||
| 	"go.unistack.org/micro/v4/store" | ||||
| ) | ||||
|  | ||||
| func TestMemoryReInit(t *testing.T) { | ||||
|   | ||||
| @@ -5,11 +5,11 @@ import ( | ||||
| 	"crypto/tls" | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/codec" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| // Options contains configuration for the Store | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package store is an interface for distributed data storage. | ||||
| package store // import "go.unistack.org/micro/v3/store" | ||||
| package store // import "go.unistack.org/micro/v4/store" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|   | ||||
| @@ -3,9 +3,9 @@ package sync | ||||
| import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v3/meter" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| 	"go.unistack.org/micro/v4/meter" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| // Options holds the sync options | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package sync is an interface for distributed synchronization | ||||
| package sync // import "go.unistack.org/micro/v3/sync" | ||||
| package sync // import "go.unistack.org/micro/v4/sync" | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
|   | ||||
| @@ -3,7 +3,7 @@ package tracer | ||||
| import ( | ||||
| 	"context" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/logger" | ||||
| 	"go.unistack.org/micro/v4/logger" | ||||
| ) | ||||
|  | ||||
| type SpanStatus int | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| // Package tracer provides an interface for distributed tracing | ||||
| package tracer // import "go.unistack.org/micro/v3/tracer" | ||||
| package tracer // import "go.unistack.org/micro/v4/tracer" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| // Package wrapper provides wrapper for Tracer | ||||
| package wrapper // import "go.unistack.org/micro/v3/tracer/wrapper" | ||||
| package wrapper // import "go.unistack.org/micro/v4/tracer/wrapper" | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/server" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"go.unistack.org/micro/v4/client" | ||||
| 	"go.unistack.org/micro/v4/metadata" | ||||
| 	"go.unistack.org/micro/v4/server" | ||||
| 	"go.unistack.org/micro/v4/tracer" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| package addr // import "go.unistack.org/micro/v3/util/addr" | ||||
| package addr // import "go.unistack.org/micro/v4/util/addr" | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| @@ -58,6 +58,7 @@ func IsLocal(addr string) bool { | ||||
| } | ||||
|  | ||||
| // Extract returns a real ip | ||||
| // | ||||
| //nolint:gocyclo | ||||
| func Extract(addr string) (string, error) { | ||||
| 	// if addr specified then its returned | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user