forked from gofiber/fiber
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmount.go
149 lines (124 loc) · 4.16 KB
/
mount.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// ⚡️ Fiber is an Express inspired web framework written in Go with ☕️
// 🤖 Github Repository: https://github.com/gofiber/fiber
// 📌 API Documentation: https://docs.gofiber.io
package fiber
import (
"sort"
"strings"
"sync"
"sync/atomic"
)
// Put fields related to mounting.
type mountFields struct {
// Mounted and main apps
appList map[string]*App
// Ordered keys of apps (sorted by key length for Render)
appListKeys []string
// check added routes of sub-apps
subAppsRoutesAdded sync.Once
// Prefix of app if it was mounted
mountPath string
}
// Create empty mountFields instance
func newMountFields(app *App) *mountFields {
return &mountFields{
appList: map[string]*App{"": app},
appListKeys: make([]string, 0),
}
}
// Mount attaches another app instance as a sub-router along a routing path.
// It's very useful to split up a large API as many independent routers and
// compose them as a single service using Mount. The fiber's error handler and
// any of the fiber's sub apps are added to the application's error handlers
// to be invoked on errors that happen within the prefix route.
func (app *App) Mount(prefix string, fiber *App) Router {
prefix = strings.TrimRight(prefix, "/")
if prefix == "" {
prefix = "/"
}
// Support for configs of mounted-apps and sub-mounted-apps
for mountedPrefixes, subApp := range fiber.mountFields.appList {
path := getGroupPath(prefix, mountedPrefixes)
subApp.mountFields.mountPath = path
app.mountFields.appList[path] = subApp
}
// Execute onMount hooks
if err := fiber.hooks.executeOnMountHooks(app); err != nil {
panic(err)
}
return app
}
// Mount attaches another app instance as a sub-router along a routing path.
// It's very useful to split up a large API as many independent routers and
// compose them as a single service using Mount.
func (grp *Group) Mount(prefix string, fiber *App) Router {
groupPath := getGroupPath(grp.Prefix, prefix)
groupPath = strings.TrimRight(groupPath, "/")
if groupPath == "" {
groupPath = "/"
}
// Support for configs of mounted-apps and sub-mounted-apps
for mountedPrefixes, subApp := range fiber.mountFields.appList {
path := getGroupPath(groupPath, mountedPrefixes)
subApp.mountFields.mountPath = path
grp.app.mountFields.appList[path] = subApp
}
// Execute onMount hooks
if err := fiber.hooks.executeOnMountHooks(grp.app); err != nil {
panic(err)
}
return grp
}
// The MountPath property contains one or more path patterns on which a sub-app was mounted.
func (app *App) MountPath() string {
return app.mountFields.mountPath
}
// generateAppListKeys generates app list keys for Render, should work after appendSubAppLists
func (app *App) generateAppListKeys() {
for key := range app.mountFields.appList {
app.mountFields.appListKeys = append(app.mountFields.appListKeys, key)
}
sort.Slice(app.mountFields.appListKeys, func(i, j int) bool {
return len(app.mountFields.appListKeys[i]) < len(app.mountFields.appListKeys[j])
})
}
// appendSubAppLists supports nested for sub apps
func (app *App) appendSubAppLists(appList map[string]*App, parent ...string) {
for prefix, subApp := range appList {
// skip real app
if prefix == "" {
continue
}
if len(parent) > 0 {
prefix = getGroupPath(parent[0], prefix)
}
if _, ok := app.mountFields.appList[prefix]; !ok {
app.mountFields.appList[prefix] = subApp
}
// The first element of appList is always the app itself. If there are no other sub apps, we should skip appending nested apps.
if len(subApp.mountFields.appList) > 1 {
app.appendSubAppLists(subApp.mountFields.appList, prefix)
}
}
}
// addSubAppsRoutes adds routes of sub apps nestedly when to start the server
func (app *App) addSubAppsRoutes(appList map[string]*App, parent ...string) {
for prefix, subApp := range appList {
// skip real app
if prefix == "" {
continue
}
if len(parent) > 0 {
prefix = getGroupPath(parent[0], prefix)
}
// add routes
stack := subApp.stack
for m := range stack {
for r := range stack[m] {
route := app.copyRoute(stack[m][r])
app.addRoute(route.Method, app.addPrefixToRoute(prefix, route), true)
}
}
atomic.AddUint32(&app.handlersCount, subApp.handlersCount)
}
}