go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/protocol/sub/sub.go (about) 1 // Copyright 2019 The Mangos Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use file except in compliance with the License. 5 // You may obtain a copy of the license at 6 // 7 // http://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 // Package sub implements the SUB protocol. This protocol receives messages 16 // from publishers (PUB peers). The messages are filtered based on 17 // subscription, such that only subscribed messages (see OptionSubscribe) are 18 // received. 19 // 20 // Note that in order to receive any messages, at least one subscription must 21 // be present. If no subscription is present (the default state), receive 22 // operations will block forever. 23 package sub 24 25 import ( 26 "bytes" 27 "sync" 28 "time" 29 30 "go.nanomsg.org/mangos/v3/protocol" 31 ) 32 33 // Protocol identity information. 34 const ( 35 Self = protocol.ProtoSub 36 Peer = protocol.ProtoPub 37 SelfName = "sub" 38 PeerName = "pub" 39 ) 40 41 type socket struct { 42 master *context 43 ctxs map[*context]struct{} 44 closed bool 45 sync.Mutex 46 } 47 48 type pipe struct { 49 s *socket 50 p protocol.Pipe 51 } 52 53 type context struct { 54 recvQLen int 55 recvQ chan *protocol.Message 56 closeQ chan struct{} 57 sizeQ chan struct{} 58 recvExpire time.Duration 59 closed bool 60 subs [][]byte 61 s *socket 62 } 63 64 const defaultQLen = 128 65 66 func (*context) SendMsg(*protocol.Message) error { 67 return protocol.ErrProtoOp 68 } 69 70 func (c *context) RecvMsg() (*protocol.Message, error) { 71 72 s := c.s 73 var timeQ <-chan time.Time 74 s.Lock() 75 recvQ := c.recvQ 76 sizeQ := c.sizeQ 77 closeQ := c.closeQ 78 if c.recvExpire > 0 { 79 timeQ = time.After(c.recvExpire) 80 } 81 s.Unlock() 82 83 for { 84 select { 85 case <-timeQ: 86 return nil, protocol.ErrRecvTimeout 87 case <-closeQ: 88 return nil, protocol.ErrClosed 89 case <-sizeQ: 90 s.Lock() 91 sizeQ = c.sizeQ 92 recvQ = c.recvQ 93 s.Unlock() 94 continue 95 case m := <-recvQ: 96 m = m.MakeUnique() 97 return m, nil 98 } 99 } 100 } 101 102 func (c *context) Close() error { 103 s := c.s 104 s.Lock() 105 if c.closed { 106 s.Unlock() 107 return protocol.ErrClosed 108 } 109 c.closed = true 110 delete(s.ctxs, c) 111 s.Unlock() 112 close(c.closeQ) 113 return nil 114 } 115 116 func (*socket) SendMsg(*protocol.Message) error { 117 return protocol.ErrProtoOp 118 } 119 120 func (p *pipe) receiver() { 121 s := p.s 122 for { 123 m := p.p.RecvMsg() 124 if m == nil { 125 break 126 } 127 s.Lock() 128 for c := range s.ctxs { 129 if c.matches(m) { 130 // Matched, send it up. Best effort. 131 // As we are passing this to the user, 132 // we need to ensure that the message 133 // may be modified. 134 m.Clone() 135 select { 136 case c.recvQ <- m: 137 default: 138 select { 139 case m2 := <-c.recvQ: 140 m2.Free() 141 default: 142 } 143 // We have made room, and as we are 144 // holding the lock, we are guaranteed 145 // to be able to enqueue another 146 // message. (No other pipe can 147 // get in right now.) 148 // NB: If we ever do work to break 149 // up the locking, we will need to 150 // revisit this. 151 c.recvQ <- m 152 } 153 } 154 } 155 s.Unlock() 156 m.Free() 157 } 158 159 p.close() 160 } 161 162 func (s *socket) AddPipe(pp protocol.Pipe) error { 163 p := &pipe{ 164 p: pp, 165 s: s, 166 } 167 s.Lock() 168 defer s.Unlock() 169 if s.closed { 170 return protocol.ErrClosed 171 } 172 go p.receiver() 173 return nil 174 } 175 176 func (s *socket) RemovePipe(protocol.Pipe) { 177 } 178 179 func (s *socket) Close() error { 180 s.Lock() 181 if s.closed { 182 s.Unlock() 183 return protocol.ErrClosed 184 } 185 ctxs := make([]*context, 0, len(s.ctxs)) 186 for c := range s.ctxs { 187 ctxs = append(ctxs, c) 188 } 189 s.closed = true 190 s.Unlock() 191 for _, c := range ctxs { 192 _ = c.Close() 193 } 194 return nil 195 } 196 197 func (p *pipe) close() { 198 _ = p.p.Close() 199 } 200 201 func (c *context) matches(m *protocol.Message) bool { 202 for _, sub := range c.subs { 203 if bytes.HasPrefix(m.Body, sub) { 204 return true 205 } 206 } 207 return false 208 209 } 210 211 func (c *context) subscribe(topic []byte) error { 212 for _, sub := range c.subs { 213 if bytes.Equal(sub, topic) { 214 // Already present 215 return nil 216 } 217 } 218 // We need a full data copy of our own. 219 topic = append(make([]byte, 0, len(topic)), topic...) 220 c.subs = append(c.subs, topic) 221 return nil 222 } 223 224 func (c *context) unsubscribe(topic []byte) error { 225 for i, sub := range c.subs { 226 if !bytes.Equal(sub, topic) { 227 continue 228 } 229 c.subs = append(c.subs[:i], c.subs[i+1:]...) 230 231 // Because we have changed the subscription, 232 // we may have messages in the channel that 233 // we don't want any more. Lets prune those. 234 recvQ := make(chan *protocol.Message, c.recvQLen) 235 sizeQ := make(chan struct{}) 236 recvQ, c.recvQ = c.recvQ, recvQ 237 sizeQ, c.sizeQ = c.sizeQ, sizeQ 238 close(sizeQ) 239 for { 240 select { 241 case m := <-recvQ: 242 if !c.matches(m) { 243 m.Free() 244 continue 245 } 246 // We're holding the lock, so nothing else 247 // can contend for this (pipes must be 248 // waiting) -- so this is guaranteed not to 249 // block. 250 c.recvQ <- m 251 default: 252 return nil 253 } 254 } 255 } 256 // Subscription not present 257 return protocol.ErrBadValue 258 } 259 260 func (c *context) SetOption(name string, value interface{}) error { 261 s := c.s 262 263 var fn func([]byte) error 264 265 switch name { 266 case protocol.OptionReadQLen: 267 if v, ok := value.(int); ok { 268 recvQ := make(chan *protocol.Message, v) 269 sizeQ := make(chan struct{}) 270 c.s.Lock() 271 c.recvQ = recvQ 272 sizeQ, c.sizeQ = c.sizeQ, sizeQ 273 c.recvQ = recvQ 274 c.recvQLen = v 275 close(sizeQ) 276 c.s.Unlock() 277 return nil 278 } 279 return protocol.ErrBadValue 280 281 case protocol.OptionRecvDeadline: 282 if v, ok := value.(time.Duration); ok { 283 c.s.Lock() 284 c.recvExpire = v 285 c.s.Unlock() 286 return nil 287 } 288 return protocol.ErrBadValue 289 290 case protocol.OptionSubscribe: 291 fn = c.subscribe 292 case protocol.OptionUnsubscribe: 293 fn = c.unsubscribe 294 default: 295 return protocol.ErrBadOption 296 } 297 298 var vb []byte 299 300 switch v := value.(type) { 301 case []byte: 302 vb = v 303 case string: 304 vb = []byte(v) 305 default: 306 return protocol.ErrBadValue 307 } 308 309 s.Lock() 310 defer s.Unlock() 311 312 return fn(vb) 313 } 314 315 func (c *context) GetOption(name string) (interface{}, error) { 316 switch name { 317 case protocol.OptionReadQLen: 318 c.s.Lock() 319 v := c.recvQLen 320 c.s.Unlock() 321 return v, nil 322 case protocol.OptionRecvDeadline: 323 c.s.Lock() 324 v := c.recvExpire 325 c.s.Unlock() 326 return v, nil 327 } 328 return nil, protocol.ErrBadOption 329 } 330 331 func (s *socket) RecvMsg() (*protocol.Message, error) { 332 return s.master.RecvMsg() 333 } 334 335 func (s *socket) OpenContext() (protocol.Context, error) { 336 s.Lock() 337 defer s.Unlock() 338 if s.closed { 339 return nil, protocol.ErrClosed 340 } 341 c := &context{ 342 s: s, 343 closeQ: make(chan struct{}), 344 sizeQ: make(chan struct{}), 345 recvQ: make(chan *protocol.Message, s.master.recvQLen), 346 recvQLen: s.master.recvQLen, 347 recvExpire: s.master.recvExpire, 348 subs: [][]byte{}, 349 } 350 s.ctxs[c] = struct{}{} 351 return c, nil 352 } 353 354 func (s *socket) GetOption(name string) (interface{}, error) { 355 switch name { 356 case protocol.OptionRaw: 357 return false, nil 358 default: 359 return s.master.GetOption(name) 360 } 361 } 362 363 func (s *socket) SetOption(name string, val interface{}) error { 364 return s.master.SetOption(name, val) 365 } 366 367 func (s *socket) Info() protocol.Info { 368 return protocol.Info{ 369 Self: Self, 370 Peer: Peer, 371 SelfName: SelfName, 372 PeerName: PeerName, 373 } 374 } 375 376 // NewProtocol returns a new protocol implementation. 377 func NewProtocol() protocol.Protocol { 378 s := &socket{ 379 ctxs: make(map[*context]struct{}), 380 } 381 s.master = &context{ 382 s: s, 383 recvQ: make(chan *protocol.Message, defaultQLen), 384 closeQ: make(chan struct{}), 385 sizeQ: make(chan struct{}), 386 recvQLen: defaultQLen, 387 } 388 s.ctxs[s.master] = struct{}{} 389 return s 390 } 391 392 // NewSocket allocates a new Socket using the SUB protocol. 393 func NewSocket() (protocol.Socket, error) { 394 return protocol.MakeSocket(NewProtocol()), nil 395 }