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  }