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