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 }