-
Notifications
You must be signed in to change notification settings - Fork 0
/
appconfig.go
152 lines (134 loc) · 3.81 KB
/
appconfig.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package moesifgin
import (
"encoding/json"
"io/ioutil"
"log"
"sync"
)
type AppConfig struct {
Mu sync.RWMutex
Updates chan string
eTags [2]string
config AppConfigResponse
}
func NewAppConfig() AppConfig {
return AppConfig{
Updates: make(chan string, 1),
config: NewAppConfigResponse(),
}
}
func (c *AppConfig) Read() AppConfigResponse {
c.Mu.RLock()
defer c.Mu.RUnlock()
return c.config
}
func (c *AppConfig) Write(config AppConfigResponse) {
c.Mu.Lock()
defer c.Mu.Unlock()
c.config = config
c.eTags[1] = c.eTags[0]
c.eTags[0] = config.eTag
}
func (c *AppConfig) Go() {
go c.UpdateLoop()
c.Notify("go")
}
func (c *AppConfig) Notify(eTag string) {
c.Mu.RLock()
e := c.eTags
c.Mu.RUnlock()
if eTag == "" || eTag == e[0] || eTag == e[1] {
return
}
select {
case c.Updates <- eTag:
default:
}
}
func (c *AppConfig) UpdateLoop() {
for {
eTag, more := <-c.Updates
if !more {
return
}
config, err := getAppConfig()
if err != nil {
log.Printf("Failed to get config: %v", err)
continue
}
log.Printf("AppConfig.Notify ETag=%s got /config response ETag=%s", eTag, config.eTag)
c.Write(config)
}
}
func (c *AppConfig) GetEntityValues(userId, companyId string) (userValues, companyValues []EntityRuleValues) {
config := c.Read()
return config.UserRules[userId], config.CompanyRules[companyId]
}
type AppConfigResponse struct {
OrgID string `json:"org_id"`
AppID string `json:"app_id"`
SampleRate int `json:"sample_rate"`
BlockBotTraffic bool `json:"block_bot_traffic"`
UserSampleRate map[string]int `json:"user_sample_rate"` // user id to a sample rate [0, 100]
CompanySampleRate map[string]int `json:"company_sample_rate"` // company id to a sample rate [0, 100]
UserRules map[string][]EntityRuleValues `json:"user_rules"` // user id to a rule id and template values
CompanyRules map[string][]EntityRuleValues `json:"company_rules"` // company id to a rule id and template values
IPAddressesBlockedByName map[string]string `json:"ip_addresses_blocked_by_name"`
RegexConfig []RegexRule `json:"regex_config"`
BillingConfigJsons map[string]string `json:"billing_config_jsons"`
eTag string
}
func NewAppConfigResponse() AppConfigResponse {
return AppConfigResponse{
SampleRate: 100,
}
}
// EntityRule is a user rule or company rule
type EntityRuleValues struct {
Rule string `json:"rules"`
Values map[string]string `json:"values"`
}
// Regex Rule
type RegexRule struct {
Conditions []RegexCondition `json:"conditions"`
SampleRate int `json:"sample_rate"`
}
// RegexCondition
type RegexCondition struct {
Path string `json:"path"`
Value string `json:"value"`
}
func getAppConfig() (config AppConfigResponse, err error) {
config = NewAppConfigResponse()
r, err := apiClient.GetAppConfig()
if err != nil {
log.Printf("Application configuration request error: %v", err)
return
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Printf("Application configuration response body read error: %v", err)
return
}
err = json.Unmarshal(body, &config)
if err != nil {
log.Printf("Application configuration response body malformed: %v", err)
return
}
config.eTag = r.Header.Get("X-Moesif-Config-Etag")
return
}
func getSamplingPercentage(userId string, companyId string) int {
c := appConfig.Read()
if userId != "" {
if userRate, ok := c.UserSampleRate[userId]; ok {
return userRate
}
}
if companyId != "" {
if companyRate, ok := c.CompanySampleRate[companyId]; ok {
return companyRate
}
}
return c.SampleRate
}