go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/protocol/xpub/xpub.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 xpub implements the PUB protocol. This broadcasts messages 16 // out to SUB partners, where they may be filtered. 17 package xpub 18 19 import ( 20 "sync" 21 22 "go.nanomsg.org/mangos/v3/protocol" 23 ) 24 25 type pipe struct { 26 p protocol.Pipe 27 s *socket 28 closeq chan struct{} 29 sendq chan *protocol.Message 30 } 31 32 type socket struct { 33 closed bool 34 pipes map[uint32]*pipe 35 sendQLen int 36 sync.Mutex 37 } 38 39 // Protocol identity information. 40 const ( 41 Self = protocol.ProtoPub 42 Peer = protocol.ProtoSub 43 SelfName = "pub" 44 PeerName = "sub" 45 ) 46 47 const defaultQLen = 128 48 49 func (s *socket) SendMsg(m *protocol.Message) error { 50 s.Lock() 51 if s.closed { 52 s.Unlock() 53 return protocol.ErrClosed 54 } 55 // This could benefit from optimization to avoid useless duplicates. 56 for _, p := range s.pipes { 57 m.Clone() 58 select { 59 case p.sendq <- m: 60 default: 61 // back-pressure, but we do not exert 62 m.Free() 63 } 64 } 65 s.Unlock() 66 m.Free() 67 return nil 68 } 69 70 func (s *socket) RecvMsg() (*protocol.Message, error) { 71 return nil, protocol.ErrProtoOp 72 } 73 74 func (s *socket) SetOption(name string, value interface{}) error { 75 switch name { 76 77 case protocol.OptionWriteQLen: 78 if v, ok := value.(int); ok && v >= 0 { 79 s.Lock() 80 s.sendQLen = v 81 s.Unlock() 82 return nil 83 } 84 return protocol.ErrBadValue 85 } 86 87 return protocol.ErrBadOption 88 } 89 90 func (s *socket) GetOption(option string) (interface{}, error) { 91 switch option { 92 case protocol.OptionRaw: 93 return true, nil 94 case protocol.OptionWriteQLen: 95 s.Lock() 96 v := s.sendQLen 97 s.Unlock() 98 return v, nil 99 } 100 101 return nil, protocol.ErrBadOption 102 } 103 104 func (s *socket) AddPipe(pp protocol.Pipe) error { 105 p := &pipe{ 106 p: pp, 107 s: s, 108 closeq: make(chan struct{}), 109 sendq: make(chan *protocol.Message, s.sendQLen), 110 } 111 pp.SetPrivate(p) 112 s.Lock() 113 defer s.Unlock() 114 if s.closed { 115 return protocol.ErrClosed 116 } 117 s.pipes[pp.ID()] = p 118 go p.sender() 119 go p.receiver() 120 return nil 121 } 122 123 func (s *socket) RemovePipe(pp protocol.Pipe) { 124 p := pp.GetPrivate().(*pipe) 125 s.Lock() 126 delete(s.pipes, pp.ID()) 127 close(p.closeq) 128 s.Unlock() 129 } 130 131 func (s *socket) OpenContext() (protocol.Context, error) { 132 return nil, protocol.ErrProtoOp 133 } 134 135 func (*socket) Info() protocol.Info { 136 return protocol.Info{ 137 Self: Self, 138 Peer: Peer, 139 SelfName: SelfName, 140 PeerName: PeerName, 141 } 142 } 143 144 func (s *socket) Close() error { 145 s.Lock() 146 if s.closed { 147 s.Unlock() 148 return protocol.ErrClosed 149 } 150 s.closed = true 151 s.Unlock() 152 return nil 153 } 154 155 func (p *pipe) sender() { 156 outer: 157 for { 158 var m *protocol.Message 159 select { 160 case <-p.closeq: 161 break outer 162 case m = <-p.sendq: 163 } 164 165 if err := p.p.SendMsg(m); err != nil { 166 m.Free() 167 break 168 } 169 } 170 p.close() 171 } 172 173 func (p *pipe) receiver() { 174 for { 175 m := p.p.RecvMsg() 176 if m == nil { 177 break 178 } 179 m.Free() 180 } 181 p.close() 182 } 183 184 func (p *pipe) close() { 185 _ = p.p.Close() 186 } 187 188 // NewProtocol returns a new protocol implementation. 189 func NewProtocol() protocol.Protocol { 190 s := &socket{ 191 pipes: make(map[uint32]*pipe), 192 sendQLen: defaultQLen, 193 } 194 return s 195 } 196 197 // NewSocket allocates a new Socket using the RESPONDENT protocol. 198 func NewSocket() (protocol.Socket, error) { 199 return protocol.MakeSocket(NewProtocol()), nil 200 }