func (c *PubSub) ReceiveMessage() (*Message, error) {
	return c.receiveMessage(5 * time.Second)
}
ReceiveMessage returns a Message or error ignoring Subscription or Pong
messages. It automatically reconnects to Redis Server and resubscribes
to channels in case of network errors.
package redis
import (
	"fmt"
	"net"
	"sync"
	"time"
	"gopkg.in/redis.v5/internal"
	"gopkg.in/redis.v5/internal/pool"
)
type PubSub struct {
	base baseClient
	cmd  *Cmd
	mu       sync.Mutex
	channels []string
	patterns []string
}
func (c *PubSub) conn() (*pool.Conn, bool, error) {
	cn, isNew, err := c.base.conn()
	if err != nil {
		return nil, false, err
	}
	if isNew {
		c.resubscribe()
	}
	return cn, isNew, nil
}
func (c *PubSub) putConn(cn *pool.Conn, err error) {
	c.base.putConn(cn, err, true)
}
func (c *PubSub) subscribe(redisCmd string, channels ...string) error {
	args := make([]interface{}, 1+len(channels))
	args[0] = redisCmd
	for i, channel := range channels {
		args[1+i] = channel
	}
	cmd := NewSliceCmd(args...)
	cn, _, err := c.conn()
	if err != nil {
		return err
	}
	cn.SetWriteTimeout(c.base.opt.WriteTimeout)
	err = writeCmd(cn, cmd)
	c.putConn(cn, err)
	return err
}
func (c *PubSub) Subscribe(channels ...string) error {
	err := c.subscribe("SUBSCRIBE", channels...)
	if err == nil {
		c.channels = appendIfNotExists(c.channels, channels...)
	}
	return err
}
func (c *PubSub) PSubscribe(patterns ...string) error {
	err := c.subscribe("PSUBSCRIBE", patterns...)
	if err == nil {
		c.patterns = appendIfNotExists(c.patterns, patterns...)
	}
	return err
}
func (c *PubSub) Unsubscribe(channels ...string) error {
	err := c.subscribe("UNSUBSCRIBE", channels...)
	if err == nil {
		c.channels = remove(c.channels, channels...)
	}
	return err
}
func (c *PubSub) PUnsubscribe(patterns ...string) error {
	err := c.subscribe("PUNSUBSCRIBE", patterns...)
	if err == nil {
		c.patterns = remove(c.patterns, patterns...)
	}
	return err
}
func (c *PubSub) Close() error {
	return c.base.Close()
}
func (c *PubSub) Ping(payload ...string) error {
	args := []interface{}{"PING"}
	if len(payload) == 1 {
		args = append(args, payload[0])
	}
	cmd := NewCmd(args...)
	cn, _, err := c.conn()
	if err != nil {
		return err
	}
	cn.SetWriteTimeout(c.base.opt.WriteTimeout)
	err = writeCmd(cn, cmd)
	c.putConn(cn, err)
	return err
}
type Subscription struct {
	Kind string
	Channel string
	Count int
}
func (m *Subscription) String() string {
	return fmt.Sprintf("%s: %s", m.Kind, m.Channel)
}
type Message struct {
	Channel string
	Pattern string
	Payload string
}
func (m *Message) String() string {
	return fmt.Sprintf("Message<%s: %s>", m.Channel, m.Payload)
}
type Pong struct {
	Payload string
}
func (p *Pong) String() string {
	if p.Payload != "" {
		return fmt.Sprintf("Pong<%s>", p.Payload)
	}
	return "Pong"
}
func (c *PubSub) newMessage(reply interface{}) (interface{}, error) {
	switch reply := reply.(type) {
	case string:
		return &Pong{
			Payload: reply,
		}, nil
	case []interface{}:
		switch kind := reply[0].(string); kind {
		case "subscribe", "unsubscribe", "psubscribe", "punsubscribe":
			return &Subscription{
				Kind:    kind,
				Channel: reply[1].(string),
				Count:   int(reply[2].(int64)),
			}, nil
		case "message":
			return &Message{
				Channel: reply[1].(string),
				Payload: reply[2].(string),
			}, nil
		case "pmessage":
			return &Message{
				Pattern: reply[1].(string),
				Channel: reply[2].(string),
				Payload: reply[3].(string),
			}, nil
		case "pong":
			return &Pong{
				Payload: reply[1].(string),
			}, nil
		default:
			return nil, fmt.Errorf("redis: unsupported pubsub message: %q", kind)
		}
	default:
		return nil, fmt.Errorf("redis: unsupported pubsub message: %#v", reply)
	}
}
func (c *PubSub) ReceiveTimeout(timeout time.Duration) (interface{}, error) {
	if c.cmd == nil {
		c.cmd = NewCmd()
	}
	cn, _, err := c.conn()
	if err != nil {
		return nil, err
	}
	cn.SetReadTimeout(timeout)
	err = c.cmd.readReply(cn)
	c.putConn(cn, err)
	if err != nil {
		return nil, err
	}
	return c.newMessage(c.cmd.Val())
}
func (c *PubSub) Receive() (interface{}, error) {
	return c.ReceiveTimeout(0)
}