10
"time"
11
)
12
13
-var currentCfg *Config
14
-var currentCfgMu sync.Mutex
15
-
13
// Start runs Caddy with the given config.
14
func Start(cfg Config) error {
15
+ // allow only one call to Start at a time,
16
+ // since various calls to LoadModule()
17
+ // access shared map moduleInstances
18
+ startMu.Lock()
19
+ defer startMu.Unlock()
20
+
21
+ // prepare the config for use
22
cfg.runners = make(map[string]Runner)
23
+ cfg.moduleStates = make(map[string]interface{})
24
+
25
+ // reset the shared moduleInstances map; but
26
+ // keep a temporary reference to the current
27
+ // one so we can transfer over any necessary
28
+ // state to the new modules; or in case this
29
+ // function returns an error, we need to put
30
+ // the "old" one back where we found it
31
+ var err error
32
+ oldModuleInstances := moduleInstances
33
+ defer func() {
34
+ if err != nil {
35
+ moduleInstances = oldModuleInstances
36
+ }
37
+ }()
38
+ moduleInstances = make(map[string][]interface{})
39
40
+ // load (decode) each runner module
41
for modName, rawMsg := range cfg.Modules {
42
val, err := LoadModule(modName, rawMsg)
43
if err != nil {
55
}
56
}
57
37
- // shut down down the old ones
58
+ // shut down down the old runners
59
currentCfgMu.Lock()
60
if currentCfg != nil {
40
- for _, r := range currentCfg.runners {
61
+ for name, r := range currentCfg.runners {
62
err := r.Cancel()
63
if err != nil {
43
- log.Println(err)
64
+ log.Printf("[ERROR] cancel %s: %v", name, err)
65
}
66
}
67
}
68
+ oldCfg := currentCfg
69
currentCfg = &cfg
70
currentCfgMu.Unlock()
71
72
+ // invoke unload callbacks on old configuration
73
+ for modName := range oldModuleInstances {
74
+ mod, err := GetModule(modName)
75
+ if err != nil {
76
+ return err
77
+ }
78
+ if mod.OnUnload != nil {
79
+ var unloadingState interface{}
80
+ if oldCfg != nil {
81
+ unloadingState = oldCfg.moduleStates[modName]
82
+ }
83
+ err := mod.OnUnload(unloadingState)
84
+ if err != nil {
85
+ log.Printf("[ERROR] module OnUnload: %s: %v", modName, err)
86
+ continue
87
+ }
88
+ }
89
+ }
90
+
91
+ // invoke load callbacks on new configuration
92
+ for modName, instances := range moduleInstances {
93
+ mod, err := GetModule(modName)
94
+ if err != nil {
95
+ return err
96
+ }
97
+ if mod.OnLoad != nil {
98
+ var priorState interface{}
99
+ if oldCfg != nil {
100
+ priorState = oldCfg.moduleStates[modName]
101
+ }
102
+ modState, err := mod.OnLoad(instances, priorState)
103
+ if err != nil {
104
+ return fmt.Errorf("module OnLoad: %s: %v", modName, err)
105
+ }
106
+ if modState != nil {
107
+ cfg.moduleStates[modName] = modState
108
+ }
109
+ }
110
+ }
111
+
112
// shut down listeners that are no longer being used
113
listenersMu.Lock()
114
for key, info := range listeners {
136
type Config struct {
137
TestVal string `json:"testval"`
138
Modules map[string]json.RawMessage `json:"modules"`
139
+
140
+ // runners stores the decoded Modules values,
141
+ // keyed by module name.
142
runners map[string]Runner
143
+
144
+ // moduleStates stores the optional "global" state
145
+ // values of every module used by this configuration,
146
+ // keyed by module name.
147
+ moduleStates map[string]interface{}
148
}
149
150
// Duration is a JSON-string-unmarshable duration type.
165
func (d Duration) MarshalJSON() ([]byte, error) {
166
return []byte(fmt.Sprintf(`"%s"`, time.Duration(d).String())), nil
167
}
168
+
169
+// currentCfg is the currently-loaded configuration.
170
+var (
171
+ currentCfg *Config
172
+ currentCfgMu sync.Mutex
173
+)
174
+
175
+// moduleInstances stores the individual instantiated
176
+// values of modules, keyed by module name. The list
177
+// of instances of each module get passed into the
178
+// respective module's OnLoad callback, so they can
179
+// set up any global state and/or make sure their
180
+// configuration, when viewed as a whole, is valid.
181
+// Since this list is shared, only one Start() routine
182
+// must be allowed to happen at any given time.
183
+var moduleInstances = make(map[string][]interface{})
184
+
185
+// startMu ensures that only one Start() happens at a time.
186
+// This is important since
187
+var startMu sync.Mutex