/
proxy.go
135 lines (123 loc) · 2.6 KB
/
proxy.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main
import (
"github.com/simonz05/godis/redis"
"log"
"net/http"
"net/http/httputil"
)
const (
NORMAL = iota
MIGRATION
CLEANUP
)
var (
DefaultHost = "localhost:3456"
OldHost = "localhost:3457"
RunningDefault = true
)
func main() {
director := func(req *http.Request) {
req.URL.Scheme = "http"
switch {
case RunningDefault:
req.URL.Host = DefaultHost
case LegacyPort(req):
req.URL.Host = OldHost
default:
req.URL.Host = DefaultHost
}
}
proxy := &httputil.ReverseProxy{Director: director}
go RedisChecker()
log.Fatal(http.ListenAndServe(":5799", proxy))
}
func LegacyPort(req *http.Request) bool {
return false
}
func RedisChecker() {
ctx := ConnectToRedis()
ctx.SetupWatcher()
ctx.Watch()
}
func ConnectToRedis() *RedisContext {
rc := new(RedisContext)
rc.Conn = redis.New("tcp:127.0.0.1:6379", 0, "")
status_type, err := rc.Conn.Type("migration_status")
if err != nil {
switch status_type {
case "string":
status, err := rc.Conn.Get("migration_status")
if err == nil {
rc.State = DecodeStatus(status.String())
} else {
log.Println("Could not get migration_status value, assuming normal")
rc.State = NORMAL
}
default:
log.Printf("Could not ascertain migration_status type (unknown type %s), assuming Normal", status_type)
}
} else {
log.Println("Could not ascertain migration_status type due to error, assuming Normal")
rc.State = NORMAL
}
return rc
}
type RedisContext struct {
Conn *redis.Client
Sub *redis.Sub
State int
}
func (rc *RedisContext) SetupWatcher() {
sub, err := rc.Conn.Subscribe("migrations")
if err == nil {
rc.Sub = sub
} else {
log.Fatal("Redis could not subscribe, is Redis started?")
}
}
func (rc *RedisContext) Watch() {
var change *redis.Message
select {
case change = <-rc.Sub.Messages:
switch rc.State {
case NORMAL:
switch DecodeStatus(change.Elem.String()) {
case MIGRATION:
RunningDefault = false
rc.State = MIGRATION
case CLEANUP:
RunningDefault = true
rc.State = CLEANUP
}
case MIGRATION:
switch DecodeStatus(change.Elem.String()) {
case NORMAL:
RunningDefault = true
rc.State = NORMAL
case CLEANUP:
RunningDefault = true
rc.State = CLEANUP
}
case CLEANUP:
switch DecodeStatus(change.Elem.String()) {
case MIGRATION:
RunningDefault = false
rc.State = MIGRATION
case NORMAL:
RunningDefault = true
rc.State = NORMAL
}
}
}
}
func DecodeStatus(status string) int {
switch status {
case "normal":
return NORMAL
case "migration":
return MIGRATION
case "cleanup":
return CLEANUP
}
return NORMAL
}