github.com/erda-project/erda-infra@v1.0.9/providers/httpserver/server/router.go (about)

     1  // Copyright (c) 2021 Terminus, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package server
    16  
    17  import (
    18  	"sync"
    19  	"sync/atomic"
    20  
    21  	"github.com/labstack/echo"
    22  )
    23  
    24  type (
    25  	// Context .
    26  	Context = echo.Context
    27  	// HandlerFunc .
    28  	HandlerFunc = echo.HandlerFunc
    29  	// MiddlewareFunc .
    30  	MiddlewareFunc = echo.MiddlewareFunc
    31  
    32  	// Router .
    33  	Router interface {
    34  		Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc)
    35  		Find(method, path string, c Context)
    36  		NewContext() Context
    37  		ReleaseContext(c Context)
    38  	}
    39  )
    40  
    41  type router struct {
    42  	*echo.Router
    43  	e    *echo.Echo
    44  	pool sync.Pool
    45  }
    46  
    47  func newRouter(e *echo.Echo, binder echo.Binder, validator echo.Validator) Router {
    48  	if e == nil {
    49  		e = echo.New()
    50  		e.Binder, e.Validator = binder, validator
    51  	}
    52  	r := &router{
    53  		Router: e.Router(),
    54  		e:      e,
    55  	}
    56  	r.pool.New = func() interface{} {
    57  		return r.e.NewContext(nil, nil)
    58  	}
    59  	return r
    60  }
    61  
    62  // Add registers a new route for an HTTP method and path with matching handler
    63  // in the router with optional route-level middleware.
    64  func (rt *router) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
    65  	h := handler
    66  	// Chain middleware
    67  	for i := len(middleware) - 1; i >= 0; i-- {
    68  		h = middleware[i](h)
    69  	}
    70  	rt.Router.Add(method, path, h)
    71  }
    72  
    73  // NewContext .
    74  func (rt *router) NewContext() Context {
    75  	return rt.pool.Get().(Context)
    76  }
    77  
    78  func (rt *router) ReleaseContext(c Context) {
    79  	rt.pool.Put(c)
    80  }
    81  
    82  type fixedRouterManager struct{ Router }
    83  
    84  func (r *fixedRouterManager) GetRouter() Router   { return r.Router }
    85  func (r *fixedRouterManager) NewRouter() RouterTx { return r }
    86  func (r *fixedRouterManager) Commit()             {}
    87  
    88  func newFixedRouterManager(e *echo.Echo) routerManager {
    89  	return &fixedRouterManager{
    90  		Router: newRouter(e, e.Binder, e.Validator),
    91  	}
    92  }
    93  
    94  type reloadableRouterManager struct {
    95  	v         atomic.Value
    96  	binder    echo.Binder
    97  	validator echo.Validator
    98  }
    99  
   100  func (r *reloadableRouterManager) GetRouter() Router { return r.v.Load().(Router) }
   101  func (r *reloadableRouterManager) NewRouter() RouterTx {
   102  	return &reloadableRouterTx{
   103  		Router: newRouter(nil, r.binder, r.validator),
   104  		rr:     r,
   105  	}
   106  }
   107  
   108  type reloadableRouterTx struct {
   109  	Router
   110  	rr *reloadableRouterManager
   111  }
   112  
   113  func (r *reloadableRouterTx) Commit() { r.rr.v.Store(r.Router) }
   114  
   115  func newReloadableRouterManager(e *echo.Echo) routerManager {
   116  	r := &reloadableRouterManager{
   117  		binder:    e.Binder,
   118  		validator: e.Validator,
   119  	}
   120  	r.NewRouter().Commit()
   121  	return r
   122  }