Package Router:

- rework to apply standard hierarchy
- move auth to dedicated sub package
- move header to dedicated sub package

Package Static:
- fix bugs
This commit is contained in:
nabbar
2023-12-02 16:48:48 +01:00
parent 4a47f39dc0
commit 824f9cc0ce
21 changed files with 668 additions and 383 deletions

View File

@@ -27,7 +27,7 @@
package head package head
import ( import (
librtr "github.com/nabbar/golib/router" librtr "github.com/nabbar/golib/router/header"
spfcbr "github.com/spf13/cobra" spfcbr "github.com/spf13/cobra"
spfvpr "github.com/spf13/viper" spfvpr "github.com/spf13/viper"
) )

View File

@@ -29,9 +29,10 @@ package head
import ( import (
"sync" "sync"
librtr "github.com/nabbar/golib/router/header"
libcfg "github.com/nabbar/golib/config" libcfg "github.com/nabbar/golib/config"
cfgtps "github.com/nabbar/golib/config/types" cfgtps "github.com/nabbar/golib/config/types"
librtr "github.com/nabbar/golib/router"
) )
type ComponentHead interface { type ComponentHead interface {

View File

@@ -29,8 +29,9 @@ package head
import ( import (
"sync" "sync"
librtr "github.com/nabbar/golib/router/header"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
librtr "github.com/nabbar/golib/router"
) )
type componentHead struct { type componentHead struct {

View File

@@ -31,7 +31,6 @@ import (
"sync" "sync"
ginsdk "github.com/gin-gonic/gin" ginsdk "github.com/gin-gonic/gin"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
libmet "github.com/nabbar/golib/prometheus/metrics" libmet "github.com/nabbar/golib/prometheus/metrics"
prmpol "github.com/nabbar/golib/prometheus/pool" prmpol "github.com/nabbar/golib/prometheus/pool"

48
router/auth/interface.go Normal file
View File

@@ -0,0 +1,48 @@
/*
* MIT License
*
* Copyright (c) 2019 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package auth
import (
ginsdk "github.com/gin-gonic/gin"
liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger"
rtrhdr "github.com/nabbar/golib/router/authheader"
)
type Authorization interface {
Handler(c *ginsdk.Context)
Register(router ...ginsdk.HandlerFunc) ginsdk.HandlerFunc
Append(router ...ginsdk.HandlerFunc)
}
func NewAuthorization(log liblog.FuncLog, HeadAuthType string, authCheckFunc func(AuthHeader string) (rtrhdr.AuthCode, liberr.Error)) Authorization {
return &authorization{
log: log,
check: authCheckFunc,
authType: HeadAuthType,
router: make([]ginsdk.HandlerFunc, 0),
}
}

View File

@@ -23,78 +23,28 @@
* *
*/ */
package router package auth
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"strings" "strings"
liblog "github.com/nabbar/golib/logger"
ginsdk "github.com/gin-gonic/gin" ginsdk "github.com/gin-gonic/gin"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger"
loglvl "github.com/nabbar/golib/logger/level" loglvl "github.com/nabbar/golib/logger/level"
librtr "github.com/nabbar/golib/router"
rtrhdr "github.com/nabbar/golib/router/authheader"
) )
type AuthCode uint8
const (
AUTH_CODE_SUCCESS = iota
AUTH_CODE_REQUIRE
AUTH_CODE_FORBIDDEN
)
const (
HEAD_AUTH_REQR = "WWW-Authenticate"
HEAD_AUTH_SEND = "Authorization"
HEAD_AUTH_REAL = "Basic realm=LDAP Authorization Required"
)
func AuthRequire(c *ginsdk.Context, err error) {
if err != nil {
c.Errors = append(c.Errors, &ginsdk.Error{
Err: err,
Type: ginsdk.ErrorTypePrivate,
})
}
// Credentials doesn't match, we return 401 and abort handlers chain.
c.Header(HEAD_AUTH_REQR, HEAD_AUTH_REAL)
c.AbortWithStatus(http.StatusUnauthorized)
}
func AuthForbidden(c *ginsdk.Context, err error) {
if err != nil {
c.Errors = append(c.Errors, &ginsdk.Error{
Err: err,
Type: ginsdk.ErrorTypePrivate,
})
}
c.AbortWithStatus(http.StatusForbidden)
}
type authorization struct { type authorization struct {
log liblog.FuncLog log liblog.FuncLog
check func(AuthHeader string) (AuthCode, liberr.Error) check func(AuthHeader string) (rtrhdr.AuthCode, liberr.Error)
router []ginsdk.HandlerFunc router []ginsdk.HandlerFunc
authType string authType string
} }
type Authorization interface {
Handler(c *ginsdk.Context)
Register(router ...ginsdk.HandlerFunc) ginsdk.HandlerFunc
Append(router ...ginsdk.HandlerFunc)
}
func NewAuthorization(log liblog.FuncLog, HeadAuthType string, authCheckFunc func(AuthHeader string) (AuthCode, liberr.Error)) Authorization {
return &authorization{
log: log,
check: authCheckFunc,
authType: HeadAuthType,
router: make([]ginsdk.HandlerFunc, 0),
}
}
func (a *authorization) Register(router ...ginsdk.HandlerFunc) ginsdk.HandlerFunc { func (a *authorization) Register(router ...ginsdk.HandlerFunc) ginsdk.HandlerFunc {
a.router = router a.router = router
return a.Handler return a.Handler
@@ -112,10 +62,10 @@ func (a *authorization) logDebug(msg string, args ...interface{}) {
func (a *authorization) Handler(c *ginsdk.Context) { func (a *authorization) Handler(c *ginsdk.Context) {
// Search user in the slice of allowed credentials // Search user in the slice of allowed credentials
auth := c.Request.Header.Get(HEAD_AUTH_SEND) auth := c.Request.Header.Get(rtrhdr.HeaderAuthSend)
if auth == "" { if auth == "" {
AuthRequire(c, fmt.Errorf("%v", ErrorHeaderAuthMissing.Error(nil).GetErrorSlice())) rtrhdr.AuthRequire(c, fmt.Errorf("%v", librtr.ErrorHeaderAuthMissing.Error(nil).GetErrorSlice()))
return return
} }
@@ -129,24 +79,24 @@ func (a *authorization) Handler(c *ginsdk.Context) {
} }
if authValue == "" { if authValue == "" {
AuthRequire(c, fmt.Errorf("%v", ErrorHeaderAuthEmpty.Error(nil).GetErrorSlice())) rtrhdr.AuthRequire(c, fmt.Errorf("%v", librtr.ErrorHeaderAuthEmpty.Error(nil).GetErrorSlice()))
return return
} else { } else {
code, err := a.check(authValue) code, err := a.check(authValue)
switch code { switch code {
case AUTH_CODE_SUCCESS: case rtrhdr.AuthCodeSuccess:
for _, r := range a.router { for _, r := range a.router {
a.logDebug("Calling router '%s=%s'", c.Request.Method, c.Request.URL.RawPath) a.logDebug("Calling router '%s=%s'", c.Request.Method, c.Request.URL.RawPath)
r(c) r(c)
} }
case AUTH_CODE_REQUIRE: case rtrhdr.AuthCodeRequire:
AuthRequire(c, fmt.Errorf("%v", ErrorHeaderAuthRequire.Error(err).GetErrorSlice())) rtrhdr.AuthRequire(c, fmt.Errorf("%v", librtr.ErrorHeaderAuthRequire.Error(err).GetErrorSlice()))
case AUTH_CODE_FORBIDDEN: case rtrhdr.AuthCodeForbidden:
AuthForbidden(c, fmt.Errorf("%v", ErrorHeaderAuthForbidden.Error(err).GetErrorSlice())) rtrhdr.AuthForbidden(c, fmt.Errorf("%v", librtr.ErrorHeaderAuthForbidden.Error(err).GetErrorSlice()))
default: default:
c.Errors = append(c.Errors, &ginsdk.Error{ c.Errors = append(c.Errors, &ginsdk.Error{
Err: fmt.Errorf("%v", ErrorHeaderAuth.Error(err).GetErrorSlice()), Err: fmt.Errorf("%v", librtr.ErrorHeaderAuth.Error(err).GetErrorSlice()),
Type: ginsdk.ErrorTypePrivate, Type: ginsdk.ErrorTypePrivate,
}) })
c.AbortWithStatus(http.StatusInternalServerError) c.AbortWithStatus(http.StatusInternalServerError)

View File

@@ -0,0 +1,68 @@
/*
* MIT License
*
* Copyright (c) 2019 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package authheader
import (
"net/http"
ginsdk "github.com/gin-gonic/gin"
)
type AuthCode uint8
const (
AuthCodeSuccess = iota
AuthCodeRequire
AuthCodeForbidden
)
const (
HeaderAuthRequire = "WWW-Authenticate"
HeaderAuthSend = "Authorization"
HeaderAuthReal = "Basic realm=LDAP Authorization Required"
)
func AuthRequire(c *ginsdk.Context, err error) {
if err != nil {
c.Errors = append(c.Errors, &ginsdk.Error{
Err: err,
Type: ginsdk.ErrorTypePrivate,
})
}
// Credentials doesn't match, we return 401 and abort handlers chain.
c.Header(HeaderAuthRequire, HeaderAuthReal)
c.AbortWithStatus(http.StatusUnauthorized)
}
func AuthForbidden(c *ginsdk.Context, err error) {
if err != nil {
c.Errors = append(c.Errors, &ginsdk.Error{
Err: err,
Type: ginsdk.ErrorTypePrivate,
})
}
c.AbortWithStatus(http.StatusForbidden)
}

109
router/default.go Normal file
View File

@@ -0,0 +1,109 @@
/*
* MIT License
*
* Copyright (c) 2019 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package router
import (
"net/http"
ginsdk "github.com/gin-gonic/gin"
)
func DefaultGinInit() *ginsdk.Engine {
engine := ginsdk.New()
engine.Use(ginsdk.Logger(), ginsdk.Recovery())
return engine
}
func DefaultGinWithTrustyProxy(trustyProxy []string) *ginsdk.Engine {
engine := ginsdk.New()
engine.Use(ginsdk.Logger(), ginsdk.Recovery())
if len(trustyProxy) > 0 {
_ = engine.SetTrustedProxies(trustyProxy)
}
return engine
}
func DefaultGinWithTrustedPlatform(trustedPlatform string) *ginsdk.Engine {
engine := ginsdk.New()
engine.Use(ginsdk.Logger(), ginsdk.Recovery())
if len(trustedPlatform) > 0 {
engine.TrustedPlatform = trustedPlatform
}
return engine
}
func RoutersRegister(method string, relativePath string, router ...ginsdk.HandlerFunc) {
defaultRouters.Register(method, relativePath, router...)
}
func RoutersRegisterInGroup(group, method string, relativePath string, router ...ginsdk.HandlerFunc) {
defaultRouters.RegisterInGroup(group, method, relativePath, router...)
}
func RoutersHandler(engine *ginsdk.Engine) {
defaultRouters.Handler(engine)
}
func GinEngine(trustedPlatform string, trustyProxy ...string) (*ginsdk.Engine, error) {
var err error
engine := ginsdk.New()
if len(trustyProxy) > 0 {
err = engine.SetTrustedProxies(trustyProxy)
}
if len(trustedPlatform) > 0 {
engine.TrustedPlatform = trustedPlatform
}
return engine, err
}
func GinAddGlobalMiddleware(eng *ginsdk.Engine, middleware ...ginsdk.HandlerFunc) *ginsdk.Engine {
eng.Use(middleware...)
return eng
}
// SetGinHandler func that return given func as ginTonic HandlerFunc interface type.
func SetGinHandler(fct func(c *ginsdk.Context)) ginsdk.HandlerFunc {
return fct
}
func Handler(routerList RouterList) http.Handler {
e := routerList.Engine()
if routerList == nil {
RoutersHandler(e)
} else {
routerList.Handler(e)
}
return e
}

53
router/header/config.go Normal file
View File

@@ -0,0 +1,53 @@
/*
* MIT License
*
* Copyright (c) 2019 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package header
import (
liberr "github.com/nabbar/golib/errors"
"github.com/nabbar/golib/router"
)
type HeadersConfig map[string]string
func (h HeadersConfig) New() Headers {
var res = NewHeaders()
for k, v := range h {
res.Add(k, v)
}
return res
}
func (h HeadersConfig) Validate() liberr.Error {
err := router.ErrorConfigValidator.Error(nil)
if !err.HasParent() {
err = nil
}
return err
}

View File

@@ -0,0 +1,51 @@
/*
* MIT License
*
* Copyright (c) 2019 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package header
import (
"net/http"
ginsdk "github.com/gin-gonic/gin"
)
type Headers interface {
Add(key, value string)
Set(key, value string)
Get(key string) string
Del(key string)
Header() map[string]string
Register(router ...ginsdk.HandlerFunc) []ginsdk.HandlerFunc
Handler(c *ginsdk.Context)
Clone() Headers
}
func NewHeaders() Headers {
return &headers{
head: make(http.Header),
}
}

View File

@@ -23,60 +23,18 @@
* *
*/ */
package router package header
import ( import (
"net/http" "net/http"
ginsdk "github.com/gin-gonic/gin" ginsdk "github.com/gin-gonic/gin"
liberr "github.com/nabbar/golib/errors"
) )
type HeadersConfig map[string]string
func (h HeadersConfig) New() Headers {
var res = NewHeaders()
for k, v := range h {
res.Add(k, v)
}
return res
}
func (h HeadersConfig) Validate() liberr.Error {
err := ErrorConfigValidator.Error(nil)
if !err.HasParent() {
err = nil
}
return err
}
type headers struct { type headers struct {
head http.Header head http.Header
} }
type Headers interface {
Add(key, value string)
Set(key, value string)
Get(key string) string
Del(key string)
Header() map[string]string
Register(router ...ginsdk.HandlerFunc) []ginsdk.HandlerFunc
Handler(c *ginsdk.Context)
Clone() Headers
}
func NewHeaders() Headers {
return &headers{
head: make(http.Header),
}
}
func (h headers) Clone() Headers { func (h headers) Clone() Headers {
return &headers{ return &headers{
head: h.head, head: h.head,

67
router/interface.go Normal file
View File

@@ -0,0 +1,67 @@
/*
* MIT License
*
* Copyright (c) 2019 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package router
import (
"os"
ginsdk "github.com/gin-gonic/gin"
)
const (
EmptyHandlerGroup = "<nil>"
GinContextStartUnixNanoTime = "gin-ctx-start-unix-nano-time"
GinContextRequestPath = "gin-ctx-request-path"
GinContextRequestUser = "gin-ctx-request-user"
)
var (
defaultRouters = NewRouterList(DefaultGinInit)
)
func init() {
if os.Getenv("GIN_MODE") == "" {
ginsdk.SetMode(ginsdk.ReleaseMode)
}
}
type RegisterRouter func(method string, relativePath string, router ...ginsdk.HandlerFunc)
type RegisterRouterInGroup func(group, method string, relativePath string, router ...ginsdk.HandlerFunc)
type RouterList interface {
Register(method string, relativePath string, router ...ginsdk.HandlerFunc)
RegisterInGroup(group, method string, relativePath string, router ...ginsdk.HandlerFunc)
RegisterMergeInGroup(group, method string, relativePath string, router ...ginsdk.HandlerFunc)
Handler(engine *ginsdk.Engine)
Engine() *ginsdk.Engine
}
func NewRouterList(initGin func() *ginsdk.Engine) RouterList {
return &rtr{
init: initGin,
list: make(map[string][]itm),
}
}

View File

@@ -40,36 +40,6 @@ import (
loglvl "github.com/nabbar/golib/logger/level" loglvl "github.com/nabbar/golib/logger/level"
) )
const (
EmptyHandlerGroup = "<nil>"
GinContextStartUnixNanoTime = "gin-ctx-start-unix-nano-time"
GinContextRequestPath = "gin-ctx-request-path"
GinContextRequestUser = "gin-ctx-request-user"
)
var (
defaultRouters = NewRouterList(DefaultGinInit)
)
func GinEngine(trustedPlatform string, trustyProxy ...string) (*ginsdk.Engine, error) {
var err error
engine := ginsdk.New()
if len(trustyProxy) > 0 {
err = engine.SetTrustedProxies(trustyProxy)
}
if len(trustedPlatform) > 0 {
engine.TrustedPlatform = trustedPlatform
}
return engine, err
}
func GinAddGlobalMiddleware(eng *ginsdk.Engine, middleware ...ginsdk.HandlerFunc) *ginsdk.Engine {
eng.Use(middleware...)
return eng
}
func GinLatencyContext(c *ginsdk.Context) { func GinLatencyContext(c *ginsdk.Context) {
// Start timer // Start timer
c.Set(GinContextStartUnixNanoTime, time.Now().UnixNano()) c.Set(GinContextStartUnixNanoTime, time.Now().UnixNano())
@@ -78,13 +48,6 @@ func GinLatencyContext(c *ginsdk.Context) {
c.Next() c.Next()
} }
func sanitizeString(s string) string {
s = strings.Replace(s, "\n", "", -1)
s = strings.Replace(s, "\r", "", -1)
s = strings.Replace(s, "\t", "", -1)
return s
}
func GinRequestContext(c *ginsdk.Context) { func GinRequestContext(c *ginsdk.Context) {
// Set Path // Set Path
if c != nil { if c != nil {
@@ -204,115 +167,3 @@ func GinErrorLog(log liblog.FuncLog) ginsdk.HandlerFunc {
c.Next() c.Next()
} }
} }
func DefaultGinInit() *ginsdk.Engine {
engine := ginsdk.New()
engine.Use(ginsdk.Logger(), ginsdk.Recovery())
return engine
}
func DefaultGinWithTrustyProxy(trustyProxy []string) *ginsdk.Engine {
engine := ginsdk.New()
engine.Use(ginsdk.Logger(), ginsdk.Recovery())
if len(trustyProxy) > 0 {
_ = engine.SetTrustedProxies(trustyProxy)
}
return engine
}
func DefaultGinWithTrustedPlatform(trustedPlatform string) *ginsdk.Engine {
engine := ginsdk.New()
engine.Use(ginsdk.Logger(), ginsdk.Recovery())
if len(trustedPlatform) > 0 {
engine.TrustedPlatform = trustedPlatform
}
return engine
}
type routerItem struct {
method string
relative string
router []ginsdk.HandlerFunc
}
type routerList struct {
init func() *ginsdk.Engine
list map[string][]routerItem
}
type RegisterRouter func(method string, relativePath string, router ...ginsdk.HandlerFunc)
type RegisterRouterInGroup func(group, method string, relativePath string, router ...ginsdk.HandlerFunc)
type RouterList interface {
Register(method string, relativePath string, router ...ginsdk.HandlerFunc)
RegisterInGroup(group, method string, relativePath string, router ...ginsdk.HandlerFunc)
Handler(engine *ginsdk.Engine)
Engine() *ginsdk.Engine
}
func RoutersRegister(method string, relativePath string, router ...ginsdk.HandlerFunc) {
defaultRouters.Register(method, relativePath, router...)
}
func RoutersRegisterInGroup(group, method string, relativePath string, router ...ginsdk.HandlerFunc) {
defaultRouters.RegisterInGroup(group, method, relativePath, router...)
}
func RoutersHandler(engine *ginsdk.Engine) {
defaultRouters.Handler(engine)
}
func NewRouterList(initGin func() *ginsdk.Engine) RouterList {
return &routerList{
init: initGin,
list: make(map[string][]routerItem),
}
}
func (l routerList) Handler(engine *ginsdk.Engine) {
for grpRoute, grpList := range l.list {
if grpRoute == EmptyHandlerGroup {
for _, r := range grpList {
engine.Handle(r.method, r.relative, r.router...)
}
} else {
var grp = engine.Group(grpRoute)
for _, r := range grpList {
grp.Handle(r.method, r.relative, r.router...)
}
}
}
}
func (l *routerList) RegisterInGroup(group, method string, relativePath string, router ...ginsdk.HandlerFunc) {
if group == "" {
group = EmptyHandlerGroup
}
if _, ok := l.list[group]; !ok {
l.list[group] = make([]routerItem, 0)
}
l.list[group] = append(l.list[group], routerItem{
method: method,
relative: relativePath,
router: router,
})
}
func (l *routerList) Register(method string, relativePath string, router ...ginsdk.HandlerFunc) {
l.RegisterInGroup("", method, relativePath, router...)
}
func (l routerList) Engine() *ginsdk.Engine {
if l.init != nil {
return l.init()
} else {
return DefaultGinInit()
}
}

104
router/model.go Normal file
View File

@@ -0,0 +1,104 @@
/*
* MIT License
*
* Copyright (c) 2019 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package router
import (
ginsdk "github.com/gin-gonic/gin"
)
type rtr struct {
init func() *ginsdk.Engine
list map[string][]itm
}
func (l *rtr) Handler(engine *ginsdk.Engine) {
for grpRoute, grpList := range l.list {
if grpRoute == EmptyHandlerGroup {
for _, r := range grpList {
engine.Handle(r.method, r.relative, r.router...)
}
} else {
var grp = engine.Group(grpRoute)
for _, r := range grpList {
grp.Handle(r.method, r.relative, r.router...)
}
}
}
}
func (l *rtr) RegisterInGroup(group, method, relativePath string, router ...ginsdk.HandlerFunc) {
if group == "" {
group = EmptyHandlerGroup
}
if _, ok := l.list[group]; !ok {
l.list[group] = make([]itm, 0)
}
l.list[group] = append(l.list[group], itm{
method: method,
relative: relativePath,
router: router,
})
}
func (l *rtr) RegisterMergeInGroup(group, method, relativePath string, router ...ginsdk.HandlerFunc) {
if group == "" {
group = EmptyHandlerGroup
}
if _, ok := l.list[group]; !ok {
l.list[group] = make([]itm, 0)
}
// if same route exists for same relative path and same method, so replace router list
for i, r := range l.list[group] {
if !r.Same(method, relativePath) {
continue
} else {
l.list[group][i].Merge(router...)
return
}
}
l.list[group] = append(l.list[group], itm{
method: method,
relative: relativePath,
router: router,
})
}
func (l *rtr) Register(method, relativePath string, router ...ginsdk.HandlerFunc) {
l.RegisterInGroup("", method, relativePath, router...)
}
func (l *rtr) Engine() *ginsdk.Engine {
if l.init != nil {
return l.init()
} else {
return DefaultGinInit()
}
}

View File

@@ -25,32 +25,24 @@
package router package router
import ( import ginsdk "github.com/gin-gonic/gin"
"net/http"
"os"
ginsdk "github.com/gin-gonic/gin" type itm struct {
) method string
relative string
router []ginsdk.HandlerFunc
}
func init() { func (o *itm) Same(method, relative string) bool {
if os.Getenv("GIN_MODE") == "" { if o.method != method {
ginsdk.SetMode(ginsdk.ReleaseMode) return false
} }
} if o.relative != relative {
return false
// SetGinHandler func that return given func as ginTonic HandlerFunc interface type.
func SetGinHandler(fct func(c *ginsdk.Context)) ginsdk.HandlerFunc {
return fct
}
func Handler(routerList RouterList) http.Handler {
e := routerList.Engine()
if routerList == nil {
RoutersHandler(e)
} else {
routerList.Handler(e)
} }
return true
return e }
func (o *itm) Merge(rtr ...ginsdk.HandlerFunc) {
o.router = rtr
} }

35
router/tools.go Normal file
View File

@@ -0,0 +1,35 @@
/*
* MIT License
*
* Copyright (c) 2019 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package router
import "strings"
func sanitizeString(s string) string {
s = strings.Replace(s, "\n", "", -1)
s = strings.Replace(s, "\r", "", -1)
s = strings.Replace(s, "\t", "", -1)
return s
}

View File

@@ -30,7 +30,6 @@ import (
"embed" "embed"
"io" "io"
"os" "os"
"sync"
"sync/atomic" "sync/atomic"
libfpg "github.com/nabbar/golib/file/progress" libfpg "github.com/nabbar/golib/file/progress"
@@ -48,7 +47,7 @@ type Static interface {
RegisterRouter(route string, register librtr.RegisterRouter, router ...ginsdk.HandlerFunc) RegisterRouter(route string, register librtr.RegisterRouter, router ...ginsdk.HandlerFunc)
RegisterRouterInGroup(route, group string, register librtr.RegisterRouterInGroup, router ...ginsdk.HandlerFunc) RegisterRouterInGroup(route, group string, register librtr.RegisterRouterInGroup, router ...ginsdk.HandlerFunc)
RegisterLogger(log func() liblog.Logger) RegisterLogger(log liblog.FuncLog)
SetDownload(pathFile string, flag bool) SetDownload(pathFile string, flag bool)
SetIndex(group, route, pathFile string) SetIndex(group, route, pathFile string)
@@ -79,15 +78,19 @@ type Static interface {
} }
func New(ctx libctx.FuncContext, content embed.FS, embedRootDir ...string) Static { func New(ctx libctx.FuncContext, content embed.FS, embedRootDir ...string) Static {
return &staticHandler{ s := &staticHandler{
m: sync.RWMutex{}, l: new(atomic.Value),
l: nil,
c: content, c: content,
b: embedRootDir, b: new(atomic.Value),
z: 0, z: new(atomic.Int64),
i: libctx.NewConfig[string](ctx), i: libctx.NewConfig[string](ctx),
d: libctx.NewConfig[string](ctx), d: libctx.NewConfig[string](ctx),
f: libctx.NewConfig[string](ctx), f: libctx.NewConfig[string](ctx),
s: libctx.NewConfig[string](ctx),
r: new(atomic.Value), r: new(atomic.Value),
h: new(atomic.Value),
} }
s._setBase(embedRootDir...)
s._setLogger(nil)
return s
} }

View File

@@ -28,7 +28,6 @@ package static
import ( import (
"embed" "embed"
"sync"
"sync/atomic" "sync/atomic"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
@@ -40,62 +39,46 @@ const (
) )
type staticHandler struct { type staticHandler struct {
m sync.RWMutex l *atomic.Value // logger
l func() liblog.Logger r *atomic.Value // router
h *atomic.Value // monitor
c embed.FS c embed.FS
b []string // base b *atomic.Value // base []string
z int64 // size z *atomic.Int64 // size
i libctx.Config[string] // index i libctx.Config[string] // index
d libctx.Config[string] // download d libctx.Config[string] // download
f libctx.Config[string] // follow f libctx.Config[string] // follow
s libctx.Config[string] // specific s libctx.Config[string] // specific
r *atomic.Value // router
h *atomic.Value // monitor
} }
func (s *staticHandler) _setLogger(fct func() liblog.Logger) { func (s *staticHandler) _setLogger(fct liblog.FuncLog) {
s.m.Lock() if fct == nil {
defer s.m.Unlock() fct = s._getDefaultLogger
}
s.l = fct s.l.Store(fct())
} }
func (s *staticHandler) _getLogger() liblog.Logger { func (s *staticHandler) _getLogger() liblog.Logger {
s.m.RLock() i := s.l.Load()
defer s.m.RUnlock()
var log liblog.Logger if i == nil {
return s._getDefaultLogger()
if s.l == nil { } else if l, k := i.(liblog.FuncLog); !k {
s.m.RUnlock() return s._getDefaultLogger()
log = s._getDefaultLogger() } else if log := l(); log == nil {
s.m.RLock() return s._getDefaultLogger()
return log
} else if log = s.l(); log == nil {
s.m.RUnlock()
log = s._getDefaultLogger()
s.m.RLock()
return log
} else { } else {
return log return log
} }
} }
func (s *staticHandler) _getDefaultLogger() liblog.Logger { func (s *staticHandler) _getDefaultLogger() liblog.Logger {
s.m.Lock() return liblog.New(s.d.GetContext)
defer s.m.Unlock()
var log = liblog.New(s.d.GetContext)
s.l = func() liblog.Logger {
return log
}
return log
} }
func (s *staticHandler) RegisterLogger(log func() liblog.Logger) { func (s *staticHandler) RegisterLogger(log liblog.FuncLog) {
s._setLogger(log) s._setLogger(log)
} }

View File

@@ -41,31 +41,32 @@ import (
) )
func (s *staticHandler) _getSize() int64 { func (s *staticHandler) _getSize() int64 {
s.m.RLock() return s.z.Load()
defer s.m.RUnlock()
return s.z
} }
func (s *staticHandler) _setSize(size int64) { func (s *staticHandler) _setSize(size int64) {
s.m.Lock() s.z.Store(size)
defer s.m.Unlock()
s.z = size
} }
func (s *staticHandler) _getBase() []string { func (s *staticHandler) _getBase() []string {
s.m.RLock() i := s.b.Load()
defer s.m.RUnlock() if i == nil {
return make([]string, 0)
return s.b } else if b, k := i.([]string); !k {
return make([]string, 0)
} else {
return b
}
} }
func (s *staticHandler) _setBase(base ...string) { func (s *staticHandler) _setBase(base ...string) {
s.m.Lock() var b = make([]string, 0)
defer s.m.Unlock()
s.b = base if len(base) > 0 {
b = append(b, base...)
}
s.b.Store(b)
} }
func (s *staticHandler) _listEmbed(root string) ([]fs.DirEntry, liberr.Error) { func (s *staticHandler) _listEmbed(root string) ([]fs.DirEntry, liberr.Error) {
@@ -73,9 +74,6 @@ func (s *staticHandler) _listEmbed(root string) ([]fs.DirEntry, liberr.Error) {
return nil, ErrorParamEmpty.Error(fmt.Errorf("pathfile is empty")) return nil, ErrorParamEmpty.Error(fmt.Errorf("pathfile is empty"))
} }
s.m.RLock()
defer s.m.RUnlock()
val, err := s.c.ReadDir(root) val, err := s.c.ReadDir(root)
if err != nil && errors.Is(err, fs.ErrNotExist) { if err != nil && errors.Is(err, fs.ErrNotExist) {
@@ -108,9 +106,6 @@ func (s *staticHandler) _fileInfo(pathFile string) (fs.FileInfo, liberr.Error) {
return nil, ErrorParamEmpty.Error(fmt.Errorf("pathfile is empty")) return nil, ErrorParamEmpty.Error(fmt.Errorf("pathfile is empty"))
} }
s.m.RLock()
defer s.m.RUnlock()
var inf fs.FileInfo var inf fs.FileInfo
obj, err := s.c.Open(pathFile) obj, err := s.c.Open(pathFile)
@@ -140,9 +135,6 @@ func (s *staticHandler) _fileBuff(pathFile string) (io.ReadCloser, liberr.Error)
return nil, ErrorParamEmpty.Error(fmt.Errorf("pathfile is empty")) return nil, ErrorParamEmpty.Error(fmt.Errorf("pathfile is empty"))
} }
s.m.RLock()
defer s.m.RUnlock()
obj, err := s.c.ReadFile(pathFile) obj, err := s.c.ReadFile(pathFile)
if err != nil && errors.Is(err, fs.ErrNotExist) { if err != nil && errors.Is(err, fs.ErrNotExist) {
@@ -159,9 +151,6 @@ func (s *staticHandler) _fileTemp(pathFile string) (libfpg.Progress, liberr.Erro
return nil, ErrorParamEmpty.Error(fmt.Errorf("pathfile is empty")) return nil, ErrorParamEmpty.Error(fmt.Errorf("pathfile is empty"))
} }
s.m.RLock()
defer s.m.RUnlock()
var tmp libfpg.Progress var tmp libfpg.Progress
obj, err := s.c.Open(pathFile) obj, err := s.c.Open(pathFile)

View File

@@ -35,6 +35,8 @@ import (
"path" "path"
"strings" "strings"
"github.com/nabbar/golib/router/header"
ginsdk "github.com/gin-gonic/gin" ginsdk "github.com/gin-gonic/gin"
ginrdr "github.com/gin-gonic/gin/render" ginrdr "github.com/gin-gonic/gin/render"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
@@ -50,18 +52,53 @@ func (s *staticHandler) _makeRoute(group, route string) string {
return path.Join(group, route) return path.Join(group, route)
} }
func (s *staticHandler) RegisterRouter(route string, register librtr.RegisterRouter, router ...ginsdk.HandlerFunc) { func (s *staticHandler) genRegisterRouter(route, group string, register any, router ...ginsdk.HandlerFunc) {
s._setRouter(append(s._getRouter(), s._makeRoute(urlPathSeparator, route))) var (
ok bool
rte string
reg librtr.RegisterRouter
grp librtr.RegisterRouterInGroup
)
if register == nil {
return
} else if reg, ok = register.(librtr.RegisterRouter); ok {
rte = s._makeRoute(urlPathSeparator, route)
grp = nil
} else if grp, ok = register.(librtr.RegisterRouterInGroup); ok {
rte = s._makeRoute(group, route)
reg = nil
} else {
return
}
if len(router) > 0 {
router = append(router, s.Get) router = append(router, s.Get)
register(http.MethodGet, path.Join(route, urlPathSeparator+"*file"), router...) } else {
router = append(make([]ginsdk.HandlerFunc, 0), s.Get)
}
if rtr := s._getRouter(); len(rtr) > 0 {
s._setRouter(append(rtr, rte))
} else {
s._setRouter(append(make([]string, 0), rte))
}
if reg != nil {
reg(http.MethodGet, path.Join(route, urlPathSeparator+"*file"), router...)
}
if grp != nil {
grp(group, http.MethodGet, path.Join(route, urlPathSeparator+"*file"), router...)
}
}
func (s *staticHandler) RegisterRouter(route string, register librtr.RegisterRouter, router ...ginsdk.HandlerFunc) {
s.genRegisterRouter(route, "", register, router...)
} }
func (s *staticHandler) RegisterRouterInGroup(route, group string, register librtr.RegisterRouterInGroup, router ...ginsdk.HandlerFunc) { func (s *staticHandler) RegisterRouterInGroup(route, group string, register librtr.RegisterRouterInGroup, router ...ginsdk.HandlerFunc) {
s._setRouter(append(s._getRouter(), s._makeRoute(group, route))) s.genRegisterRouter(route, group, register, router...)
router = append(router, s.Get)
register(group, http.MethodGet, path.Join(route, urlPathSeparator+"*file"), router...)
} }
func (s *staticHandler) Get(c *ginsdk.Context) { func (s *staticHandler) Get(c *ginsdk.Context) {
@@ -139,7 +176,7 @@ func (s *staticHandler) Get(c *ginsdk.Context) {
} }
func (s *staticHandler) SendFile(c *ginsdk.Context, filename string, size int64, isDownload bool, buf io.ReadCloser) { func (s *staticHandler) SendFile(c *ginsdk.Context, filename string, size int64, isDownload bool, buf io.ReadCloser) {
head := librtr.NewHeaders() head := header.NewHeaders()
if isDownload { if isDownload {
head.Add("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", path.Base(filename))) head.Add("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", path.Base(filename)))

View File

@@ -26,36 +26,22 @@
package static package static
import "sync/atomic"
func (s *staticHandler) _getRouter() []string { func (s *staticHandler) _getRouter() []string {
s.m.Lock()
defer s.m.Unlock()
var def = make([]string, 0)
if s.r == nil {
return def
}
if i := s.r.Load(); i == nil { if i := s.r.Load(); i == nil {
return def return make([]string, 0)
} else if o, ok := i.([]string); !ok { } else if o, ok := i.([]string); !ok {
return def return make([]string, 0)
} else { } else {
return o return o
} }
} }
func (s *staticHandler) _setRouter(val []string) { func (s *staticHandler) _setRouter(val []string) {
s.m.Lock() var rtr = make([]string, 0)
defer s.m.Unlock()
if val == nil { if len(val) > 0 {
val = make([]string, 0) copy(rtr, val)
} }
if s.r == nil { s.r.Store(rtr)
s.r = new(atomic.Value)
}
s.r.Store(val)
} }