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
import (
librtr "github.com/nabbar/golib/router"
librtr "github.com/nabbar/golib/router/header"
spfcbr "github.com/spf13/cobra"
spfvpr "github.com/spf13/viper"
)

View File

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

View File

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

View File

@@ -31,7 +31,6 @@ import (
"sync"
ginsdk "github.com/gin-gonic/gin"
libctx "github.com/nabbar/golib/context"
libmet "github.com/nabbar/golib/prometheus/metrics"
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 (
"fmt"
"net/http"
"strings"
liblog "github.com/nabbar/golib/logger"
ginsdk "github.com/gin-gonic/gin"
liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger"
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 {
log liblog.FuncLog
check func(AuthHeader string) (AuthCode, liberr.Error)
check func(AuthHeader string) (rtrhdr.AuthCode, liberr.Error)
router []ginsdk.HandlerFunc
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 {
a.router = router
return a.Handler
@@ -112,10 +62,10 @@ func (a *authorization) logDebug(msg string, args ...interface{}) {
func (a *authorization) Handler(c *ginsdk.Context) {
// 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 == "" {
AuthRequire(c, fmt.Errorf("%v", ErrorHeaderAuthMissing.Error(nil).GetErrorSlice()))
rtrhdr.AuthRequire(c, fmt.Errorf("%v", librtr.ErrorHeaderAuthMissing.Error(nil).GetErrorSlice()))
return
}
@@ -129,24 +79,24 @@ func (a *authorization) Handler(c *ginsdk.Context) {
}
if authValue == "" {
AuthRequire(c, fmt.Errorf("%v", ErrorHeaderAuthEmpty.Error(nil).GetErrorSlice()))
rtrhdr.AuthRequire(c, fmt.Errorf("%v", librtr.ErrorHeaderAuthEmpty.Error(nil).GetErrorSlice()))
return
} else {
code, err := a.check(authValue)
switch code {
case AUTH_CODE_SUCCESS:
case rtrhdr.AuthCodeSuccess:
for _, r := range a.router {
a.logDebug("Calling router '%s=%s'", c.Request.Method, c.Request.URL.RawPath)
r(c)
}
case AUTH_CODE_REQUIRE:
AuthRequire(c, fmt.Errorf("%v", ErrorHeaderAuthRequire.Error(err).GetErrorSlice()))
case AUTH_CODE_FORBIDDEN:
AuthForbidden(c, fmt.Errorf("%v", ErrorHeaderAuthForbidden.Error(err).GetErrorSlice()))
case rtrhdr.AuthCodeRequire:
rtrhdr.AuthRequire(c, fmt.Errorf("%v", librtr.ErrorHeaderAuthRequire.Error(err).GetErrorSlice()))
case rtrhdr.AuthCodeForbidden:
rtrhdr.AuthForbidden(c, fmt.Errorf("%v", librtr.ErrorHeaderAuthForbidden.Error(err).GetErrorSlice()))
default:
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,
})
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 (
"net/http"
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 {
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 {
return &headers{
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"
)
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) {
// Start timer
c.Set(GinContextStartUnixNanoTime, time.Now().UnixNano())
@@ -78,13 +48,6 @@ func GinLatencyContext(c *ginsdk.Context) {
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) {
// Set Path
if c != nil {
@@ -204,115 +167,3 @@ func GinErrorLog(log liblog.FuncLog) ginsdk.HandlerFunc {
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
import (
"net/http"
"os"
import ginsdk "github.com/gin-gonic/gin"
ginsdk "github.com/gin-gonic/gin"
)
type itm struct {
method string
relative string
router []ginsdk.HandlerFunc
}
func init() {
if os.Getenv("GIN_MODE") == "" {
ginsdk.SetMode(ginsdk.ReleaseMode)
func (o *itm) Same(method, relative string) bool {
if o.method != method {
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)
if o.relative != relative {
return false
}
return e
return true
}
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"
"io"
"os"
"sync"
"sync/atomic"
libfpg "github.com/nabbar/golib/file/progress"
@@ -48,7 +47,7 @@ type Static interface {
RegisterRouter(route string, register librtr.RegisterRouter, 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)
SetIndex(group, route, pathFile string)
@@ -79,15 +78,19 @@ type Static interface {
}
func New(ctx libctx.FuncContext, content embed.FS, embedRootDir ...string) Static {
return &staticHandler{
m: sync.RWMutex{},
l: nil,
s := &staticHandler{
l: new(atomic.Value),
c: content,
b: embedRootDir,
z: 0,
b: new(atomic.Value),
z: new(atomic.Int64),
i: libctx.NewConfig[string](ctx),
d: libctx.NewConfig[string](ctx),
f: libctx.NewConfig[string](ctx),
s: libctx.NewConfig[string](ctx),
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 (
"embed"
"sync"
"sync/atomic"
libctx "github.com/nabbar/golib/context"
@@ -40,62 +39,46 @@ const (
)
type staticHandler struct {
m sync.RWMutex
l func() liblog.Logger
l *atomic.Value // logger
r *atomic.Value // router
h *atomic.Value // monitor
c embed.FS
b []string // base
z int64 // size
b *atomic.Value // base []string
z *atomic.Int64 // size
i libctx.Config[string] // index
d libctx.Config[string] // download
f libctx.Config[string] // follow
s libctx.Config[string] // specific
r *atomic.Value // router
h *atomic.Value // monitor
}
func (s *staticHandler) _setLogger(fct func() liblog.Logger) {
s.m.Lock()
defer s.m.Unlock()
func (s *staticHandler) _setLogger(fct liblog.FuncLog) {
if fct == nil {
fct = s._getDefaultLogger
}
s.l = fct
s.l.Store(fct())
}
func (s *staticHandler) _getLogger() liblog.Logger {
s.m.RLock()
defer s.m.RUnlock()
i := s.l.Load()
var log liblog.Logger
if s.l == nil {
s.m.RUnlock()
log = s._getDefaultLogger()
s.m.RLock()
return log
} else if log = s.l(); log == nil {
s.m.RUnlock()
log = s._getDefaultLogger()
s.m.RLock()
return log
if i == nil {
return s._getDefaultLogger()
} else if l, k := i.(liblog.FuncLog); !k {
return s._getDefaultLogger()
} else if log := l(); log == nil {
return s._getDefaultLogger()
} else {
return log
}
}
func (s *staticHandler) _getDefaultLogger() liblog.Logger {
s.m.Lock()
defer s.m.Unlock()
var log = liblog.New(s.d.GetContext)
s.l = func() liblog.Logger {
return log
}
return log
return liblog.New(s.d.GetContext)
}
func (s *staticHandler) RegisterLogger(log func() liblog.Logger) {
func (s *staticHandler) RegisterLogger(log liblog.FuncLog) {
s._setLogger(log)
}

View File

@@ -41,31 +41,32 @@ import (
)
func (s *staticHandler) _getSize() int64 {
s.m.RLock()
defer s.m.RUnlock()
return s.z
return s.z.Load()
}
func (s *staticHandler) _setSize(size int64) {
s.m.Lock()
defer s.m.Unlock()
s.z = size
s.z.Store(size)
}
func (s *staticHandler) _getBase() []string {
s.m.RLock()
defer s.m.RUnlock()
return s.b
i := s.b.Load()
if i == nil {
return make([]string, 0)
} else if b, k := i.([]string); !k {
return make([]string, 0)
} else {
return b
}
}
func (s *staticHandler) _setBase(base ...string) {
s.m.Lock()
defer s.m.Unlock()
var b = make([]string, 0)
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) {
@@ -73,9 +74,6 @@ func (s *staticHandler) _listEmbed(root string) ([]fs.DirEntry, liberr.Error) {
return nil, ErrorParamEmpty.Error(fmt.Errorf("pathfile is empty"))
}
s.m.RLock()
defer s.m.RUnlock()
val, err := s.c.ReadDir(root)
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"))
}
s.m.RLock()
defer s.m.RUnlock()
var inf fs.FileInfo
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"))
}
s.m.RLock()
defer s.m.RUnlock()
obj, err := s.c.ReadFile(pathFile)
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"))
}
s.m.RLock()
defer s.m.RUnlock()
var tmp libfpg.Progress
obj, err := s.c.Open(pathFile)

View File

@@ -35,6 +35,8 @@ import (
"path"
"strings"
"github.com/nabbar/golib/router/header"
ginsdk "github.com/gin-gonic/gin"
ginrdr "github.com/gin-gonic/gin/render"
liberr "github.com/nabbar/golib/errors"
@@ -50,18 +52,53 @@ func (s *staticHandler) _makeRoute(group, route string) string {
return path.Join(group, route)
}
func (s *staticHandler) RegisterRouter(route string, register librtr.RegisterRouter, router ...ginsdk.HandlerFunc) {
s._setRouter(append(s._getRouter(), s._makeRoute(urlPathSeparator, route)))
func (s *staticHandler) genRegisterRouter(route, group string, register any, router ...ginsdk.HandlerFunc) {
var (
ok bool
rte string
reg librtr.RegisterRouter
grp librtr.RegisterRouterInGroup
)
router = append(router, s.Get)
register(http.MethodGet, path.Join(route, urlPathSeparator+"*file"), router...)
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)
} 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) {
s._setRouter(append(s._getRouter(), s._makeRoute(group, route)))
router = append(router, s.Get)
register(group, http.MethodGet, path.Join(route, urlPathSeparator+"*file"), router...)
s.genRegisterRouter(route, group, register, router...)
}
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) {
head := librtr.NewHeaders()
head := header.NewHeaders()
if isDownload {
head.Add("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", path.Base(filename)))

View File

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