github.com/therealbill/libredis@v0.0.0-20161227004305-7d50abda5ccf/client/pubsub.go (about)

     1  package client
     2  
     3  import (
     4  	"errors"
     5  	"strconv"
     6  	"strings"
     7  )
     8  
     9  // Publish posts a message to the given channel.
    10  // Integer reply: the number of clients that received the message.
    11  func (r *Redis) Publish(channel, message string) (int64, error) {
    12  	rp, err := r.ExecuteCommand("PUBLISH", channel, message)
    13  	if err != nil {
    14  		return 0, err
    15  	}
    16  	return rp.IntegerValue()
    17  }
    18  
    19  // PubSub doc: http://redis.io/topics/pubsub
    20  type PubSub struct {
    21  	redis *Redis
    22  	conn  *connection
    23  
    24  	Patterns map[string]bool
    25  	Channels map[string]bool
    26  }
    27  
    28  // GetName returns the address/name of the sentinel we are connected to
    29  func (p *PubSub) GetName() string {
    30  	return p.redis.GetName()
    31  }
    32  
    33  // PubSub new a PubSub from *redis.
    34  func (r *Redis) PubSub() (*PubSub, error) {
    35  	c, err := r.pool.Get()
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	return &PubSub{
    40  		redis:    r,
    41  		conn:     c,
    42  		Patterns: make(map[string]bool),
    43  		Channels: make(map[string]bool),
    44  	}, nil
    45  }
    46  
    47  // Close closes current pubsub command.
    48  func (p *PubSub) Close() error {
    49  	return p.conn.Conn.Close()
    50  }
    51  
    52  // Receive returns the reply of pubsub command.
    53  // A message is a Multi-bulk reply with three elements.
    54  // The first element is the kind of message:
    55  // 1) subscribe: means that we successfully subscribed to the channel given as the second element in the reply.
    56  // The third argument represents the number of channels we are currently subscribed to.
    57  // 2) unsubscribe: means that we successfully unsubscribed from the channel given as second element in the reply.
    58  // third argument represents the number of channels we are currently subscribed to.
    59  // When the last argument is zero, we are no longer subscribed to any channel,
    60  // and the client can issue any kind of Redis command as we are outside the Pub/Sub state.
    61  // 3) message: it is a message received as result of a PUBLISH command issued by another client.
    62  // The second element is the name of the originating channel, and the third argument is the actual message payload.
    63  func (p *PubSub) Receive() ([]string, error) {
    64  	rp, err := p.conn.RecvReply()
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	command, err := rp.Multi[0].StringValue()
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	switch strings.ToLower(command) {
    73  	case "psubscribe", "punsubscribe":
    74  		pattern, err := rp.Multi[1].StringValue()
    75  		if err != nil {
    76  			return nil, err
    77  		}
    78  		if command == "psubscribe" {
    79  			p.Patterns[pattern] = true
    80  		} else {
    81  			delete(p.Patterns, pattern)
    82  		}
    83  		number, err := rp.Multi[2].IntegerValue()
    84  		if err != nil {
    85  			return nil, err
    86  		}
    87  		return []string{command, pattern, strconv.FormatInt(number, 10)}, nil
    88  	case "subscribe", "unsubscribe":
    89  		channel, err := rp.Multi[1].StringValue()
    90  		if err != nil {
    91  			return nil, err
    92  		}
    93  		if command == "subscribe" {
    94  			p.Channels[channel] = true
    95  		} else {
    96  			delete(p.Channels, channel)
    97  		}
    98  		number, err := rp.Multi[2].IntegerValue()
    99  		if err != nil {
   100  			return nil, err
   101  		}
   102  		return []string{command, channel, strconv.FormatInt(number, 10)}, nil
   103  	case "pmessage":
   104  		pattern, err := rp.Multi[1].StringValue()
   105  		if err != nil {
   106  			return nil, err
   107  		}
   108  		channel, err := rp.Multi[2].StringValue()
   109  		if err != nil {
   110  			return nil, err
   111  		}
   112  		message, err := rp.Multi[3].StringValue()
   113  		if err != nil {
   114  			return nil, err
   115  		}
   116  		return []string{command, pattern, channel, message}, nil
   117  	case "message":
   118  		channel, err := rp.Multi[1].StringValue()
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  		message, err := rp.Multi[2].StringValue()
   123  		if err != nil {
   124  			return nil, err
   125  		}
   126  		return []string{command, channel, message}, nil
   127  	}
   128  	return nil, errors.New("pubsub protocol error")
   129  }
   130  
   131  // Subscribe channel [channel ...]
   132  func (p *PubSub) Subscribe(channels ...string) error {
   133  	args := packArgs("SUBSCRIBE", channels)
   134  	return p.conn.SendCommand(args...)
   135  }
   136  
   137  // PSubscribe pattern [pattern ...]
   138  func (p *PubSub) PSubscribe(patterns ...string) error {
   139  	args := packArgs("PSUBSCRIBE", patterns)
   140  	return p.conn.SendCommand(args...)
   141  }
   142  
   143  // UnSubscribe [channel [channel ...]]
   144  func (p *PubSub) UnSubscribe(channels ...string) error {
   145  	args := packArgs("UNSUBSCRIBE", channels)
   146  	return p.conn.SendCommand(args...)
   147  }
   148  
   149  // PUnSubscribe [pattern [pattern ...]]
   150  func (p *PubSub) PUnSubscribe(patterns ...string) error {
   151  	args := packArgs("PUNSUBSCRIBE", patterns)
   152  	return p.conn.SendCommand(args...)
   153  }