1// Copyright 2012 Gary Burd
2//
3// Licensed under the Apache License, Version 2.0 (the "License"): you may
4// not use this file except in compliance with the License. You may obtain
5// 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, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations
13// under the License.
14
15package redis
16
17import (
18	"errors"
19)
20
21// Subscription represents a subscribe or unsubscribe notification.
22type Subscription struct {
23
24	// Kind is "subscribe", "unsubscribe", "psubscribe" or "punsubscribe"
25	Kind string
26
27	// The channel that was changed.
28	Channel string
29
30	// The current number of subscriptions for connection.
31	Count int
32}
33
34// Message represents a message notification.
35type Message struct {
36
37	// The originating channel.
38	Channel string
39
40	// The message data.
41	Data []byte
42}
43
44// PMessage represents a pmessage notification.
45type PMessage struct {
46
47	// The matched pattern.
48	Pattern string
49
50	// The originating channel.
51	Channel string
52
53	// The message data.
54	Data []byte
55}
56
57// PubSubConn wraps a Conn with convenience methods for subscribers.
58type PubSubConn struct {
59	Conn Conn
60}
61
62// Close closes the connection.
63func (c PubSubConn) Close() error {
64	return c.Conn.Close()
65}
66
67// Subscribe subscribes the connection to the specified channels.
68func (c PubSubConn) Subscribe(channel ...interface{}) error {
69	c.Conn.Send("SUBSCRIBE", channel...)
70	return c.Conn.Flush()
71}
72
73// PSubscribe subscribes the connection to the given patterns.
74func (c PubSubConn) PSubscribe(channel ...interface{}) error {
75	c.Conn.Send("PSUBSCRIBE", channel...)
76	return c.Conn.Flush()
77}
78
79// Unsubscribe unsubscribes the connection from the given channels, or from all
80// of them if none is given.
81func (c PubSubConn) Unsubscribe(channel ...interface{}) error {
82	c.Conn.Send("UNSUBSCRIBE", channel...)
83	return c.Conn.Flush()
84}
85
86// PUnsubscribe unsubscribes the connection from the given patterns, or from all
87// of them if none is given.
88func (c PubSubConn) PUnsubscribe(channel ...interface{}) error {
89	c.Conn.Send("PUNSUBSCRIBE", channel...)
90	return c.Conn.Flush()
91}
92
93// Receive returns a pushed message as a Subscription, Message, PMessage or
94// error. The return value is intended to be used directly in a type switch as
95// illustrated in the PubSubConn example.
96func (c PubSubConn) Receive() interface{} {
97	reply, err := Values(c.Conn.Receive())
98	if err != nil {
99		return err
100	}
101
102	var kind string
103	reply, err = Scan(reply, &kind)
104	if err != nil {
105		return err
106	}
107
108	switch kind {
109	case "message":
110		var m Message
111		if _, err := Scan(reply, &m.Channel, &m.Data); err != nil {
112			return err
113		}
114		return m
115	case "pmessage":
116		var pm PMessage
117		if _, err := Scan(reply, &pm.Pattern, &pm.Channel, &pm.Data); err != nil {
118			return err
119		}
120		return pm
121	case "subscribe", "psubscribe", "unsubscribe", "punsubscribe":
122		s := Subscription{Kind: kind}
123		if _, err := Scan(reply, &s.Channel, &s.Count); err != nil {
124			return err
125		}
126		return s
127	}
128	return errors.New("redigo: unknown pubsub notification")
129}
130