@@ -81,13 +81,14 @@ type Config struct {
81
81
// associated value.
82
82
AppsRaw ModuleMap `json:"apps,omitempty" caddy:"namespace="`
83
83
84
- apps map [string ]App
85
- storage certmagic.Storage
84
+ apps map [string ]App
85
+ storage certmagic.Storage
86
+ eventEmitter eventEmitter
86
87
87
88
cancelFunc context.CancelFunc
88
89
89
- // filesystems is a dict of filesystems that will later be loaded from and added to.
90
- filesystems FileSystems
90
+ // fileSystems is a dict of fileSystems that will later be loaded from and added to.
91
+ fileSystems FileSystems
91
92
}
92
93
93
94
// App is a thing that Caddy runs.
@@ -442,6 +443,10 @@ func run(newCfg *Config, start bool) (Context, error) {
442
443
}
443
444
globalMetrics .configSuccess .Set (1 )
444
445
globalMetrics .configSuccessTime .SetToCurrentTime ()
446
+
447
+ // TODO: This event is experimental and subject to change.
448
+ ctx .emitEvent ("started" , nil )
449
+
445
450
// now that the user's config is running, finish setting up anything else,
446
451
// such as remote admin endpoint, config loader, etc.
447
452
return ctx , finishSettingUp (ctx , ctx .cfg )
@@ -509,7 +514,7 @@ func provisionContext(newCfg *Config, replaceAdminServer bool) (Context, error)
509
514
}
510
515
511
516
// create the new filesystem map
512
- newCfg .filesystems = & filesystems.FilesystemMap {}
517
+ newCfg .fileSystems = & filesystems.FileSystemMap {}
513
518
514
519
// prepare the new config for use
515
520
newCfg .apps = make (map [string ]App )
@@ -696,6 +701,9 @@ func unsyncedStop(ctx Context) {
696
701
return
697
702
}
698
703
704
+ // TODO: This event is experimental and subject to change.
705
+ ctx .emitEvent ("stopping" , nil )
706
+
699
707
// stop each app
700
708
for name , a := range ctx .cfg .apps {
701
709
err := a .Stop ()
@@ -1038,6 +1046,92 @@ func Version() (simple, full string) {
1038
1046
return
1039
1047
}
1040
1048
1049
+ // Event represents something that has happened or is happening.
1050
+ // An Event value is not synchronized, so it should be copied if
1051
+ // being used in goroutines.
1052
+ //
1053
+ // EXPERIMENTAL: Events are subject to change.
1054
+ type Event struct {
1055
+ // If non-nil, the event has been aborted, meaning
1056
+ // propagation has stopped to other handlers and
1057
+ // the code should stop what it was doing. Emitters
1058
+ // may choose to use this as a signal to adjust their
1059
+ // code path appropriately.
1060
+ Aborted error
1061
+
1062
+ // The data associated with the event. Usually the
1063
+ // original emitter will be the only one to set or
1064
+ // change these values, but the field is exported
1065
+ // so handlers can have full access if needed.
1066
+ // However, this map is not synchronized, so
1067
+ // handlers must not use this map directly in new
1068
+ // goroutines; instead, copy the map to use it in a
1069
+ // goroutine. Data may be nil.
1070
+ Data map [string ]any
1071
+
1072
+ id uuid.UUID
1073
+ ts time.Time
1074
+ name string
1075
+ origin Module
1076
+ }
1077
+
1078
+ // NewEvent creates a new event, but does not emit the event. To emit an
1079
+ // event, call Emit() on the current instance of the caddyevents app insteaad.
1080
+ //
1081
+ // EXPERIMENTAL: Subject to change.
1082
+ func NewEvent (ctx Context , name string , data map [string ]any ) (Event , error ) {
1083
+ id , err := uuid .NewRandom ()
1084
+ if err != nil {
1085
+ return Event {}, fmt .Errorf ("generating new event ID: %v" , err )
1086
+ }
1087
+ name = strings .ToLower (name )
1088
+ return Event {
1089
+ Data : data ,
1090
+ id : id ,
1091
+ ts : time .Now (),
1092
+ name : name ,
1093
+ origin : ctx .Module (),
1094
+ }, nil
1095
+ }
1096
+
1097
+ func (e Event ) ID () uuid.UUID { return e .id }
1098
+ func (e Event ) Timestamp () time.Time { return e .ts }
1099
+ func (e Event ) Name () string { return e .name }
1100
+ func (e Event ) Origin () Module { return e .origin } // Returns the module that originated the event. May be nil, usually if caddy core emits the event.
1101
+
1102
+ // CloudEvent exports event e as a structure that, when
1103
+ // serialized as JSON, is compatible with the
1104
+ // CloudEvents spec.
1105
+ func (e Event ) CloudEvent () CloudEvent {
1106
+ dataJSON , _ := json .Marshal (e .Data )
1107
+ return CloudEvent {
1108
+ ID : e .id .String (),
1109
+ Source : e .origin .CaddyModule ().String (),
1110
+ SpecVersion : "1.0" ,
1111
+ Type : e .name ,
1112
+ Time : e .ts ,
1113
+ DataContentType : "application/json" ,
1114
+ Data : dataJSON ,
1115
+ }
1116
+ }
1117
+
1118
+ // CloudEvent is a JSON-serializable structure that
1119
+ // is compatible with the CloudEvents specification.
1120
+ // See https://cloudevents.io.
1121
+ // EXPERIMENTAL: Subject to change.
1122
+ type CloudEvent struct {
1123
+ ID string `json:"id"`
1124
+ Source string `json:"source"`
1125
+ SpecVersion string `json:"specversion"`
1126
+ Type string `json:"type"`
1127
+ Time time.Time `json:"time"`
1128
+ DataContentType string `json:"datacontenttype,omitempty"`
1129
+ Data json.RawMessage `json:"data,omitempty"`
1130
+ }
1131
+
1132
+ // ErrEventAborted cancels an event.
1133
+ var ErrEventAborted = errors .New ("event aborted" )
1134
+
1041
1135
// ActiveContext returns the currently-active context.
1042
1136
// This function is experimental and might be changed
1043
1137
// or removed in the future.
0 commit comments