gitee.com/sasukebo/go-micro/v4@v4.7.1/broker/memory.go (about)

     1  // Package memory provides a memory broker
     2  package broker
     3  
     4  import (
     5  	"context"
     6  	"errors"
     7  	"math/rand"
     8  	"sync"
     9  	"time"
    10  
    11  	"gitee.com/sasukebo/go-micro/v4/logger"
    12  	maddr "gitee.com/sasukebo/go-micro/v4/util/addr"
    13  	mnet "gitee.com/sasukebo/go-micro/v4/util/net"
    14  	"github.com/google/uuid"
    15  )
    16  
    17  type memoryBroker struct {
    18  	opts Options
    19  
    20  	addr string
    21  	sync.RWMutex
    22  	connected   bool
    23  	Subscribers map[string][]*memorySubscriber
    24  }
    25  
    26  type memoryEvent struct {
    27  	opts    Options
    28  	topic   string
    29  	err     error
    30  	message interface{}
    31  }
    32  
    33  type memorySubscriber struct {
    34  	id      string
    35  	topic   string
    36  	exit    chan bool
    37  	handler Handler
    38  	opts    SubscribeOptions
    39  }
    40  
    41  func (m *memoryBroker) Options() Options {
    42  	return m.opts
    43  }
    44  
    45  func (m *memoryBroker) Address() string {
    46  	return m.addr
    47  }
    48  
    49  func (m *memoryBroker) Connect() error {
    50  	m.Lock()
    51  	defer m.Unlock()
    52  
    53  	if m.connected {
    54  		return nil
    55  	}
    56  
    57  	// use 127.0.0.1 to avoid scan of all network interfaces
    58  	addr, err := maddr.Extract("127.0.0.1")
    59  	if err != nil {
    60  		return err
    61  	}
    62  	i := rand.Intn(20000)
    63  	// set addr with port
    64  	addr = mnet.HostPort(addr, 10000+i)
    65  
    66  	m.addr = addr
    67  	m.connected = true
    68  
    69  	return nil
    70  }
    71  
    72  func (m *memoryBroker) Disconnect() error {
    73  	m.Lock()
    74  	defer m.Unlock()
    75  
    76  	if !m.connected {
    77  		return nil
    78  	}
    79  
    80  	m.connected = false
    81  
    82  	return nil
    83  }
    84  
    85  func (m *memoryBroker) Init(opts ...Option) error {
    86  	for _, o := range opts {
    87  		o(&m.opts)
    88  	}
    89  	return nil
    90  }
    91  
    92  func (m *memoryBroker) Publish(topic string, msg *Message, opts ...PublishOption) error {
    93  	m.RLock()
    94  	if !m.connected {
    95  		m.RUnlock()
    96  		return errors.New("not connected")
    97  	}
    98  
    99  	subs, ok := m.Subscribers[topic]
   100  	m.RUnlock()
   101  	if !ok {
   102  		return nil
   103  	}
   104  
   105  	var v interface{}
   106  	if m.opts.Codec != nil {
   107  		buf, err := m.opts.Codec.Marshal(msg)
   108  		if err != nil {
   109  			return err
   110  		}
   111  		v = buf
   112  	} else {
   113  		v = msg
   114  	}
   115  
   116  	p := &memoryEvent{
   117  		topic:   topic,
   118  		message: v,
   119  		opts:    m.opts,
   120  	}
   121  
   122  	for _, sub := range subs {
   123  		if err := sub.handler(p); err != nil {
   124  			p.err = err
   125  			if eh := m.opts.ErrorHandler; eh != nil {
   126  				eh(p)
   127  				continue
   128  			}
   129  			return err
   130  		}
   131  	}
   132  
   133  	return nil
   134  }
   135  
   136  func (m *memoryBroker) Subscribe(topic string, handler Handler, opts ...SubscribeOption) (Subscriber, error) {
   137  	m.RLock()
   138  	if !m.connected {
   139  		m.RUnlock()
   140  		return nil, errors.New("not connected")
   141  	}
   142  	m.RUnlock()
   143  
   144  	var options SubscribeOptions
   145  	for _, o := range opts {
   146  		o(&options)
   147  	}
   148  
   149  	sub := &memorySubscriber{
   150  		exit:    make(chan bool, 1),
   151  		id:      uuid.New().String(),
   152  		topic:   topic,
   153  		handler: handler,
   154  		opts:    options,
   155  	}
   156  
   157  	m.Lock()
   158  	m.Subscribers[topic] = append(m.Subscribers[topic], sub)
   159  	m.Unlock()
   160  
   161  	go func() {
   162  		<-sub.exit
   163  		m.Lock()
   164  		var newSubscribers []*memorySubscriber
   165  		for _, sb := range m.Subscribers[topic] {
   166  			if sb.id == sub.id {
   167  				continue
   168  			}
   169  			newSubscribers = append(newSubscribers, sb)
   170  		}
   171  		m.Subscribers[topic] = newSubscribers
   172  		m.Unlock()
   173  	}()
   174  
   175  	return sub, nil
   176  }
   177  
   178  func (m *memoryBroker) String() string {
   179  	return "memory"
   180  }
   181  
   182  func (m *memoryEvent) Topic() string {
   183  	return m.topic
   184  }
   185  
   186  func (m *memoryEvent) Message() *Message {
   187  	switch v := m.message.(type) {
   188  	case *Message:
   189  		return v
   190  	case []byte:
   191  		msg := &Message{}
   192  		if err := m.opts.Codec.Unmarshal(v, msg); err != nil {
   193  			if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
   194  				logger.Errorf("[memory]: failed to unmarshal: %v\n", err)
   195  			}
   196  			return nil
   197  		}
   198  		return msg
   199  	}
   200  
   201  	return nil
   202  }
   203  
   204  func (m *memoryEvent) Ack() error {
   205  	return nil
   206  }
   207  
   208  func (m *memoryEvent) Error() error {
   209  	return m.err
   210  }
   211  
   212  func (m *memorySubscriber) Options() SubscribeOptions {
   213  	return m.opts
   214  }
   215  
   216  func (m *memorySubscriber) Topic() string {
   217  	return m.topic
   218  }
   219  
   220  func (m *memorySubscriber) Unsubscribe() error {
   221  	m.exit <- true
   222  	return nil
   223  }
   224  
   225  func NewMemoryBroker(opts ...Option) Broker {
   226  	options := Options{
   227  		Context: context.Background(),
   228  	}
   229  
   230  	rand.Seed(time.Now().UnixNano())
   231  	for _, o := range opts {
   232  		o(&options)
   233  	}
   234  
   235  	return &memoryBroker{
   236  		opts:        options,
   237  		Subscribers: make(map[string][]*memorySubscriber),
   238  	}
   239  }