github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/broker/memory/memory.go (about)

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