mirror of
https://github.com/zap-proto/fiber.git
synced 2026-10-30 15:06:23 +00:00
Fork of gofiber/fiber v3 based on the v3.2.0 tag. Rewrites all self-imports github.com/gofiber/fiber/v3 -> github.com/zap-proto/fiber/v3. Upstream gofiber/schema and gofiber/utils/v2 dependencies are left untouched. Co-authored-by: Hanzo Dev <[email protected]>
463 lines
12 KiB
Go
463 lines
12 KiB
Go
package fiber
|
|
|
|
import (
|
|
"slices"
|
|
|
|
"github.com/zap-proto/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
|
|
}
|