diff options
author | Matthew Holt <mholt@users.noreply.github.com> | 2022-09-19 16:20:58 -0600 |
---|---|---|
committer | Matthew Holt <mholt@users.noreply.github.com> | 2022-09-19 16:20:58 -0600 |
commit | 0950ba4f0b77f2a9134188386345fccdfddb80ad (patch) | |
tree | b6d3dadd8652c3159db8cbad10e417d0a6c55deb | |
parent | c7a6bc59345ca4075cc8bf97bd80900d28d8e05d (diff) |
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.
-rw-r--r-- | modules/caddyevents/app.go | 39 |
1 files changed, 28 insertions, 11 deletions
diff --git a/modules/caddyevents/app.go b/modules/caddyevents/app.go index db2192c..6b10460 100644 --- a/modules/caddyevents/app.go +++ b/modules/caddyevents/app.go @@ -201,6 +201,9 @@ func (app *App) On(eventName string, handler Handler) error { // Emit creates and dispatches an event named eventName to all relevant handlers with // the metadata data. Events are emitted and propagated synchronously. The returned Event // value will have any additional information from the invoked handlers. +// +// Note that the data map is not copied, for efficiency. After Emit() is called, the +// data passed in should not be changed in other goroutines. func (app *App) Emit(ctx caddy.Context, eventName string, data map[string]any) Event { logger := app.logger.With(zap.String("name", eventName)) @@ -212,11 +215,11 @@ func (app *App) Emit(ctx caddy.Context, eventName string, data map[string]any) E eventName = strings.ToLower(eventName) e := Event{ + Data: data, id: id, ts: time.Now(), name: eventName, origin: ctx.Module(), - data: data, } logger = logger.With( @@ -244,12 +247,12 @@ func (app *App) Emit(ctx caddy.Context, eventName string, data map[string]any) E case "event.module": return e.origin.CaddyModule().ID, true case "event.data": - return e.data, true + return e.Data, true } if strings.HasPrefix(key, "event.data.") { key = strings.TrimPrefix(key, "event.data.") - if val, ok := data[key]; ok { + if val, ok := e.Data[key]; ok { return val, true } } @@ -257,7 +260,7 @@ func (app *App) Emit(ctx caddy.Context, eventName string, data map[string]any) E return nil, false }) - logger.Debug("event", zap.Any("data", e.data)) + logger.Debug("event", zap.Any("data", e.Data)) // invoke handlers bound to the event by name and also all events; this for loop // 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 } // Event represents something that has happened or is happening. +// An Event value is not synchronized, so it should be copied if +// being used in goroutines. +// +// EXPERIMENTAL: As with the rest of this package, events are +// subject to change. type Event struct { - id uuid.UUID - ts time.Time - name string - origin caddy.Module - data map[string]any - // If non-nil, the event has been aborted, meaning // propagation has stopped to other handlers and // the code should stop what it was doing. Emitters // may choose to use this as a signal to adjust their // code path appropriately. Aborted error + + // The data associated with the event. Usually the + // original emitter will be the only one to set or + // change these values, but the field is exported + // so handlers can have full access if needed. + // However, this map is not synchronized, so + // handlers must not use this map directly in new + // goroutines; instead, copy the map to use it in a + // goroutine. + Data map[string]any + + id uuid.UUID + ts time.Time + name string + origin caddy.Module } // CloudEvent exports event e as a structure that, when // serialized as JSON, is compatible with the // CloudEvents spec. func (e Event) CloudEvent() CloudEvent { - dataJSON, _ := json.Marshal(e.data) + dataJSON, _ := json.Marshal(e.Data) return CloudEvent{ ID: e.id.String(), Source: e.origin.CaddyModule().String(), |