go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/protocol/sub/sub.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 sub implements the SUB protocol.  This protocol receives messages
    16  // from publishers (PUB peers).  The messages are filtered based on
    17  // subscription, such that only subscribed messages (see OptionSubscribe) are
    18  // received.
    19  //
    20  // Note that in order to receive any messages, at least one subscription must
    21  // be present.  If no subscription is present (the default state), receive
    22  // operations will block forever.
    23  package sub
    24  
    25  import (
    26  	"bytes"
    27  	"sync"
    28  	"time"
    29  
    30  	"go.nanomsg.org/mangos/v3/protocol"
    31  )
    32  
    33  // Protocol identity information.
    34  const (
    35  	Self     = protocol.ProtoSub
    36  	Peer     = protocol.ProtoPub
    37  	SelfName = "sub"
    38  	PeerName = "pub"
    39  )
    40  
    41  type socket struct {
    42  	master *context
    43  	ctxs   map[*context]struct{}
    44  	closed bool
    45  	sync.Mutex
    46  }
    47  
    48  type pipe struct {
    49  	s *socket
    50  	p protocol.Pipe
    51  }
    52  
    53  type context struct {
    54  	recvQLen   int
    55  	recvQ      chan *protocol.Message
    56  	closeQ     chan struct{}
    57  	sizeQ      chan struct{}
    58  	recvExpire time.Duration
    59  	closed     bool
    60  	subs       [][]byte
    61  	s          *socket
    62  }
    63  
    64  const defaultQLen = 128
    65  
    66  func (*context) SendMsg(*protocol.Message) error {
    67  	return protocol.ErrProtoOp
    68  }
    69  
    70  func (c *context) RecvMsg() (*protocol.Message, error) {
    71  
    72  	s := c.s
    73  	var timeQ <-chan time.Time
    74  	s.Lock()
    75  	recvQ := c.recvQ
    76  	sizeQ := c.sizeQ
    77  	closeQ := c.closeQ
    78  	if c.recvExpire > 0 {
    79  		timeQ = time.After(c.recvExpire)
    80  	}
    81  	s.Unlock()
    82  
    83  	for {
    84  		select {
    85  		case <-timeQ:
    86  			return nil, protocol.ErrRecvTimeout
    87  		case <-closeQ:
    88  			return nil, protocol.ErrClosed
    89  		case <-sizeQ:
    90  			s.Lock()
    91  			sizeQ = c.sizeQ
    92  			recvQ = c.recvQ
    93  			s.Unlock()
    94  			continue
    95  		case m := <-recvQ:
    96  			m = m.MakeUnique()
    97  			return m, nil
    98  		}
    99  	}
   100  }
   101  
   102  func (c *context) Close() error {
   103  	s := c.s
   104  	s.Lock()
   105  	if c.closed {
   106  		s.Unlock()
   107  		return protocol.ErrClosed
   108  	}
   109  	c.closed = true
   110  	delete(s.ctxs, c)
   111  	s.Unlock()
   112  	close(c.closeQ)
   113  	return nil
   114  }
   115  
   116  func (*socket) SendMsg(*protocol.Message) error {
   117  	return protocol.ErrProtoOp
   118  }
   119  
   120  func (p *pipe) receiver() {
   121  	s := p.s
   122  	for {
   123  		m := p.p.RecvMsg()
   124  		if m == nil {
   125  			break
   126  		}
   127  		s.Lock()
   128  		for c := range s.ctxs {
   129  			if c.matches(m) {
   130  				// Matched, send it up.  Best effort.
   131  				// As we are passing this to the user,
   132  				// we need to ensure that the message
   133  				// may be modified.
   134  				m.Clone()
   135  				select {
   136  				case c.recvQ <- m:
   137  				default:
   138  					select {
   139  					case m2 := <-c.recvQ:
   140  						m2.Free()
   141  					default:
   142  					}
   143  					// We have made room, and as we are
   144  					// holding the lock, we are guaranteed
   145  					// to be able to enqueue another
   146  					// message. (No other pipe can
   147  					// get in right now.)
   148  					// NB: If we ever do work to break
   149  					// up the locking, we will need to
   150  					// revisit this.
   151  					c.recvQ <- m
   152  				}
   153  			}
   154  		}
   155  		s.Unlock()
   156  		m.Free()
   157  	}
   158  
   159  	p.close()
   160  }
   161  
   162  func (s *socket) AddPipe(pp protocol.Pipe) error {
   163  	p := &pipe{
   164  		p: pp,
   165  		s: s,
   166  	}
   167  	s.Lock()
   168  	defer s.Unlock()
   169  	if s.closed {
   170  		return protocol.ErrClosed
   171  	}
   172  	go p.receiver()
   173  	return nil
   174  }
   175  
   176  func (s *socket) RemovePipe(protocol.Pipe) {
   177  }
   178  
   179  func (s *socket) Close() error {
   180  	s.Lock()
   181  	if s.closed {
   182  		s.Unlock()
   183  		return protocol.ErrClosed
   184  	}
   185  	ctxs := make([]*context, 0, len(s.ctxs))
   186  	for c := range s.ctxs {
   187  		ctxs = append(ctxs, c)
   188  	}
   189  	s.closed = true
   190  	s.Unlock()
   191  	for _, c := range ctxs {
   192  		_ = c.Close()
   193  	}
   194  	return nil
   195  }
   196  
   197  func (p *pipe) close() {
   198  	_ = p.p.Close()
   199  }
   200  
   201  func (c *context) matches(m *protocol.Message) bool {
   202  	for _, sub := range c.subs {
   203  		if bytes.HasPrefix(m.Body, sub) {
   204  			return true
   205  		}
   206  	}
   207  	return false
   208  
   209  }
   210  
   211  func (c *context) subscribe(topic []byte) error {
   212  	for _, sub := range c.subs {
   213  		if bytes.Equal(sub, topic) {
   214  			// Already present
   215  			return nil
   216  		}
   217  	}
   218  	// We need a full data copy of our own.
   219  	topic = append(make([]byte, 0, len(topic)), topic...)
   220  	c.subs = append(c.subs, topic)
   221  	return nil
   222  }
   223  
   224  func (c *context) unsubscribe(topic []byte) error {
   225  	for i, sub := range c.subs {
   226  		if !bytes.Equal(sub, topic) {
   227  			continue
   228  		}
   229  		c.subs = append(c.subs[:i], c.subs[i+1:]...)
   230  
   231  		// Because we have changed the subscription,
   232  		// we may have messages in the channel that
   233  		// we don't want any more.  Lets prune those.
   234  		recvQ := make(chan *protocol.Message, c.recvQLen)
   235  		sizeQ := make(chan struct{})
   236  		recvQ, c.recvQ = c.recvQ, recvQ
   237  		sizeQ, c.sizeQ = c.sizeQ, sizeQ
   238  		close(sizeQ)
   239  		for {
   240  			select {
   241  			case m := <-recvQ:
   242  				if !c.matches(m) {
   243  					m.Free()
   244  					continue
   245  				}
   246  				// We're holding the lock, so nothing else
   247  				// can contend for this (pipes must be
   248  				// waiting) -- so this is guaranteed not to
   249  				// block.
   250  				c.recvQ <- m
   251  			default:
   252  				return nil
   253  			}
   254  		}
   255  	}
   256  	// Subscription not present
   257  	return protocol.ErrBadValue
   258  }
   259  
   260  func (c *context) SetOption(name string, value interface{}) error {
   261  	s := c.s
   262  
   263  	var fn func([]byte) error
   264  
   265  	switch name {
   266  	case protocol.OptionReadQLen:
   267  		if v, ok := value.(int); ok {
   268  			recvQ := make(chan *protocol.Message, v)
   269  			sizeQ := make(chan struct{})
   270  			c.s.Lock()
   271  			c.recvQ = recvQ
   272  			sizeQ, c.sizeQ = c.sizeQ, sizeQ
   273  			c.recvQ = recvQ
   274  			c.recvQLen = v
   275  			close(sizeQ)
   276  			c.s.Unlock()
   277  			return nil
   278  		}
   279  		return protocol.ErrBadValue
   280  
   281  	case protocol.OptionRecvDeadline:
   282  		if v, ok := value.(time.Duration); ok {
   283  			c.s.Lock()
   284  			c.recvExpire = v
   285  			c.s.Unlock()
   286  			return nil
   287  		}
   288  		return protocol.ErrBadValue
   289  
   290  	case protocol.OptionSubscribe:
   291  		fn = c.subscribe
   292  	case protocol.OptionUnsubscribe:
   293  		fn = c.unsubscribe
   294  	default:
   295  		return protocol.ErrBadOption
   296  	}
   297  
   298  	var vb []byte
   299  
   300  	switch v := value.(type) {
   301  	case []byte:
   302  		vb = v
   303  	case string:
   304  		vb = []byte(v)
   305  	default:
   306  		return protocol.ErrBadValue
   307  	}
   308  
   309  	s.Lock()
   310  	defer s.Unlock()
   311  
   312  	return fn(vb)
   313  }
   314  
   315  func (c *context) GetOption(name string) (interface{}, error) {
   316  	switch name {
   317  	case protocol.OptionReadQLen:
   318  		c.s.Lock()
   319  		v := c.recvQLen
   320  		c.s.Unlock()
   321  		return v, nil
   322  	case protocol.OptionRecvDeadline:
   323  		c.s.Lock()
   324  		v := c.recvExpire
   325  		c.s.Unlock()
   326  		return v, nil
   327  	}
   328  	return nil, protocol.ErrBadOption
   329  }
   330  
   331  func (s *socket) RecvMsg() (*protocol.Message, error) {
   332  	return s.master.RecvMsg()
   333  }
   334  
   335  func (s *socket) OpenContext() (protocol.Context, error) {
   336  	s.Lock()
   337  	defer s.Unlock()
   338  	if s.closed {
   339  		return nil, protocol.ErrClosed
   340  	}
   341  	c := &context{
   342  		s:          s,
   343  		closeQ:     make(chan struct{}),
   344  		sizeQ:      make(chan struct{}),
   345  		recvQ:      make(chan *protocol.Message, s.master.recvQLen),
   346  		recvQLen:   s.master.recvQLen,
   347  		recvExpire: s.master.recvExpire,
   348  		subs:       [][]byte{},
   349  	}
   350  	s.ctxs[c] = struct{}{}
   351  	return c, nil
   352  }
   353  
   354  func (s *socket) GetOption(name string) (interface{}, error) {
   355  	switch name {
   356  	case protocol.OptionRaw:
   357  		return false, nil
   358  	default:
   359  		return s.master.GetOption(name)
   360  	}
   361  }
   362  
   363  func (s *socket) SetOption(name string, val interface{}) error {
   364  	return s.master.SetOption(name, val)
   365  }
   366  
   367  func (s *socket) Info() protocol.Info {
   368  	return protocol.Info{
   369  		Self:     Self,
   370  		Peer:     Peer,
   371  		SelfName: SelfName,
   372  		PeerName: PeerName,
   373  	}
   374  }
   375  
   376  // NewProtocol returns a new protocol implementation.
   377  func NewProtocol() protocol.Protocol {
   378  	s := &socket{
   379  		ctxs: make(map[*context]struct{}),
   380  	}
   381  	s.master = &context{
   382  		s:        s,
   383  		recvQ:    make(chan *protocol.Message, defaultQLen),
   384  		closeQ:   make(chan struct{}),
   385  		sizeQ:    make(chan struct{}),
   386  		recvQLen: defaultQLen,
   387  	}
   388  	s.ctxs[s.master] = struct{}{}
   389  	return s
   390  }
   391  
   392  // NewSocket allocates a new Socket using the SUB protocol.
   393  func NewSocket() (protocol.Socket, error) {
   394  	return protocol.MakeSocket(NewProtocol()), nil
   395  }