go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/protocol/xsub/xsub.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 xsub implements the raw SUB protocol. This protocol simply 16 // passes through all messages received, and does not filter them. 17 package xsub 18 19 import ( 20 "sync" 21 "time" 22 23 "go.nanomsg.org/mangos/v3/protocol" 24 ) 25 26 // Protocol identity information. 27 const ( 28 Self = protocol.ProtoSub 29 Peer = protocol.ProtoPub 30 SelfName = "sub" 31 PeerName = "pub" 32 ) 33 34 type pipe struct { 35 p protocol.Pipe 36 s *socket 37 } 38 39 type socket struct { 40 closed bool 41 closeQ chan struct{} 42 recvQLen int 43 recvExpire time.Duration 44 recvQ chan *protocol.Message 45 sizeQ chan struct{} 46 sync.Mutex 47 } 48 49 var ( 50 nilQ <-chan time.Time 51 ) 52 53 const defaultQLen = 128 54 55 func (s *socket) SendMsg(*protocol.Message) error { 56 return protocol.ErrProtoOp 57 } 58 59 func (s *socket) RecvMsg() (*protocol.Message, error) { 60 // For now this uses a simple unified queue for the entire 61 // socket. Later we can look at moving this to priority queues 62 // based on socket pipes. 63 timeQ := nilQ 64 for { 65 s.Lock() 66 if s.recvExpire > 0 { 67 timeQ = time.After(s.recvExpire) 68 } 69 closeQ := s.closeQ 70 sizeQ := s.sizeQ 71 recvQ := s.recvQ 72 s.Unlock() 73 select { 74 case <-closeQ: 75 return nil, protocol.ErrClosed 76 case <-timeQ: 77 return nil, protocol.ErrRecvTimeout 78 case <-sizeQ: 79 continue 80 case m := <-recvQ: 81 return m, nil 82 } 83 } 84 } 85 86 func (s *socket) SetOption(name string, value interface{}) error { 87 switch name { 88 89 case protocol.OptionRecvDeadline: 90 if v, ok := value.(time.Duration); ok { 91 s.Lock() 92 s.recvExpire = v 93 s.Unlock() 94 return nil 95 } 96 return protocol.ErrBadValue 97 98 case protocol.OptionReadQLen: 99 if v, ok := value.(int); ok && v >= 0 { 100 recvQ := make(chan *protocol.Message, v) 101 sizeQ := make(chan struct{}) 102 s.Lock() 103 s.recvQ = recvQ 104 sizeQ, s.sizeQ = s.sizeQ, sizeQ 105 s.recvQLen = v 106 s.Unlock() 107 close(sizeQ) 108 109 // This leaks a few messages. But it doesn't really 110 // matter. Resizing the queue tosses the messages. 111 return nil 112 } 113 return protocol.ErrBadValue 114 } 115 116 return protocol.ErrBadOption 117 } 118 119 func (s *socket) GetOption(option string) (interface{}, error) { 120 switch option { 121 case protocol.OptionRaw: 122 return true, nil 123 case protocol.OptionRecvDeadline: 124 s.Lock() 125 v := s.recvExpire 126 s.Unlock() 127 return v, nil 128 case protocol.OptionReadQLen: 129 s.Lock() 130 v := s.recvQLen 131 s.Unlock() 132 return v, nil 133 } 134 135 return nil, protocol.ErrBadOption 136 } 137 138 func (s *socket) AddPipe(pp protocol.Pipe) error { 139 p := &pipe{ 140 p: pp, 141 s: s, 142 } 143 s.Lock() 144 defer s.Unlock() 145 if s.closed { 146 return protocol.ErrClosed 147 } 148 go p.receiver() 149 return nil 150 } 151 152 func (s *socket) RemovePipe(protocol.Pipe) { 153 } 154 155 func (s *socket) OpenContext() (protocol.Context, error) { 156 return nil, protocol.ErrProtoOp 157 } 158 159 func (*socket) Info() protocol.Info { 160 return protocol.Info{ 161 Self: Self, 162 Peer: Peer, 163 SelfName: SelfName, 164 PeerName: PeerName, 165 } 166 } 167 168 func (s *socket) Close() error { 169 s.Lock() 170 if s.closed { 171 s.Unlock() 172 return protocol.ErrClosed 173 } 174 s.closed = true 175 s.Unlock() 176 close(s.closeQ) 177 return nil 178 } 179 180 func (p *pipe) receiver() { 181 s := p.s 182 for { 183 m := p.p.RecvMsg() 184 if m == nil { 185 break 186 } 187 188 s.Lock() 189 recvQ := s.recvQ 190 s.Unlock() 191 192 // No need to test for resizing or close here, because we 193 // never block anyway. 194 195 select { 196 case recvQ <- m: 197 default: 198 m.Free() 199 } 200 } 201 p.close() 202 } 203 204 func (p *pipe) close() { 205 _ = p.p.Close() 206 } 207 208 // NewProtocol returns a new protocol implementation. 209 func NewProtocol() protocol.Protocol { 210 s := &socket{ 211 closeQ: make(chan struct{}), 212 sizeQ: make(chan struct{}), 213 recvQ: make(chan *protocol.Message, defaultQLen), 214 recvQLen: defaultQLen, 215 } 216 return s 217 } 218 219 // NewSocket allocates a raw Socket using the PULL protocol. 220 func NewSocket() (protocol.Socket, error) { 221 return protocol.MakeSocket(NewProtocol()), nil 222 }