forked from emojitracker/emojitrack-gostreamer
/
redis.go
104 lines (91 loc) · 2.91 KB
/
redis.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package main
import (
"github.com/garyburd/redigo/redis"
"log"
"time"
)
// it'd be nice to get rid of this and just use redis.Message generic interface
// ...but sigh Go: https://github.com/garyburd/redigo/issues/51
//
// let's just keep this and warp, even though there is some slight copy overhead
// probably, but it's better than having to have to have the rest of the code
// differentiate between structs based on where they originated.
// RedisMsg is our wrapper around redis.Message and redis.PMessage, since they
// really should be the same.
type RedisMsg struct {
channel string
data []byte
}
// direct copy from http://godoc.org/github.com/garyburd/redigo/redis#Pool
// why do we need to cut and paste code instead of having it be built-in
// to the package? because golang!
func newPool(server, password string) *redis.Pool {
return &redis.Pool{
MaxIdle: 3,
IdleTimeout: 240 * time.Second,
Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp", server)
if err != nil {
return nil, err
}
if password != "" {
if _, err := c.Do("AUTH", password); err != nil {
c.Close()
return nil, err
}
}
return c, err
},
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING")
return err
},
}
}
// this should make a global var we can access wherever?
var (
redisPool *redis.Pool
)
func initRedisPool() {
host, pass := envRedis()
redisPool = newPool(host, pass)
}
func myRedisSubscriptions() (<-chan RedisMsg, <-chan RedisMsg) {
// set up structures and channels to stream events out on
scoreUpdates := make(chan RedisMsg)
detailUpdates := make(chan RedisMsg)
// get a new redis connection from pool.
// since this is the first time the app tries to do something with redis,
// die if we can't get a valid connection, since something is probably
// configured wrong.
conn := redisPool.Get()
_, err := conn.Do("PING")
if err != nil {
log.Fatal("Could not connect to Redis, check your configuration.")
}
// subscribe to and handle streams
psc := redis.PubSubConn{conn}
psc.Subscribe("stream.score_updates")
psc.PSubscribe("stream.tweet_updates.*")
go func() {
for {
switch v := psc.Receive().(type) {
case redis.Message:
//fmt.Printf("%s: message: %s\n", v.Channel, v.Data)
scoreUpdates <- RedisMsg{v.Channel, v.Data} //string(v.Data)
case redis.PMessage:
//fmt.Printf("pattern: %s, channel: %s, data: %s\n", v.Pattern, v.Channel, v.Data)
//TODO: at some point we might need to also match the pattern here for kiosk mode
detailUpdates <- RedisMsg{v.Channel, v.Data}
case error:
log.Println("redis subscribe connection errored?@&*(#)akjd")
// probable cause is connection was closed, but force close just in case
conn.Close()
log.Println("attempting to get a new one in 5 seconds...")
time.Sleep(5 * time.Second)
conn = redisPool.Get()
}
}
}()
return scoreUpdates, detailUpdates
}