mirror of https://github.com/gofiber/fiber.git
WIP: export buildTree method
parent
dbba6cfa69
commit
ae61c32860
2
app.go
2
app.go
|
@ -86,7 +86,7 @@ type Error struct {
|
|||
|
||||
// App denotes the Fiber application.
|
||||
type App struct {
|
||||
mutex sync.Mutex
|
||||
mutex sync.RWMutex
|
||||
// Route stack divided by HTTP methods
|
||||
stack [][]*Route
|
||||
// Route stack divided by HTTP methods and route prefixes
|
||||
|
|
22
router.go
22
router.go
|
@ -146,12 +146,15 @@ func (app *App) nextCustom(c CustomCtx) (bool, error) { //nolint: unparam // boo
|
|||
}
|
||||
|
||||
func (app *App) next(c *DefaultCtx) (bool, error) {
|
||||
app.mutex.Lock()
|
||||
|
||||
// Get stack length
|
||||
tree, ok := app.treeStack[c.methodINT][c.treePath]
|
||||
if !ok {
|
||||
tree = app.treeStack[c.methodINT][""]
|
||||
}
|
||||
lenTree := len(tree) - 1
|
||||
app.mutex.Unlock()
|
||||
|
||||
// Loop over the route stack starting from previous index
|
||||
for c.indexRoute < lenTree {
|
||||
|
@ -375,6 +378,11 @@ func (app *App) register(methods []string, pathRaw string, group *Group, handler
|
|||
}
|
||||
|
||||
func (app *App) addRoute(method string, route *Route, isMounted ...bool) {
|
||||
app.mutex.Lock()
|
||||
defer app.mutex.Unlock()
|
||||
|
||||
fmt.Printf("addRoute: method: %s, route: %v, isMounted: %v\n", method, route, isMounted)
|
||||
|
||||
// Check mounted routes
|
||||
var mounted bool
|
||||
if len(isMounted) > 0 {
|
||||
|
@ -400,12 +408,12 @@ func (app *App) addRoute(method string, route *Route, isMounted ...bool) {
|
|||
|
||||
// Execute onRoute hooks & change latestRoute if not adding mounted route
|
||||
if !mounted {
|
||||
app.mutex.Lock()
|
||||
//app.mutex.Lock()
|
||||
app.latestRoute = route
|
||||
if err := app.hooks.executeOnRouteHooks(*route); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
app.mutex.Unlock()
|
||||
//app.mutex.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,3 +454,13 @@ func (app *App) buildTree() *App {
|
|||
|
||||
return app
|
||||
}
|
||||
|
||||
// BuildTree rebuilds the prefix tree from the previously registered routes.
|
||||
// This method is useful when you want to register routes dynamically after the app has started.
|
||||
// It is not recommended to use this method on produtcion environments because rebuilding the tree is performance-intensive.
|
||||
func (app *App) BuildTree() *App {
|
||||
app.mutex.Lock()
|
||||
defer app.mutex.Unlock()
|
||||
|
||||
return app.buildTree()
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ import (
|
|||
"io"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/utils/v2"
|
||||
|
@ -368,6 +371,56 @@ func Test_Router_NotFound_HTML_Inject(t *testing.T) {
|
|||
require.Equal(t, "Cannot DELETE /does/not/exist<script>alert('foo');</script>", string(c.Response.Body()))
|
||||
}
|
||||
|
||||
func Test_App_BuildTree_Concurrent(t *testing.T) {
|
||||
t.Parallel()
|
||||
app := New()
|
||||
|
||||
var counter atomic.Uint64
|
||||
var routerMu sync.Mutex
|
||||
app.Get("/test", func(c Ctx) error {
|
||||
routerMu.Lock()
|
||||
|
||||
cStr := strconv.FormatUint(counter.Load(), 10)
|
||||
counter.Add(1)
|
||||
|
||||
app.Get("/test"+cStr, func(c Ctx) error {
|
||||
return c.SendString("test" + cStr)
|
||||
})
|
||||
|
||||
routerMu.Unlock()
|
||||
|
||||
app.BuildTree()
|
||||
|
||||
return c.SendStatus(StatusOK)
|
||||
})
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(4)
|
||||
for i := 0; i < 4; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
req := httptest.NewRequest(MethodGet, "/test", nil)
|
||||
resp, err := app.Test(req)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, StatusOK, resp.StatusCode)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
req := httptest.NewRequest(MethodGet, "/test"+strconv.FormatInt(int64(i), 10), nil)
|
||||
resp, err := app.Test(req)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, StatusOK, resp.StatusCode)
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "test"+strconv.Itoa(i), app.getString(body))
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
///////////////// BENCHMARKS /////////////////
|
||||
//////////////////////////////////////////////
|
||||
|
|
Loading…
Reference in New Issue