| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- package fiber
- import (
- "slices"
- "github.com/gofiber/fiber/v3/log"
- )
- type (
- // OnRouteHandler defines the hook signature invoked whenever a route is registered.
- OnRouteHandler = func(Route) error
- // OnNameHandler shares the OnRouteHandler signature for route naming callbacks.
- OnNameHandler = OnRouteHandler
- // OnGroupHandler defines the hook signature invoked whenever a group is registered.
- OnGroupHandler = func(Group) error
- // OnGroupNameHandler shares the OnGroupHandler signature for group naming callbacks.
- OnGroupNameHandler = OnGroupHandler
- // OnListenHandler runs when the application begins listening and receives the listener details.
- OnListenHandler = func(ListenData) error
- // OnPreStartupMessageHandler runs before Fiber prints the startup banner.
- OnPreStartupMessageHandler = func(*PreStartupMessageData) error
- // OnPostStartupMessageHandler runs after Fiber prints (or skips) the startup banner.
- OnPostStartupMessageHandler = func(*PostStartupMessageData) error
- // OnPreShutdownHandler runs before the application shuts down.
- OnPreShutdownHandler = func() error
- // OnPostShutdownHandler runs after shutdown and receives the shutdown result.
- OnPostShutdownHandler = func(error) error
- // OnForkHandler runs inside a forked worker process and receives the worker ID.
- OnForkHandler = func(int) error
- // OnMountHandler runs after a sub-application mounts to a parent and receives the parent app reference.
- OnMountHandler = func(*App) error
- )
- // Hooks is a struct to use it with App.
- type Hooks struct {
- // Embed app
- app *App
- // Hooks
- onRoute []OnRouteHandler
- onName []OnNameHandler
- onGroup []OnGroupHandler
- onGroupName []OnGroupNameHandler
- onListen []OnListenHandler
- onPreStartup []OnPreStartupMessageHandler
- onPostStartup []OnPostStartupMessageHandler
- onPreShutdown []OnPreShutdownHandler
- onPostShutdown []OnPostShutdownHandler
- onFork []OnForkHandler
- onMount []OnMountHandler
- }
- type StartupMessageLevel int
- const (
- // StartupMessageLevelInfo represents informational startup message entries.
- StartupMessageLevelInfo StartupMessageLevel = iota
- // StartupMessageLevelWarning represents warning startup message entries.
- StartupMessageLevelWarning
- // StartupMessageLevelError represents error startup message entries.
- StartupMessageLevelError
- )
- const errString = "ERROR"
- // startupMessageEntry represents a single line of startup message information.
- type startupMessageEntry struct {
- key string
- title string
- value string
- priority int
- level StartupMessageLevel
- }
- // ListenData contains the listener metadata provided to OnListenHandler.
- type ListenData struct {
- ColorScheme Colors
- Host string
- Port string
- Version string
- AppName string
- ChildPIDs []int
- HandlerCount int
- ProcessCount int
- PID int
- TLS bool
- Prefork bool
- }
- // PreStartupMessageData contains metadata exposed to OnPreStartupMessage hooks.
- type PreStartupMessageData struct {
- *ListenData
- // BannerHeader allows overriding the ASCII art banner displayed at startup.
- BannerHeader string
- entries []startupMessageEntry
- // PreventDefault, when set to true, suppresses the default startup message.
- PreventDefault bool
- }
- // AddInfo adds an informational entry to the startup message with "INFO" label.
- func (sm *PreStartupMessageData) AddInfo(key, title, value string, priority ...int) {
- pri := -1
- if len(priority) > 0 {
- pri = priority[0]
- }
- sm.addEntry(key, title, value, pri, StartupMessageLevelInfo)
- }
- // AddWarning adds a warning entry to the startup message with "WARNING" label.
- func (sm *PreStartupMessageData) AddWarning(key, title, value string, priority ...int) {
- pri := -1
- if len(priority) > 0 {
- pri = priority[0]
- }
- sm.addEntry(key, title, value, pri, StartupMessageLevelWarning)
- }
- // AddError adds an error entry to the startup message with "ERROR" label.
- func (sm *PreStartupMessageData) AddError(key, title, value string, priority ...int) {
- pri := -1
- if len(priority) > 0 {
- pri = priority[0]
- }
- sm.addEntry(key, title, value, pri, StartupMessageLevelError)
- }
- // EntryKeys returns all entry keys currently present in the startup message.
- func (sm *PreStartupMessageData) EntryKeys() []string {
- keys := make([]string, 0, len(sm.entries))
- for _, entry := range sm.entries {
- keys = append(keys, entry.key)
- }
- return keys
- }
- // ResetEntries removes all existing entries from the startup message.
- func (sm *PreStartupMessageData) ResetEntries() {
- sm.entries = sm.entries[:0]
- }
- // DeleteEntry removes a specific entry from the startup message by its key.
- func (sm *PreStartupMessageData) DeleteEntry(key string) {
- if sm.entries == nil {
- return
- }
- for i, entry := range sm.entries {
- if entry.key == key {
- sm.entries = append(sm.entries[:i], sm.entries[i+1:]...)
- return
- }
- }
- }
- func (sm *PreStartupMessageData) addEntry(key, title, value string, priority int, level StartupMessageLevel) {
- if sm.entries == nil {
- sm.entries = make([]startupMessageEntry, 0, 8)
- }
- for i, entry := range sm.entries {
- if entry.key != key {
- continue
- }
- sm.entries[i].value = value
- sm.entries[i].title = title
- sm.entries[i].level = level
- sm.entries[i].priority = priority
- return
- }
- sm.entries = append(sm.entries, startupMessageEntry{
- key: key,
- title: title,
- value: value,
- priority: priority,
- level: level,
- })
- }
- func newPreStartupMessageData(listenData *ListenData) *PreStartupMessageData {
- return &PreStartupMessageData{ListenData: listenData}
- }
- // PostStartupMessageData contains metadata exposed to OnPostStartupMessage hooks.
- type PostStartupMessageData struct {
- *ListenData
- // Disabled indicates whether the startup message was disabled via configuration.
- Disabled bool
- // IsChild indicates whether the current process is a child in prefork mode.
- IsChild bool
- // Prevented indicates whether the startup message was suppressed by a pre-startup hook using PreventDefault property.
- Prevented bool
- }
- func newPostStartupMessageData(listenData *ListenData, disabled, isChild, prevented bool) *PostStartupMessageData {
- clone := *listenData
- if len(listenData.ChildPIDs) > 0 {
- clone.ChildPIDs = slices.Clone(listenData.ChildPIDs)
- }
- return &PostStartupMessageData{
- ListenData: &clone,
- Disabled: disabled,
- IsChild: isChild,
- Prevented: prevented,
- }
- }
- func newHooks(app *App) *Hooks {
- return &Hooks{
- app: app,
- onRoute: make([]OnRouteHandler, 0),
- onGroup: make([]OnGroupHandler, 0),
- onGroupName: make([]OnGroupNameHandler, 0),
- onName: make([]OnNameHandler, 0),
- onListen: make([]OnListenHandler, 0),
- onPreStartup: make([]OnPreStartupMessageHandler, 0),
- onPostStartup: make([]OnPostStartupMessageHandler, 0),
- onPreShutdown: make([]OnPreShutdownHandler, 0),
- onPostShutdown: make([]OnPostShutdownHandler, 0),
- onFork: make([]OnForkHandler, 0),
- onMount: make([]OnMountHandler, 0),
- }
- }
- // OnRoute is a hook to execute user functions on each route registration.
- // Also you can get route properties by route parameter.
- func (h *Hooks) OnRoute(handler ...OnRouteHandler) {
- h.app.mutex.Lock()
- h.onRoute = append(h.onRoute, handler...)
- h.app.mutex.Unlock()
- }
- // OnName is a hook to execute user functions on each route naming.
- // Also you can get route properties by route parameter.
- //
- // WARN: OnName only works with naming routes, not groups.
- func (h *Hooks) OnName(handler ...OnNameHandler) {
- h.app.mutex.Lock()
- h.onName = append(h.onName, handler...)
- h.app.mutex.Unlock()
- }
- // OnGroup is a hook to execute user functions on each group registration.
- // Also you can get group properties by group parameter.
- func (h *Hooks) OnGroup(handler ...OnGroupHandler) {
- h.app.mutex.Lock()
- h.onGroup = append(h.onGroup, handler...)
- h.app.mutex.Unlock()
- }
- // OnGroupName is a hook to execute user functions on each group naming.
- // Also you can get group properties by group parameter.
- //
- // WARN: OnGroupName only works with naming groups, not routes.
- func (h *Hooks) OnGroupName(handler ...OnGroupNameHandler) {
- h.app.mutex.Lock()
- h.onGroupName = append(h.onGroupName, handler...)
- h.app.mutex.Unlock()
- }
- // OnListen is a hook to execute user functions on Listen or Listener.
- func (h *Hooks) OnListen(handler ...OnListenHandler) {
- h.app.mutex.Lock()
- h.onListen = append(h.onListen, handler...)
- h.app.mutex.Unlock()
- }
- // OnPreStartupMessage is a hook to execute user functions before the startup message is printed.
- func (h *Hooks) OnPreStartupMessage(handler ...OnPreStartupMessageHandler) {
- h.app.mutex.Lock()
- h.onPreStartup = append(h.onPreStartup, handler...)
- h.app.mutex.Unlock()
- }
- // OnPostStartupMessage is a hook to execute user functions after the startup message is printed (or skipped).
- func (h *Hooks) OnPostStartupMessage(handler ...OnPostStartupMessageHandler) {
- h.app.mutex.Lock()
- h.onPostStartup = append(h.onPostStartup, handler...)
- h.app.mutex.Unlock()
- }
- // OnPreShutdown is a hook to execute user functions before Shutdown.
- func (h *Hooks) OnPreShutdown(handler ...OnPreShutdownHandler) {
- h.app.mutex.Lock()
- h.onPreShutdown = append(h.onPreShutdown, handler...)
- h.app.mutex.Unlock()
- }
- // OnPostShutdown is a hook to execute user functions after Shutdown.
- func (h *Hooks) OnPostShutdown(handler ...OnPostShutdownHandler) {
- h.app.mutex.Lock()
- h.onPostShutdown = append(h.onPostShutdown, handler...)
- h.app.mutex.Unlock()
- }
- // OnFork is a hook to execute user function after fork process.
- func (h *Hooks) OnFork(handler ...OnForkHandler) {
- h.app.mutex.Lock()
- h.onFork = append(h.onFork, handler...)
- h.app.mutex.Unlock()
- }
- // OnMount is a hook to execute user function after mounting process.
- // The mount event is fired when sub-app is mounted on a parent app. The parent app is passed as a parameter.
- // It works for app and group mounting.
- func (h *Hooks) OnMount(handler ...OnMountHandler) {
- h.app.mutex.Lock()
- h.onMount = append(h.onMount, handler...)
- h.app.mutex.Unlock()
- }
- func (h *Hooks) executeOnRouteHooks(route *Route) error {
- if route == nil {
- return nil
- }
- cloned := *route
- // Check mounting
- if h.app.mountFields.mountPath != "" {
- cloned.path = h.app.mountFields.mountPath + cloned.path
- cloned.Path = cloned.path
- }
- for _, v := range h.onRoute {
- if err := v(cloned); err != nil {
- return err
- }
- }
- return nil
- }
- func (h *Hooks) executeOnNameHooks(route *Route) error {
- if route == nil {
- return nil
- }
- cloned := *route
- // Check mounting
- if h.app.mountFields.mountPath != "" {
- cloned.path = h.app.mountFields.mountPath + cloned.path
- cloned.Path = cloned.path
- }
- for _, v := range h.onName {
- if err := v(cloned); err != nil {
- return err
- }
- }
- return nil
- }
- func (h *Hooks) executeOnGroupHooks(group Group) error {
- // Check mounting
- if h.app.mountFields.mountPath != "" {
- group.Prefix = h.app.mountFields.mountPath + group.Prefix
- }
- for _, v := range h.onGroup {
- if err := v(group); err != nil {
- return err
- }
- }
- return nil
- }
- func (h *Hooks) executeOnGroupNameHooks(group Group) error {
- // Check mounting
- if h.app.mountFields.mountPath != "" {
- group.Prefix = h.app.mountFields.mountPath + group.Prefix
- }
- for _, v := range h.onGroupName {
- if err := v(group); err != nil {
- return err
- }
- }
- return nil
- }
- func (h *Hooks) executeOnListenHooks(listenData *ListenData) error {
- for _, v := range h.onListen {
- if err := v(*listenData); err != nil {
- return err
- }
- }
- return nil
- }
- func (h *Hooks) executeOnPreStartupMessageHooks(data *PreStartupMessageData) error {
- for _, handler := range h.onPreStartup {
- if err := handler(data); err != nil {
- return err
- }
- }
- return nil
- }
- func (h *Hooks) executeOnPostStartupMessageHooks(data *PostStartupMessageData) error {
- for _, handler := range h.onPostStartup {
- if err := handler(data); err != nil {
- return err
- }
- }
- return nil
- }
- func (h *Hooks) executeOnPreShutdownHooks() {
- for _, v := range h.onPreShutdown {
- if err := v(); err != nil {
- log.Errorf("failed to call pre shutdown hook: %v", err)
- }
- }
- }
- func (h *Hooks) executeOnPostShutdownHooks(err error) {
- for _, v := range h.onPostShutdown {
- if hookErr := v(err); hookErr != nil {
- log.Errorf("failed to call post shutdown hook: %v", hookErr)
- }
- }
- }
- func (h *Hooks) executeOnForkHooks(pid int) {
- for _, v := range h.onFork {
- if err := v(pid); err != nil {
- log.Errorf("failed to call fork hook: %v", err)
- }
- }
- }
- func (h *Hooks) executeOnMountHooks(app *App) error {
- for _, v := range h.onMount {
- if err := v(app); err != nil {
- return err
- }
- }
- return nil
- }
|