go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/protocol/xpush/xpush.go (about)

     1  // Copyright 2021 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 xpush implements the raw PUSH protocol.
    16  package xpush
    17  
    18  import (
    19  	"sync"
    20  	"time"
    21  
    22  	"go.nanomsg.org/mangos/v3/protocol"
    23  )
    24  
    25  // Protocol identity information.
    26  const (
    27  	Self     = protocol.ProtoPush
    28  	Peer     = protocol.ProtoPull
    29  	SelfName = "push"
    30  	PeerName = "pull"
    31  )
    32  
    33  type pipe struct {
    34  	p      protocol.Pipe
    35  	s      *socket
    36  	closed bool
    37  	sendQ  chan *protocol.Message
    38  	closeQ chan struct{}
    39  }
    40  
    41  type socket struct {
    42  	closed      bool
    43  	closeQ      chan struct{}
    44  	sendQ       chan *protocol.Message
    45  	noPeerQ     chan struct{}
    46  	sendExpire  time.Duration
    47  	sendQLen    int
    48  	bestEffort  bool
    49  	failNoPeers bool
    50  	readyQ      []*pipe
    51  	pipes       map[uint32]*pipe
    52  	cv          *sync.Cond
    53  	sync.Mutex
    54  }
    55  
    56  var (
    57  	nilQ    <-chan time.Time
    58  	closedQ chan time.Time
    59  )
    60  
    61  const defaultQLen = 128
    62  
    63  func init() {
    64  	closedQ = make(chan time.Time)
    65  	close(closedQ)
    66  }
    67  
    68  // SendMsg implements sending a message.  The message must come with
    69  // its headers already prepared.  This will be at a minimum the request
    70  // ID at the end of the header, plus any leading backtrace information
    71  // coming from a paired REP socket.
    72  func (s *socket) SendMsg(m *protocol.Message) error {
    73  	s.Lock()
    74  	bestEffort := s.bestEffort
    75  	tq := nilQ
    76  	if bestEffort {
    77  		tq = closedQ
    78  	} else if s.sendExpire > 0 {
    79  		tq = time.After(s.sendExpire)
    80  	}
    81  	if s.closed {
    82  		s.Unlock()
    83  		return protocol.ErrClosed
    84  	}
    85  	if s.failNoPeers && len(s.pipes) == 0 {
    86  		s.Unlock()
    87  		return protocol.ErrNoPeers
    88  	}
    89  	pq := s.noPeerQ
    90  	s.Unlock()
    91  
    92  	select {
    93  	case <-pq:
    94  		return protocol.ErrNoPeers
    95  	case s.sendQ <- m:
    96  	case <-s.closeQ:
    97  		return protocol.ErrClosed
    98  	case <-tq:
    99  		if bestEffort {
   100  			m.Free()
   101  			return nil
   102  		}
   103  		return protocol.ErrSendTimeout
   104  	}
   105  
   106  	s.Lock()
   107  	s.cv.Signal()
   108  	s.Unlock()
   109  	return nil
   110  }
   111  
   112  func (s *socket) sender() {
   113  	s.Lock()
   114  	defer s.Unlock()
   115  	for {
   116  		if s.closed {
   117  			return
   118  		}
   119  		if len(s.readyQ) == 0 || len(s.sendQ) == 0 {
   120  			s.cv.Wait()
   121  			continue
   122  		}
   123  		m := <-s.sendQ
   124  		p := s.readyQ[0]
   125  		s.readyQ = s.readyQ[1:]
   126  		go p.send(m)
   127  	}
   128  }
   129  
   130  func (s *socket) RecvMsg() (*protocol.Message, error) {
   131  	return nil, protocol.ErrProtoOp
   132  }
   133  
   134  func (p *pipe) receiver() {
   135  	for {
   136  		m := p.p.RecvMsg()
   137  		if m == nil {
   138  			break
   139  		}
   140  		// We really never expected to receive this.
   141  		m.Free()
   142  	}
   143  	p.close()
   144  }
   145  
   146  func (p *pipe) send(m *protocol.Message) {
   147  	s := p.s
   148  	if err := p.p.SendMsg(m); err != nil {
   149  		m.Free()
   150  		p.close()
   151  		return
   152  	}
   153  	s.Lock()
   154  	if !s.closed && !p.closed {
   155  		s.readyQ = append(s.readyQ, p)
   156  		s.cv.Broadcast()
   157  	}
   158  	s.Unlock()
   159  
   160  }
   161  
   162  func (p *pipe) close() {
   163  	_ = p.p.Close()
   164  }
   165  
   166  func (s *socket) SetOption(name string, value interface{}) error {
   167  	switch name {
   168  
   169  	case protocol.OptionSendDeadline:
   170  		if v, ok := value.(time.Duration); ok {
   171  			s.Lock()
   172  			s.sendExpire = v
   173  			s.Unlock()
   174  			return nil
   175  		}
   176  		return protocol.ErrBadValue
   177  
   178  	case protocol.OptionBestEffort:
   179  		if v, ok := value.(bool); ok {
   180  			s.Lock()
   181  			s.bestEffort = v
   182  			s.Unlock()
   183  			return nil
   184  		}
   185  		return protocol.ErrBadValue
   186  
   187  	case protocol.OptionFailNoPeers:
   188  		if v, ok := value.(bool); ok {
   189  			s.Lock()
   190  			s.failNoPeers = v
   191  			s.Unlock()
   192  			return nil
   193  		}
   194  		return protocol.ErrBadValue
   195  
   196  	case protocol.OptionWriteQLen:
   197  		if v, ok := value.(int); ok && v >= 0 {
   198  
   199  			newQ := make(chan *protocol.Message, v)
   200  			s.Lock()
   201  			s.sendQLen = v
   202  			oldQ := s.sendQ
   203  			s.sendQ = newQ
   204  
   205  			for {
   206  				var m *protocol.Message
   207  				select {
   208  				case m = <-oldQ:
   209  				default:
   210  				}
   211  				if m == nil {
   212  					break
   213  				}
   214  				select {
   215  				case newQ <- m:
   216  				default:
   217  					m.Free()
   218  				}
   219  			}
   220  			s.Unlock()
   221  			return nil
   222  		}
   223  		return protocol.ErrBadValue
   224  	}
   225  	return protocol.ErrBadOption
   226  }
   227  
   228  func (s *socket) GetOption(option string) (interface{}, error) {
   229  	switch option {
   230  	case protocol.OptionRaw:
   231  		return true, nil
   232  	case protocol.OptionSendDeadline:
   233  		s.Lock()
   234  		v := s.sendExpire
   235  		s.Unlock()
   236  		return v, nil
   237  	case protocol.OptionBestEffort:
   238  		s.Lock()
   239  		v := s.bestEffort
   240  		s.Unlock()
   241  		return v, nil
   242  	case protocol.OptionWriteQLen:
   243  		s.Lock()
   244  		v := s.sendQLen
   245  		s.Unlock()
   246  		return v, nil
   247  	case protocol.OptionFailNoPeers:
   248  		s.Lock()
   249  		v := s.failNoPeers
   250  		s.Unlock()
   251  		return v, nil
   252  	}
   253  
   254  	return nil, protocol.ErrBadOption
   255  }
   256  
   257  func (s *socket) Close() error {
   258  	s.Lock()
   259  	if s.closed {
   260  		s.Unlock()
   261  		return protocol.ErrClosed
   262  	}
   263  	s.closed = true
   264  	s.cv.Broadcast() 
   265  	s.Unlock()
   266  	close(s.closeQ)
   267  	return nil
   268  }
   269  
   270  func (s *socket) AddPipe(pp protocol.Pipe) error {
   271  	p := &pipe{
   272  		p:      pp,
   273  		s:      s,
   274  		closeQ: make(chan struct{}),
   275  		sendQ:  make(chan *protocol.Message, 1),
   276  	}
   277  	pp.SetPrivate(p)
   278  	s.Lock()
   279  	defer s.Unlock()
   280  	if s.closed {
   281  		return protocol.ErrClosed
   282  	}
   283  	go p.receiver()
   284  	s.pipes[pp.ID()] = p
   285  	s.readyQ = append(s.readyQ, p)
   286  	s.cv.Broadcast()
   287  	return nil
   288  }
   289  
   290  func (s *socket) RemovePipe(pp protocol.Pipe) {
   291  	p := pp.GetPrivate().(*pipe)
   292  	close(p.closeQ)
   293  
   294  	s.Lock()
   295  	p.closed = true
   296  	for i, rp := range s.readyQ {
   297  		if p == rp {
   298  			s.readyQ = append(s.readyQ[:i], s.readyQ[i+1:]...)
   299  			break
   300  		}
   301  	}
   302  	delete(s.pipes, pp.ID())
   303  	if s.failNoPeers && len(s.pipes) == 0 {
   304  		close(s.noPeerQ)
   305  		s.noPeerQ = make(chan struct{})
   306  	}
   307  	s.Unlock()
   308  }
   309  
   310  func (s *socket) OpenContext() (protocol.Context, error) {
   311  	return nil, protocol.ErrProtoOp
   312  }
   313  
   314  func (*socket) Info() protocol.Info {
   315  	return protocol.Info{
   316  		Self:     Self,
   317  		Peer:     Peer,
   318  		SelfName: SelfName,
   319  		PeerName: PeerName,
   320  	}
   321  }
   322  
   323  // NewProtocol returns a new protocol implementation.
   324  func NewProtocol() protocol.Protocol {
   325  	s := &socket{
   326  		closeQ:   make(chan struct{}),
   327  		noPeerQ: make(chan struct{}),
   328  		sendQ:    make(chan *protocol.Message, defaultQLen),
   329  		sendQLen: defaultQLen,
   330  		pipes:    make(map[uint32]*pipe),
   331  	}
   332  	s.cv = sync.NewCond(s)
   333  	go s.sender()
   334  	return s
   335  }
   336  
   337  // NewSocket allocates a new Socket using the REQ protocol.
   338  func NewSocket() (protocol.Socket, error) {
   339  	return protocol.MakeSocket(NewProtocol()), nil
   340  }