-
-
Notifications
You must be signed in to change notification settings - Fork 156
/
component.go
130 lines (113 loc) · 3.51 KB
/
component.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
package esentinel
import (
"encoding/json"
"os"
"path/filepath"
"sync"
sentinelapi "github.com/alibaba/sentinel-golang/api"
sentinelconfig "github.com/alibaba/sentinel-golang/core/config"
"github.com/alibaba/sentinel-golang/core/flow"
"github.com/fsnotify/fsnotify"
"github.com/gotomicro/ego/core/elog"
)
// PackageName component name
const PackageName = "core.sentinel"
// Component defines component's configuration schema, name, logger, etc.
type Component struct {
// name string
// config *Config
// logger *elog.Component
// err error
}
var (
rMux = new(sync.RWMutex)
resMap = make(map[string]struct{})
)
func newComponent(config *Config, logger *elog.Component) error {
if config.FlowRulesFile != "" {
_ = syncFlowRules(config.FlowRulesFile, logger)
go watch(config.FlowRulesFile, logger)
}
configEntity := sentinelconfig.NewDefaultConfig()
configEntity.Sentinel.App.Name = config.AppName
configEntity.Sentinel.Log.Dir = config.LogPath
return sentinelapi.InitWithConfig(configEntity)
}
func syncFlowRules(filePath string, logger *elog.Component) (err error) {
var rules []*flow.Rule
content, err := os.ReadFile(filePath)
if err != nil {
logger.Error("load sentinel flow rules", elog.FieldErr(err), elog.FieldKey(filePath))
return err
}
if err := json.Unmarshal(content, &rules); err != nil {
logger.Error("load sentinel flow rules", elog.FieldErr(err), elog.FieldKey(filePath))
return err
}
if len(rules) > 0 {
_, _ = flow.LoadRules(rules)
addResMap(rules)
}
return nil
}
func watch(filePath string, logger *elog.Component) {
absolutePath, err := filepath.Abs(filePath)
if err != nil {
elog.Panic("new datasource", elog.FieldErr(err))
}
// dir := xfile.CheckAndGetParentDir(absolutePath)
w, err := fsnotify.NewWatcher()
if err != nil {
logger.Panic("new sentinel file watcher", elog.FieldErr(err))
}
defer w.Close()
configFile := filepath.Clean(absolutePath)
realConfigFile, _ := filepath.EvalSymlinks(absolutePath)
done := make(chan bool)
go func() {
for {
select {
case event := <-w.Events:
currentConfigFile, _ := filepath.EvalSymlinks(absolutePath)
logger.Info("read sentinel watch event",
elog.String("event", filepath.Clean(event.Name)),
elog.String("path", filepath.Clean(absolutePath)),
elog.String("currentConfigFile", currentConfigFile),
elog.String("realConfigFile", realConfigFile),
)
// we only care about the config file with the following cases:
// 1 - if the config file was modified or created
// 2 - if the real path to the config file changed (eg: k8s ConfigMap replacement)
const writeOrCreateMask = fsnotify.Write | fsnotify.Create
if (filepath.Clean(event.Name) == configFile &&
event.Op&writeOrCreateMask != 0) ||
(currentConfigFile != "" && currentConfigFile != realConfigFile) {
realConfigFile = currentConfigFile
logger.Info("modified sentinel file", elog.FieldName(event.Name), elog.FieldAddr(realConfigFile))
_ = syncFlowRules(realConfigFile, logger)
}
case err := <-w.Errors:
logger.Error("read watch error", elog.FieldComponent("file datasource"), elog.FieldErr(err))
}
}
}()
err = w.Add(absolutePath)
if err != nil {
logger.Panic("dir err", elog.FieldErr(err))
}
<-done
}
func addResMap(rules []*flow.Rule) {
rMux.Lock()
defer rMux.Unlock()
for _, r := range rules {
resMap[r.Resource] = struct{}{}
}
}
// IsResExist check if a resource exists
func IsResExist(res string) bool {
rMux.RLock()
defer rMux.RUnlock()
_, exist := resMap[res]
return exist
}