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  }