github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/broker/memory/memory.go (about) 1 // Copyright 2020 Asim Aslam 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // Original source: github.com/micro/go-micro/v3/broker/memory/memory.go 16 17 // Package memory provides a memory broker 18 package memory 19 20 import ( 21 "context" 22 "errors" 23 "math/rand" 24 "sync" 25 "time" 26 27 "github.com/google/uuid" 28 "github.com/tickoalcantara12/micro/v3/service/broker" 29 maddr "github.com/tickoalcantara12/micro/v3/util/addr" 30 mnet "github.com/tickoalcantara12/micro/v3/util/net" 31 ) 32 33 type memoryBroker struct { 34 opts broker.Options 35 36 addr string 37 sync.RWMutex 38 connected bool 39 Subscribers map[string][]*memorySubscriber 40 } 41 42 type memorySubscriber struct { 43 id string 44 topic string 45 exit chan bool 46 handler broker.Handler 47 opts broker.SubscribeOptions 48 } 49 50 func (m *memoryBroker) Options() broker.Options { 51 return m.opts 52 } 53 54 func (m *memoryBroker) Address() string { 55 return m.addr 56 } 57 58 func (m *memoryBroker) Connect() error { 59 m.Lock() 60 defer m.Unlock() 61 62 if m.connected { 63 return nil 64 } 65 66 // use 127.0.0.1 to avoid scan of all network interfaces 67 addr, err := maddr.Extract("127.0.0.1") 68 if err != nil { 69 return err 70 } 71 i := rand.Intn(20000) 72 // set addr with port 73 addr = mnet.HostPort(addr, 10000+i) 74 75 m.addr = addr 76 m.connected = true 77 78 return nil 79 } 80 81 func (m *memoryBroker) Disconnect() error { 82 m.Lock() 83 defer m.Unlock() 84 85 if !m.connected { 86 return nil 87 } 88 89 m.connected = false 90 91 return nil 92 } 93 94 func (m *memoryBroker) Init(opts ...broker.Option) error { 95 for _, o := range opts { 96 o(&m.opts) 97 } 98 return nil 99 } 100 101 func (m *memoryBroker) Publish(topic string, msg *broker.Message, opts ...broker.PublishOption) error { 102 m.RLock() 103 if !m.connected { 104 m.RUnlock() 105 return errors.New("not connected") 106 } 107 108 subs, ok := m.Subscribers[topic] 109 m.RUnlock() 110 if !ok { 111 return nil 112 } 113 114 for _, sub := range subs { 115 if err := sub.handler(msg); err != nil { 116 if eh := sub.opts.ErrorHandler; eh != nil { 117 eh(msg, err) 118 } 119 continue 120 } 121 } 122 123 return nil 124 } 125 126 func (m *memoryBroker) Subscribe(topic string, handler broker.Handler, opts ...broker.SubscribeOption) (broker.Subscriber, error) { 127 m.RLock() 128 if !m.connected { 129 m.RUnlock() 130 return nil, errors.New("not connected") 131 } 132 m.RUnlock() 133 134 var options broker.SubscribeOptions 135 for _, o := range opts { 136 o(&options) 137 } 138 139 sub := &memorySubscriber{ 140 exit: make(chan bool, 1), 141 id: uuid.New().String(), 142 topic: topic, 143 handler: handler, 144 opts: options, 145 } 146 147 m.Lock() 148 m.Subscribers[topic] = append(m.Subscribers[topic], sub) 149 m.Unlock() 150 151 go func() { 152 <-sub.exit 153 m.Lock() 154 var newSubscribers []*memorySubscriber 155 for _, sb := range m.Subscribers[topic] { 156 if sb.id == sub.id { 157 continue 158 } 159 newSubscribers = append(newSubscribers, sb) 160 } 161 m.Subscribers[topic] = newSubscribers 162 m.Unlock() 163 }() 164 165 return sub, nil 166 } 167 168 func (m *memoryBroker) String() string { 169 return "memory" 170 } 171 172 func (m *memorySubscriber) Options() broker.SubscribeOptions { 173 return m.opts 174 } 175 176 func (m *memorySubscriber) Topic() string { 177 return m.topic 178 } 179 180 func (m *memorySubscriber) Unsubscribe() error { 181 m.exit <- true 182 return nil 183 } 184 185 func NewBroker(opts ...broker.Option) broker.Broker { 186 options := broker.Options{ 187 Context: context.Background(), 188 } 189 190 rand.Seed(time.Now().UnixNano()) 191 for _, o := range opts { 192 o(&options) 193 } 194 195 return &memoryBroker{ 196 opts: options, 197 Subscribers: make(map[string][]*memorySubscriber), 198 } 199 }