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 }