github.com/gdamore/mangos@v1.4.0/compat/compat.go (about) 1 // Copyright 2018 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 nanomsg is a compatibility wrapper. It attempts to offer an 16 // a minimal replacement for the same API as github.com/op/go-nanomsg, 17 // but does so using the mangos package underneath. The intent is to to 18 // facilitate converting existing applications to mangos. 19 // 20 // Only the synchronous API is supported -- the Poller/PollItem API is 21 // not present here. Applications are encouraged to use Go's native support 22 // for goroutines and channels to build such features if needed. 23 // 24 // New applications should be developed with mangos API directly, rather 25 // than using this compatibility shim. Additionally, note that this API 26 // lacks a number of the performance improvements in the mangos API; very 27 // specifically it does not support message reuse, which means that a busy 28 // consumer is going to thrash the garbage collector in Go pretty hard. 29 // 30 // Only a subset of the mangos capabilities are exported through this API; 31 // to get the full feature set (e.g. TLS over TCP) the mangos API should be 32 // used directly. 33 package nanomsg 34 35 import ( 36 "errors" 37 "time" 38 ) 39 40 import ( 41 "nanomsg.org/go-mangos" 42 "nanomsg.org/go-mangos/protocol/bus" 43 "nanomsg.org/go-mangos/protocol/pair" 44 "nanomsg.org/go-mangos/protocol/pub" 45 "nanomsg.org/go-mangos/protocol/pull" 46 "nanomsg.org/go-mangos/protocol/push" 47 "nanomsg.org/go-mangos/protocol/rep" 48 "nanomsg.org/go-mangos/protocol/req" 49 "nanomsg.org/go-mangos/protocol/respondent" 50 "nanomsg.org/go-mangos/protocol/sub" 51 "nanomsg.org/go-mangos/protocol/surveyor" 52 "nanomsg.org/go-mangos/transport/all" 53 ) 54 55 // Domain is the socket domain or address family. We use it to indicate 56 // either normal or raw mode sockets. 57 type Domain int 58 59 // Constants for socket type. 60 const ( 61 AF_SP = Domain(0) 62 AF_SP_RAW = Domain(1) 63 ) 64 65 // Protocol is the numeric abstraction to the various protocols or patterns 66 // that Mangos supports. 67 type Protocol int 68 69 // Constants for protocols. 70 const ( 71 PUSH = Protocol(mangos.ProtoPush) 72 PULL = Protocol(mangos.ProtoPull) 73 PUB = Protocol(mangos.ProtoPub) 74 SUB = Protocol(mangos.ProtoSub) 75 REQ = Protocol(mangos.ProtoReq) 76 REP = Protocol(mangos.ProtoRep) 77 SURVEYOR = Protocol(mangos.ProtoSurveyor) 78 RESPONDENT = Protocol(mangos.ProtoRespondent) 79 BUS = Protocol(mangos.ProtoBus) 80 PAIR = Protocol(mangos.ProtoPair) 81 ) 82 83 // DontWait is an (unsupported!) flag option. 84 const DontWait = 1 85 86 var ( 87 errNotSup = errors.New("not supported") 88 errNoFlag = errors.New("flags not supported") 89 errBadDomain = errors.New("domain invalid or not supported") 90 ) 91 92 // Socket is the main connection to the underlying library. 93 type Socket struct { 94 sock mangos.Socket 95 proto Protocol 96 dom Domain 97 rto time.Duration 98 sto time.Duration 99 } 100 101 // Endpoint is a structure that holds the peer address for now. 102 type Endpoint struct { 103 Address string 104 } 105 106 // String just returns the endpoint address for now. 107 func (ep *Endpoint) String() string { 108 return ep.Address 109 } 110 111 // NewSocket allocates a new Socket. The Socket is the handle used to 112 // access the underlying library. 113 func NewSocket(d Domain, p Protocol) (*Socket, error) { 114 115 var s Socket 116 var err error 117 118 s.proto = p 119 s.dom = d 120 121 switch p { 122 case PUB: 123 s.sock, err = pub.NewSocket() 124 case SUB: 125 s.sock, err = sub.NewSocket() 126 case PUSH: 127 s.sock, err = push.NewSocket() 128 case PULL: 129 s.sock, err = pull.NewSocket() 130 case REQ: 131 s.sock, err = req.NewSocket() 132 case REP: 133 s.sock, err = rep.NewSocket() 134 case SURVEYOR: 135 s.sock, err = surveyor.NewSocket() 136 case RESPONDENT: 137 s.sock, err = respondent.NewSocket() 138 case PAIR: 139 s.sock, err = pair.NewSocket() 140 case BUS: 141 s.sock, err = bus.NewSocket() 142 default: 143 err = mangos.ErrBadProto 144 } 145 146 if err != nil { 147 return nil, err 148 } 149 150 switch d { 151 case AF_SP: 152 case AF_SP_RAW: 153 err = s.sock.SetOption(mangos.OptionRaw, true) 154 default: 155 err = errBadDomain 156 } 157 if err != nil { 158 s.sock.Close() 159 return nil, err 160 } 161 162 // Compat mode sockets should timeout on send if we don't have any pipes 163 if err = s.sock.SetOption(mangos.OptionWriteQLen, 0); err != nil { 164 s.sock.Close() 165 return nil, err 166 } 167 168 s.rto = -1 169 s.sto = -1 170 all.AddTransports(s.sock) 171 return &s, nil 172 } 173 174 // Close shuts down the socket. 175 func (s *Socket) Close() error { 176 if s.sock != nil { 177 s.sock.Close() 178 } 179 return nil 180 } 181 182 // Bind creates sets up to receive incoming connections from remote peers. 183 // This wraps around mangos' Listen() socket interface. 184 func (s *Socket) Bind(addr string) (*Endpoint, error) { 185 186 if err := s.sock.Listen(addr); err != nil { 187 return nil, err 188 } 189 return &Endpoint{Address: addr}, nil 190 } 191 192 // Connect establishes (asynchronously) a client side connection 193 // to a remote peer. The client will attempt to keep reconnecting. 194 // This wraps around mangos' Dial() socket inteface. 195 func (s *Socket) Connect(addr string) (*Endpoint, error) { 196 d, err := s.sock.NewDialer(addr, nil) 197 if err != nil { 198 return nil, err 199 } 200 if err := d.Dial(); err != nil { 201 return nil, err 202 } 203 return &Endpoint{Address: addr}, nil 204 } 205 206 // Recv receives a message. For AF_SP_RAW messages the header data will 207 // be included at he start of the returned byte slice (otherwise it will 208 // be stripped). At this time no flags are supported. 209 func (s *Socket) Recv(flags int) ([]byte, error) { 210 var b []byte 211 var m *mangos.Message 212 var err error 213 214 if flags != 0 { 215 return nil, errNoFlag 216 } 217 218 // Legacy nanomsg uses the opposite semantic for negative and 219 // zero values than mangos. A bit unfortunate. 220 switch { 221 case s.rto > 0: 222 s.sock.SetOption(mangos.OptionRecvDeadline, s.rto) 223 case s.rto == 0: 224 s.sock.SetOption(mangos.OptionRecvDeadline, -1) 225 case s.rto < 0: 226 s.sock.SetOption(mangos.OptionRecvDeadline, 0) 227 } 228 229 if m, err = s.sock.RecvMsg(); err != nil { 230 return nil, err 231 } 232 233 if s.dom == AF_SP_RAW { 234 b = make([]byte, 0, len(m.Body)+len(m.Header)) 235 b = append(b, m.Header...) 236 b = append(b, m.Body...) 237 } else { 238 b = make([]byte, 0, len(m.Body)) 239 b = append(b, m.Body...) 240 } 241 m.Free() 242 return b, nil 243 } 244 245 // Send sends a message. For AF_SP_RAW messages the header must be 246 // included in the argument. At this time, no flags are supported. 247 func (s *Socket) Send(b []byte, flags int) (int, error) { 248 249 if flags != 0 { 250 return -1, errNoFlag 251 } 252 253 m := mangos.NewMessage(len(b)) 254 m.Body = append(m.Body, b...) 255 256 // Legacy nanomsg uses the opposite semantic for negative and 257 // zero values than mangos. A bit unfortunate. 258 switch { 259 case s.sto > 0: 260 s.sock.SetOption(mangos.OptionSendDeadline, s.sto) 261 case s.sto == 0: 262 s.sock.SetOption(mangos.OptionSendDeadline, -1) 263 case s.sto < 0: 264 s.sock.SetOption(mangos.OptionSendDeadline, 0) 265 } 266 267 return len(b), s.sock.SendMsg(m) 268 } 269 270 // Protocol returns the numeric value of the sockets protocol, such as 271 // REQ, REP, SUB, PUB, etc. 272 func (s *Socket) Protocol() (Protocol, error) { 273 return s.proto, nil 274 } 275 276 // Domain returns the socket domain, either AF_SP or AF_SP_RAW. 277 func (s *Socket) Domain() (Domain, error) { 278 return s.dom, nil 279 } 280 281 // RecvFd is not supported. 282 func (s *Socket) RecvFd() (uintptr, error) { 283 return 0, errNotSup 284 } 285 286 // SendFd is not supported. 287 func (s *Socket) SendFd() (uintptr, error) { 288 return 0, errNotSup 289 } 290 291 // SendPrio is intended to set send priorities. Mangos does not support 292 // send priorities at present. 293 func (s *Socket) SendPrio() (int, error) { 294 return 0, errNotSup 295 } 296 297 // SetSendPrio is not supported. 298 func (s *Socket) SetSendPrio(int) error { 299 return errNotSup 300 } 301 302 // Linger should set the TCP linger time, but at present is not supported. 303 func (s *Socket) Linger() (time.Duration, error) { 304 var t time.Duration 305 return t, errNotSup 306 } 307 308 // SetLinger is not supported. 309 func (s *Socket) SetLinger(time.Duration) error { 310 return errNotSup 311 } 312 313 // SendTimeout retrieves the send timeout. Negative values indicate 314 // an infinite timeout. 315 func (s *Socket) SendTimeout() (time.Duration, error) { 316 return s.sto, nil 317 } 318 319 // SetSendTimeout sets the send timeout. Negative values indicate 320 // an infinite timeout. The Send() operation will return an error if 321 // a message cannot be sent within this time. 322 func (s *Socket) SetSendTimeout(d time.Duration) error { 323 s.sto = d 324 return nil 325 } 326 327 // RecvTimeout retrieves the receive timeout. Negative values indicate 328 // an infinite timeout. 329 func (s *Socket) RecvTimeout() (time.Duration, error) { 330 return s.rto, nil 331 } 332 333 // SetRecvTimeout sets a timeout for receive operations. The Recv() 334 // function will return an error if no message is received within this time. 335 func (s *Socket) SetRecvTimeout(d time.Duration) error { 336 s.rto = d 337 return nil 338 } 339 340 // Shutdown should shut down a particular endpoint. Mangos lacks the 341 // underlying functionality to support this at present. 342 func (s *Socket) Shutdown(*Endpoint) error { 343 return errNotSup 344 } 345 346 // BusSocket is a socket associated with the BUS protocol. 347 type BusSocket struct { 348 *Socket 349 } 350 351 // NewBusSocket creates a BUS socket. 352 func NewBusSocket() (*BusSocket, error) { 353 s, err := NewSocket(AF_SP, BUS) 354 return &BusSocket{s}, err 355 } 356 357 // PairSocket is a socket associated with the PAIR protocol. 358 type PairSocket struct { 359 *Socket 360 } 361 362 // NewPairSocket creates a PAIR socket. 363 func NewPairSocket() (*PairSocket, error) { 364 s, err := NewSocket(AF_SP, PAIR) 365 return &PairSocket{s}, err 366 } 367 368 // PubSocket is a socket associated with the PUB protocol. 369 type PubSocket struct { 370 *Socket 371 } 372 373 // NewPubSocket creates a PUB socket. 374 func NewPubSocket() (*PubSocket, error) { 375 s, err := NewSocket(AF_SP, PUB) 376 return &PubSocket{s}, err 377 } 378 379 // PullSocket is a socket associated with the PULL protocol. 380 type PullSocket struct { 381 *Socket 382 } 383 384 // NewPullSocket creates a PULL socket. 385 func NewPullSocket() (*PullSocket, error) { 386 s, err := NewSocket(AF_SP, PULL) 387 return &PullSocket{s}, err 388 } 389 390 // PushSocket is a socket associated with the PUSH protocol. 391 type PushSocket struct { 392 *Socket 393 } 394 395 // NewPushSocket creates a PUSH socket. 396 func NewPushSocket() (*PushSocket, error) { 397 s, err := NewSocket(AF_SP, PUSH) 398 return &PushSocket{s}, err 399 } 400 401 // RepSocket is a socket associated with the REP protocol. 402 type RepSocket struct { 403 *Socket 404 } 405 406 // NewRepSocket creates a REP socket. 407 func NewRepSocket() (*RepSocket, error) { 408 s, err := NewSocket(AF_SP, REP) 409 return &RepSocket{s}, err 410 } 411 412 // ReqSocket is a socket associated with the REQ protocol. 413 type ReqSocket struct { 414 *Socket 415 } 416 417 // NewReqSocket creates a REQ socket. 418 func NewReqSocket() (*ReqSocket, error) { 419 s, err := NewSocket(AF_SP, REQ) 420 return &ReqSocket{s}, err 421 } 422 423 // RespondentSocket is a socket associated with the RESPONDENT protocol. 424 type RespondentSocket struct { 425 *Socket 426 } 427 428 // NewRespondentSocket creates a RESPONDENT socket. 429 func NewRespondentSocket() (*RespondentSocket, error) { 430 s, err := NewSocket(AF_SP, RESPONDENT) 431 return &RespondentSocket{s}, err 432 } 433 434 // SubSocket is a socket associated with the SUB protocol. 435 type SubSocket struct { 436 *Socket 437 } 438 439 // Subscribe registers interest in a topic. 440 func (s *SubSocket) Subscribe(topic string) error { 441 return s.sock.SetOption(mangos.OptionSubscribe, topic) 442 } 443 444 // Unsubscribe unregisters interest in a topic. 445 func (s *SubSocket) Unsubscribe(topic string) error { 446 return s.sock.SetOption(mangos.OptionUnsubscribe, topic) 447 } 448 449 // NewSubSocket creates a SUB socket. 450 func NewSubSocket() (*SubSocket, error) { 451 s, err := NewSocket(AF_SP, SUB) 452 return &SubSocket{s}, err 453 } 454 455 // SurveyorSocket is a socket associated with the SURVEYOR protocol. 456 type SurveyorSocket struct { 457 *Socket 458 } 459 460 // Deadline returns the survey deadline on the socket. After this time, 461 // responses from a survey will be discarded. 462 func (s *SurveyorSocket) Deadline() (time.Duration, error) { 463 var d time.Duration 464 v, err := s.sock.GetOption(mangos.OptionSurveyTime) 465 if err == nil { 466 d = v.(time.Duration) 467 } 468 return d, err 469 } 470 471 // SetDeadline sets the survey deadline on the socket. After this time, 472 // responses from a survey will be discarded. 473 func (s *SurveyorSocket) SetDeadline(d time.Duration) error { 474 return s.sock.SetOption(mangos.OptionSurveyTime, d) 475 } 476 477 // NewSurveyorSocket creates a SURVEYOR socket. 478 func NewSurveyorSocket() (*SurveyorSocket, error) { 479 s, err := NewSocket(AF_SP, SURVEYOR) 480 return &SurveyorSocket{s}, err 481 }