Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 13, 11:45 UTC
events: Make event data exported
This could lead to bugs if handlers are not careful, but it is surely useful. We'll see how it goes, what the feedback is like, etc.
Matthew Holt committed
Sep 19, 2022 at 16:20 UTC
0950ba4f0b77f2a9134188386345fccdfddb80ad
1 file changed
+28
-11
modules/caddyevents/app.go
+28
-11
@@ -201,6 +201,9 @@ func (app *App) On(eventName string, handler Handler) error {
201
// Emit creates and dispatches an event named eventName to all relevant handlers with
202
// the metadata data. Events are emitted and propagated synchronously. The returned Event
203
// value will have any additional information from the invoked handlers.
204
+//
205
+// Note that the data map is not copied, for efficiency. After Emit() is called, the
206
+// data passed in should not be changed in other goroutines.
207
func (app *App) Emit(ctx caddy.Context, eventName string, data map[string]any) Event {
208
logger := app.logger.With(zap.String("name", eventName))
209
@@ -212,11 +215,11 @@ func (app *App) Emit(ctx caddy.Context, eventName string, data map[string]any) E
215
eventName = strings.ToLower(eventName)
216
217
e := Event{
218
+ Data: data,
219
id: id,
220
ts: time.Now(),
221
name: eventName,
222
origin: ctx.Module(),
219
- data: data,
223
}
224
225
logger = logger.With(
@@ -244,12 +247,12 @@ func (app *App) Emit(ctx caddy.Context, eventName string, data map[string]any) E
247
case "event.module":
248
return e.origin.CaddyModule().ID, true
249
case "event.data":
247
- return e.data, true
250
+ return e.Data, true
251
}
252
253
if strings.HasPrefix(key, "event.data.") {
254
key = strings.TrimPrefix(key, "event.data.")
252
- if val, ok := data[key]; ok {
255
+ if val, ok := e.Data[key]; ok {
256
return val, true
257
}
258
}
@@ -257,7 +260,7 @@ func (app *App) Emit(ctx caddy.Context, eventName string, data map[string]any) E
260
return nil, false
261
})
262
260
- logger.Debug("event", zap.Any("data", e.data))
263
+ logger.Debug("event", zap.Any("data", e.Data))
264
265
// invoke handlers bound to the event by name and also all events; this for loop
266
// iterates twice at most: once for the event name, once for "" (all events)
@@ -314,26 +317,40 @@ func (app *App) Emit(ctx caddy.Context, eventName string, data map[string]any) E
317
}
318
319
// Event represents something that has happened or is happening.
320
+// An Event value is not synchronized, so it should be copied if
321
+// being used in goroutines.
322
+//
323
+// EXPERIMENTAL: As with the rest of this package, events are
324
+// subject to change.
325
type Event struct {
318
- id uuid.UUID
319
- ts time.Time
320
- name string
321
- origin caddy.Module
322
- data map[string]any
323
-
326
// If non-nil, the event has been aborted, meaning
327
// propagation has stopped to other handlers and
328
// the code should stop what it was doing. Emitters
329
// may choose to use this as a signal to adjust their
330
// code path appropriately.
331
Aborted error
332
+
333
+ // The data associated with the event. Usually the
334
+ // original emitter will be the only one to set or
335
+ // change these values, but the field is exported
336
+ // so handlers can have full access if needed.
337
+ // However, this map is not synchronized, so
338
+ // handlers must not use this map directly in new
339
+ // goroutines; instead, copy the map to use it in a
340
+ // goroutine.
341
+ Data map[string]any
342
+
343
+ id uuid.UUID
344
+ ts time.Time
345
+ name string
346
+ origin caddy.Module
347
}
348
349
// CloudEvent exports event e as a structure that, when
350
// serialized as JSON, is compatible with the
351
// CloudEvents spec.
352
func (e Event) CloudEvent() CloudEvent {
336
- dataJSON, _ := json.Marshal(e.data)
353
+ dataJSON, _ := json.Marshal(e.Data)
354
return CloudEvent{
355
ID: e.id.String(),
356
Source: e.origin.CaddyModule().String(),