Package HTTP Client:

- Add DNS Mapper to force destination for a fqdn source
- Allow wildcard and multi wildcard for fqdn source
- DNS Mapper create Transport, Dialer & http client
- DNS Mapper allow a config input to customize timeout, limit and TLS config
- DNS Mapper use a gloabl transport connection poller
- DNS Mapper implement DialContext & Dial method for transport
- DNS Mapper use cache to accelerate process
- DNS Mapper cache is only dnsmapper, not DNS cache
- Replace old helper for http client with DNSMapper
- Add default DNSMapper into the main lib of http client
- Allow to overide the default DNS Mapper with a new one
- Add ticker to force clean idle connection every given duration
- "Compatible" with old config, as the default config will be used instead of old client build
- Clean code and fix minor bugs
- Add config component to allow use a global config
- Config Component httpcli can overide default httpcli dns mapper when updated

Package Certificates
- Add function type to impose function that return a slice of rootCA string
- update config/component/tls by replacing mutex with atomic
- optimize some code

Package Config
- expand errors code index to add component httpcli

Package Config/component:
- database: add new validation, that config key existing into viper
- head: add new validation, that config key existing into viper
- http: add new validation, that config key existing into viper
- ldap: add new validation, that config key existing into viper
- log: add new validation, that config key existing into viper
- mail: add new validation, that config key existing into viper
- smtp: add new validation, that config key existing into viper

Package AWS:
- update package following update of httpcli
- use interface for http cli that implement the Do function
- update following the config/component/aws
- rework config/component/aws to use atomic instead of mutex
- update test unit following change

Package Request:
- update following http client update
- use interface of HTTP Client that implement DO function, instead of http client struct pointer
- update config & code following
- apply same modification into config/component/request
- update config/component/request by replacing mutex to atomic

Package Server
- add function Uptime to model to expose the duration since last start

Package Semaphore
- apply change name of constant following bump of lib associated

Package Crypt
- fix bug into reader to remove suffix of EOF if prevent

Package Errors:
- expand index module to add DNS Mapper client

Package HTTP Server:
- update monitor to apply changes

Package Socket:
- add additional check if reading error: if buffer has data, send it to handler before break run

Other:
- bump dependencies
This commit is contained in:
Nicolas JUHEL
2024-02-16 14:09:54 +01:00
parent eaf88e00b7
commit ae0a6b62c9
84 changed files with 2103 additions and 816 deletions

View File

@@ -92,8 +92,7 @@ var _ = BeforeSuite(func() {
secretKey = libpwd.Generate(64)
)
htp, err = libhtc.GetClient(libhtc.GetTransport(false, false, false), true, libhtc.ClientTimeout30Sec)
Expect(err).NotTo(HaveOccurred())
htp = libhtc.GetClient()
Expect(htp).NotTo(BeNil())
cfg = awscfg.NewConfig("", accessKey, secretKey, uri, "us-east-1")
@@ -119,7 +118,8 @@ var _ = BeforeSuite(func() {
Expect(err).NotTo(HaveOccurred())
Expect(cli).NotTo(BeNil())
cli.ForcePathStyle(ctx, true)
err = cli.ForcePathStyle(ctx, true)
Expect(err).NotTo(HaveOccurred())
name, err = lbuuid.GenerateUUID()
Expect(err).ToNot(HaveOccurred())

View File

@@ -45,9 +45,8 @@ type Model struct {
}
type ModelStatus struct {
Config Model `json:"config" yaml:"config" toml:"config" mapstructure:"config" validate:"required"`
HTTPClient libhtc.Options `json:"http-client" yaml:"http-client" toml:"http-client" mapstructure:"http-client" validate:""`
Monitor libreq.OptionsHealth `json:"health" yaml:"health" toml:"health" mapstructure:"health" validate:""`
Config Model `json:"config" yaml:"config" toml:"config" mapstructure:"config" validate:"required"`
Monitor libreq.OptionsHealth `json:"health" yaml:"health" toml:"health" mapstructure:"health" validate:""`
}
type awsModel struct {

View File

@@ -47,9 +47,8 @@ type Model struct {
}
type ModelStatus struct {
Config Model `json:"config" yaml:"config" toml:"config" mapstructure:"config" validate:"required"`
HTTPClient libhtc.Options `json:"http-client" yaml:"http-client" toml:"http-client" mapstructure:"http-client" validate:""`
Monitor libreq.OptionsHealth `json:"health" yaml:"health" toml:"health" mapstructure:"health" validate:""`
Config Model `json:"config" yaml:"config" toml:"config" mapstructure:"config" validate:"required"`
Monitor libreq.OptionsHealth `json:"health" yaml:"health" toml:"health" mapstructure:"health" validate:""`
}
type awsModel struct {

View File

@@ -36,6 +36,7 @@ import (
type FctHttpClient func(def TLSConfig, servername string) *http.Client
type FctTLSDefault func() TLSConfig
type FctRootCA func() []string
type TLSConfig interface {
AddRootCAString(rootCA string) bool

View File

@@ -27,12 +27,8 @@
package aws
import (
"net/http"
libaws "github.com/nabbar/golib/aws"
libtls "github.com/nabbar/golib/certificates"
cfgtps "github.com/nabbar/golib/config/types"
libhtc "github.com/nabbar/golib/httpcli"
libreq "github.com/nabbar/golib/request"
libver "github.com/nabbar/golib/version"
libvpr "github.com/nabbar/golib/viper"
@@ -40,9 +36,6 @@ import (
)
func (o *componentAws) _getKey() string {
o.m.RLock()
defer o.m.RUnlock()
if i, l := o.x.Load(keyCptKey); !l {
return ""
} else if i == nil {
@@ -54,32 +47,7 @@ func (o *componentAws) _getKey() string {
}
}
func (o *componentAws) _getTLS() libtls.TLSConfig {
o.m.RLock()
defer o.m.RUnlock()
if o.t == nil {
return nil
}
return o.t()
}
func (o *componentAws) _getHttpClient() *http.Client {
o.m.RLock()
defer o.m.RUnlock()
if o.c == nil {
return &http.Client{}
}
return o.c()
}
func (o *componentAws) _getFctVpr() libvpr.FuncViper {
o.m.RLock()
defer o.m.RUnlock()
if i, l := o.x.Load(keyFctViper); !l {
return nil
} else if i == nil {
@@ -112,9 +80,6 @@ func (o *componentAws) _getSPFViper() *spfvbr.Viper {
}
func (o *componentAws) _getFctCpt() cfgtps.FuncCptGet {
o.m.RLock()
defer o.m.RUnlock()
if i, l := o.x.Load(keyFctGetCpt); !l {
return nil
} else if i == nil {
@@ -127,9 +92,6 @@ func (o *componentAws) _getFctCpt() cfgtps.FuncCptGet {
}
func (o *componentAws) _getVersion() libver.Version {
o.m.RLock()
defer o.m.RUnlock()
if i, l := o.x.Load(keyCptVersion); !l {
return nil
} else if i == nil {
@@ -150,9 +112,6 @@ func (o *componentAws) _getFct() (cfgtps.FuncCptEvent, cfgtps.FuncCptEvent) {
}
func (o *componentAws) _getFctEvt(key uint8) cfgtps.FuncCptEvent {
o.m.RLock()
defer o.m.RUnlock()
if i, l := o.x.Load(key); !l {
return nil
} else if i == nil {
@@ -178,7 +137,6 @@ func (o *componentAws) _runCli() error {
cli libaws.AWS
cfg libaws.Config
mon *libreq.OptionsHealth
htc *libhtc.Options
opt *libreq.Options
req libreq.Request
prt = ErrorComponentReload
@@ -188,51 +146,33 @@ func (o *componentAws) _runCli() error {
prt = ErrorComponentStart
}
if cfg, mon, htc, err = o._getConfig(); err != nil {
if cfg, mon, err = o._getConfig(); err != nil {
return prt.Error(err)
}
if htc != nil {
var h = *htc
o.RegisterHTTPClient(func() *http.Client {
if cl, er := h.GetClient(o._getTLS(), ""); er == nil {
return cl
}
return &http.Client{}
})
}
if cli, err = libaws.New(o.x.GetContext(), cfg, o._getHttpClient()); err != nil {
if cli, err = libaws.New(o.x.GetContext(), cfg, o.getClient()); err != nil {
return prt.Error(err)
}
if mon != nil && mon.Enable {
opt = &libreq.Options{
Endpoint: "",
HttpClient: *htc,
Auth: libreq.OptionsAuth{},
Health: *mon,
Endpoint: "",
Auth: libreq.OptionsAuth{},
Health: *mon,
}
opt.SetDefaultTLS(o._getTLS)
opt.SetDefaultLog(o.getLogger)
o.m.Lock()
req = o.r
o.m.Unlock()
if req != nil {
if req = o.getRequest(); req != nil {
if req, err = opt.Update(o.x.GetContext, req); err != nil {
return prt.Error(err)
}
} else if req, err = opt.New(o.x.GetContext); err != nil {
req.RegisterHTTPClient(o.getClient())
} else if req, err = opt.New(o.x.GetContext, o.getClient()); err != nil {
return prt.Error(err)
}
o.m.Lock()
o.r = req
o.m.Unlock()
o.setRequest(req)
}
if mon != nil {
@@ -241,9 +181,7 @@ func (o *componentAws) _runCli() error {
}
}
o.m.Lock()
o.a = cli
o.m.Unlock()
o.SetAws(cli)
return nil
}

View File

@@ -55,17 +55,6 @@ func (o *componentAws) Type() string {
}
func (o *componentAws) Init(key string, ctx libctx.FuncContext, get cfgtps.FuncCptGet, vpr libvpr.FuncViper, vrs libver.Version, log liblog.FuncLog) {
o.m.Lock()
defer o.m.Unlock()
if o.x == nil {
o.x = libctx.NewConfig[uint8](ctx)
} else {
x := libctx.NewConfig[uint8](ctx)
x.Merge(o.x)
o.x = x
}
o.x.Store(keyCptKey, key)
o.x.Store(keyFctGetCpt, get)
o.x.Store(keyFctViper, vpr)
@@ -84,10 +73,11 @@ func (o *componentAws) RegisterFuncReload(before, after cfgtps.FuncCptEvent) {
}
func (o *componentAws) IsStarted() bool {
o.m.RLock()
defer o.m.RUnlock()
if o.s.Load() {
return o.getAws() != nil
}
return o.a != nil
return false
}
func (o *componentAws) IsRunning() bool {
@@ -95,6 +85,7 @@ func (o *componentAws) IsRunning() bool {
}
func (o *componentAws) Start() error {
o.s.Store(true)
return o._run()
}
@@ -103,17 +94,11 @@ func (o *componentAws) Reload() error {
}
func (o *componentAws) Stop() {
o.m.Lock()
defer o.m.Unlock()
o.a = nil
o.s.Store(false)
return
}
func (o *componentAws) Dependencies() []string {
o.m.RLock()
defer o.m.RUnlock()
var def = make([]string, 0)
if o == nil {
@@ -132,9 +117,6 @@ func (o *componentAws) Dependencies() []string {
}
func (o *componentAws) SetDependencies(d []string) error {
o.m.RLock()
defer o.m.RUnlock()
if o.x == nil {
return ErrorComponentNotInitialized.Error(nil)
} else {

View File

@@ -27,10 +27,11 @@
package aws
import (
"fmt"
libaws "github.com/nabbar/golib/aws"
cfgstd "github.com/nabbar/golib/aws/configAws"
cfgcus "github.com/nabbar/golib/aws/configCustom"
libhtc "github.com/nabbar/golib/httpcli"
libreq "github.com/nabbar/golib/request"
libvpr "github.com/nabbar/golib/viper"
spfcbr "github.com/spf13/cobra"
@@ -111,102 +112,93 @@ func (o *componentAws) RegisterFlag(Command *spfcbr.Command) error {
return nil
}
func (o *componentAws) _getConfig() (libaws.Config, *libreq.OptionsHealth, *libhtc.Options, error) {
func (o *componentAws) _getConfig() (libaws.Config, *libreq.OptionsHealth, error) {
var (
key string
cfg libaws.Config
flg = o._getFlagUpdate()
mon *libreq.OptionsHealth
htc *libhtc.Options
vpr libvpr.Viper
err error
)
if vpr = o._getViper(); vpr == nil {
return nil, nil, nil, ErrorComponentNotInitialized.Error(nil)
return nil, nil, ErrorComponentNotInitialized.Error(nil)
} else if key = o._getKey(); len(key) < 1 {
return nil, nil, nil, ErrorComponentNotInitialized.Error(nil)
return nil, nil, ErrorComponentNotInitialized.Error(nil)
} else if !vpr.Viper().IsSet(key) {
return nil, nil, ErrorParamInvalid.Error(fmt.Errorf("missing config key '%s'", key))
}
switch o.d {
case ConfigCustomStatus:
cnf := cfgcus.ModelStatus{}
if err = vpr.UnmarshalKey(key, &cnf); err != nil {
return nil, nil, nil, ErrorParamInvalid.Error(err)
return nil, nil, ErrorParamInvalid.Error(err)
} else {
flg.updCustom(&cnf.Config)
}
if cfg, err = o.d.NewFromModel(cnf); err != nil {
return nil, nil, nil, err
return nil, nil, err
} else {
mon = &cnf.Monitor
htc = &cnf.HTTPClient
}
case ConfigCustom:
cnf := cfgcus.Model{}
if err = vpr.UnmarshalKey(key, &cnf); err != nil {
return nil, nil, nil, ErrorParamInvalid.Error(err)
return nil, nil, ErrorParamInvalid.Error(err)
} else {
flg.updCustom(&cnf)
}
if cfg, err = o.d.NewFromModel(cnf); err != nil {
return nil, nil, nil, err
return nil, nil, err
} else {
mon = nil
htc = nil
}
case ConfigStandardStatus:
cnf := cfgstd.ModelStatus{}
if err = vpr.UnmarshalKey(key, &cnf); err != nil {
return nil, nil, nil, ErrorParamInvalid.Error(err)
return nil, nil, ErrorParamInvalid.Error(err)
} else {
flg.updStandard(&cnf.Config)
}
if cfg, err = o.d.NewFromModel(cnf); err != nil {
return nil, nil, nil, err
return nil, nil, err
} else {
mon = &cnf.Monitor
htc = &cnf.HTTPClient
}
case ConfigStandard:
cnf := cfgstd.Model{}
if err = vpr.UnmarshalKey(key, &cnf); err != nil {
return nil, nil, nil, ErrorParamInvalid.Error(err)
return nil, nil, ErrorParamInvalid.Error(err)
} else {
flg.updStandard(&cnf)
}
if cfg, err = o.d.NewFromModel(cnf); err != nil {
return nil, nil, nil, err
return nil, nil, err
} else {
mon = nil
htc = nil
}
}
if err = cfg.Validate(); err != nil {
return nil, nil, nil, ErrorConfigInvalid.Error(err)
return nil, nil, ErrorConfigInvalid.Error(err)
}
if mon != nil {
if err = mon.Validate(); err != nil {
return nil, nil, nil, ErrorConfigInvalid.Error(err)
return nil, nil, ErrorConfigInvalid.Error(err)
}
}
if htc != nil {
if err = htc.Validate(); err != nil {
return nil, nil, nil, ErrorConfigInvalid.Error(err)
}
}
return cfg, mon, htc, nil
return cfg, mon, nil
}
func (o *componentAws) _getFlagUpdate() *_configFlag {

View File

@@ -45,7 +45,6 @@ var _defaultConfigStandard = []byte(`{
var _defaultConfigStandardWithStatus = []byte(`{
"config":` + string(DefaultConfigStandard(cfgcst.JSONIndent+cfgcst.JSONIndent)) + `,
"http-client":` + string(libhtc.DefaultConfig(cfgcst.JSONIndent+cfgcst.JSONIndent)) + `,
"health":` + string(montps.DefaultConfig(cfgcst.JSONIndent+cfgcst.JSONIndent)) + `
}`)

View File

@@ -27,39 +27,33 @@
package aws
import (
"net/http"
"sync"
"sync/atomic"
libaws "github.com/nabbar/golib/aws"
libtls "github.com/nabbar/golib/certificates"
libcfg "github.com/nabbar/golib/config"
cfgtps "github.com/nabbar/golib/config/types"
libctx "github.com/nabbar/golib/context"
libhtc "github.com/nabbar/golib/httpcli"
)
type ComponentAwsClient interface {
cfgtps.Component
RegisterHTTPClient(fct func() *http.Client)
}
type ComponentAwsAPI interface {
cfgtps.Component
RegisterTLS(fct libtls.FctTLSDefault)
}
type ComponentAws interface {
ComponentAwsClient
ComponentAwsAPI
cfgtps.Component
GetAws() (libaws.AWS, error)
GetAws() libaws.AWS
SetAws(a libaws.AWS)
RegisterHTTPClient(cli libhtc.HttpClient)
}
func New(drv ConfigDriver) ComponentAws {
func New(ctx libctx.FuncContext, drv ConfigDriver) ComponentAws {
return &componentAws{
m: sync.RWMutex{},
x: nil,
x: libctx.NewConfig[uint8](ctx),
d: drv,
a: nil,
p: new(atomic.Value),
c: new(atomic.Value),
a: new(atomic.Value),
r: new(atomic.Value),
s: new(atomic.Bool),
}
}
@@ -67,8 +61,8 @@ func Register(cfg libcfg.Config, key string, cpt ComponentAws) {
cfg.ComponentSet(key, cpt)
}
func RegisterNew(cfg libcfg.Config, drv ConfigDriver, key string) {
cfg.ComponentSet(key, New(drv))
func RegisterNew(ctx libctx.FuncContext, cfg libcfg.Config, drv ConfigDriver, key string) {
cfg.ComponentSet(key, New(ctx, drv))
}
func Load(getCpt cfgtps.FuncCptGet, key string) ComponentAws {

View File

@@ -27,56 +27,101 @@
package aws
import (
"net/http"
"sync"
libreq "github.com/nabbar/golib/request"
"sync/atomic"
libaws "github.com/nabbar/golib/aws"
libtls "github.com/nabbar/golib/certificates"
libctx "github.com/nabbar/golib/context"
libhtc "github.com/nabbar/golib/httpcli"
montps "github.com/nabbar/golib/monitor/types"
libreq "github.com/nabbar/golib/request"
)
type componentAws struct {
m sync.RWMutex
x libctx.Config[uint8]
d ConfigDriver
p montps.FuncPool
c func() *http.Client
t libtls.FctTLSDefault
a libaws.AWS
r libreq.Request
p *atomic.Value // montps.FuncPool
c *atomic.Value // libhtc.HTTPClient
a *atomic.Value // libaws.AWS
r *atomic.Value // libreq.Request
s *atomic.Bool // status running == true
}
func (o *componentAws) RegisterHTTPClient(fct func() *http.Client) {
o.m.Lock()
defer o.m.Unlock()
func (o *componentAws) RegisterHTTPClient(cli libhtc.HttpClient) {
if cli == nil {
cli = libhtc.GetClient()
}
o.c = fct
o.c.Store(cli)
}
func (o *componentAws) RegisterTLS(fct libtls.FctTLSDefault) {
o.m.Lock()
defer o.m.Unlock()
func (o *componentAws) GetAws() libaws.AWS {
if o.s.Load() {
return o.getAws()
}
o.t = fct
return nil
}
func (o *componentAws) GetAws() (libaws.AWS, error) {
o.m.RLock()
defer o.m.RUnlock()
if o.a == nil {
return nil, ErrorComponentNotInitialized.Error(nil)
func (o *componentAws) getAws() libaws.AWS {
if i := o.a.Load(); i == nil {
return nil
} else if v, k := i.(libaws.AWS); !k {
return nil
} else {
return o.a.Clone(o.x.GetContext())
return v
}
}
func (o *componentAws) SetAws(a libaws.AWS) {
o.m.Lock()
defer o.m.Unlock()
o.a = a
func (o *componentAws) SetAws(cli libaws.AWS) {
if cli != nil {
o.a.Store(cli)
}
}
func (o *componentAws) getPool() montps.Pool {
if i := o.p.Load(); i == nil {
return nil
} else if v, k := i.(montps.FuncPool); !k {
return nil
} else if p := v(); p == nil {
return nil
} else {
return p
}
}
func (o *componentAws) RegisterMonitorPool(fct montps.FuncPool) {
if fct == nil {
fct = func() montps.Pool {
return nil
}
}
o.p.Store(fct)
}
func (o *componentAws) getClient() libhtc.HttpClient {
if i := o.c.Load(); i == nil {
return libhtc.GetClient()
} else if v, k := i.(libhtc.HttpClient); !k {
return libhtc.GetClient()
} else {
return v
}
}
func (o *componentAws) getRequest() libreq.Request {
if i := o.r.Load(); i == nil {
return nil
} else if v, k := i.(libreq.Request); !k {
return nil
} else {
return v
}
}
func (o *componentAws) setRequest(req libreq.Request) {
if req != nil {
o.r.Store(req)
}
}

View File

@@ -31,38 +31,17 @@ import (
"fmt"
"runtime"
libreq "github.com/nabbar/golib/request"
libaws "github.com/nabbar/golib/aws"
libmon "github.com/nabbar/golib/monitor"
moninf "github.com/nabbar/golib/monitor/info"
montps "github.com/nabbar/golib/monitor/types"
libreq "github.com/nabbar/golib/request"
)
const (
defaultNameMonitor = "AWS Client"
)
func (o *componentAws) RegisterMonitorPool(fct montps.FuncPool) {
o.m.Lock()
defer o.m.Unlock()
o.p = fct
}
func (o *componentAws) _getMonitorPool() montps.Pool {
o.m.RLock()
defer o.m.RUnlock()
if o.p == nil {
return nil
} else if p := o.p(); p == nil {
return nil
} else {
return p
}
}
func (o *componentAws) _registerMonitor(opt *libreq.OptionsHealth, aws libaws.Config) error {
var (
e error
@@ -73,7 +52,7 @@ func (o *componentAws) _registerMonitor(opt *libreq.OptionsHealth, aws libaws.Co
vrs = o._getVersion()
)
if o._getMonitorPool() == nil {
if o.getPool() == nil {
return nil
} else if len(key) < 1 {
return ErrorComponentNotInitialized.Error(nil)
@@ -133,10 +112,7 @@ func (o *componentAws) _registerMonitor(opt *libreq.OptionsHealth, aws libaws.Co
}
func (o *componentAws) _getEndpoint(opt *libreq.OptionsHealth, aws libaws.Config) string {
o.m.RLock()
defer o.m.RUnlock()
if o.r != nil && len(opt.Endpoint) > 0 {
if req := o.getRequest(); req != nil && len(opt.Endpoint) > 0 {
return opt.Endpoint
} else {
return aws.GetEndpoint().Host
@@ -157,7 +133,7 @@ func (o *componentAws) _newMonitor(inf montps.Info) (montps.Monitor, error) {
func (o *componentAws) _getMonitor(key string, inf montps.Info) montps.Monitor {
var (
mon libmon.Monitor
pol = o._getMonitorPool()
pol = o.getPool()
)
if pol == nil {
@@ -175,7 +151,7 @@ func (o *componentAws) _getMonitor(key string, inf montps.Info) montps.Monitor {
}
func (o *componentAws) _setMonitor(mon montps.Monitor) error {
var pol = o._getMonitorPool()
var pol = o.getPool()
if pol == nil {
return nil
@@ -185,14 +161,11 @@ func (o *componentAws) _setMonitor(mon montps.Monitor) error {
}
func (o *componentAws) HealthCheck(ctx context.Context) error {
o.m.RLock()
defer o.m.RUnlock()
if !o.IsStarted() {
if cli := o.GetAws(); cli == nil {
return fmt.Errorf("component not started")
} else if o.r == nil {
return o.a.Config().Check(ctx)
} else if req := o.getRequest(); req == nil {
return cli.Config().Check(ctx)
} else {
return o.r.HealthCheck(ctx)
return req.HealthCheck(ctx)
}
}

View File

@@ -29,9 +29,8 @@ package database
import (
"context"
"github.com/nabbar/golib/database/gorm"
cfgtps "github.com/nabbar/golib/config/types"
libdbs "github.com/nabbar/golib/database/gorm"
libver "github.com/nabbar/golib/version"
libvpr "github.com/nabbar/golib/viper"
spfvbr "github.com/spf13/viper"
@@ -159,8 +158,8 @@ func (o *componentDatabase) _runCli() error {
var (
err error
prt = ErrorComponentReload
dbo gorm.Database
cfg *gorm.Config
dbo libdbs.Database
cfg *libdbs.Config
)
if !o.IsStarted() {
@@ -171,7 +170,7 @@ func (o *componentDatabase) _runCli() error {
return prt.Error(err)
}
if dbo, err = gorm.New(cfg); err != nil {
if dbo, err = libdbs.New(cfg); err != nil {
return prt.Error(err)
}

View File

@@ -27,12 +27,11 @@
package database
import (
"fmt"
"time"
libdbs "github.com/nabbar/golib/database/gorm"
libvpr "github.com/nabbar/golib/viper"
"github.com/nabbar/golib/database/gorm"
spfcbr "github.com/spf13/cobra"
spfvpr "github.com/spf13/viper"
)
@@ -109,10 +108,10 @@ func (o *componentDatabase) RegisterFlag(Command *spfcbr.Command) error {
return nil
}
func (o *componentDatabase) _getConfig() (*gorm.Config, error) {
func (o *componentDatabase) _getConfig() (*libdbs.Config, error) {
var (
key string
cfg gorm.Config
cfg libdbs.Config
vpr libvpr.Viper
err error
)
@@ -121,9 +120,9 @@ func (o *componentDatabase) _getConfig() (*gorm.Config, error) {
return nil, ErrorComponentNotInitialized.Error(nil)
} else if key = o._getKey(); len(key) < 1 {
return nil, ErrorComponentNotInitialized.Error(nil)
}
if e := vpr.UnmarshalKey(key, &cfg); e != nil {
} else if !vpr.Viper().IsSet(key) {
return nil, ErrorParamInvalid.Error(fmt.Errorf("missing config key '%s'", key))
} else if e := vpr.UnmarshalKey(key, &cfg); e != nil {
return nil, ErrorParamInvalid.Error(e)
}
@@ -131,7 +130,7 @@ func (o *componentDatabase) _getConfig() (*gorm.Config, error) {
cfg.RegisterContext(o.x.GetContext)
if val := vpr.GetString(key + ".driver"); val != "" {
cfg.Driver = gorm.DriverFromString(val)
cfg.Driver = libdbs.DriverFromString(val)
}
if val := vpr.GetString(key + ".name"); val != "" {
cfg.Name = val

View File

@@ -30,11 +30,10 @@ import (
"sync"
"time"
libdbs "github.com/nabbar/golib/database/gorm"
libcfg "github.com/nabbar/golib/config"
cfgtps "github.com/nabbar/golib/config/types"
libctx "github.com/nabbar/golib/context"
libdbs "github.com/nabbar/golib/database/gorm"
)
type ComponentDatabase interface {

View File

@@ -30,9 +30,8 @@ import (
"sync"
"time"
libdbs "github.com/nabbar/golib/database/gorm"
libctx "github.com/nabbar/golib/context"
libdbs "github.com/nabbar/golib/database/gorm"
montps "github.com/nabbar/golib/monitor/types"
)

View File

@@ -27,6 +27,8 @@
package head
import (
"fmt"
librtr "github.com/nabbar/golib/router/header"
libvpr "github.com/nabbar/golib/viper"
spfcbr "github.com/spf13/cobra"
@@ -48,9 +50,9 @@ func (o *componentHead) _getConfig() (*librtr.HeadersConfig, error) {
return nil, ErrorComponentNotInitialized.Error(nil)
} else if key = o._getKey(); len(key) < 1 {
return nil, ErrorComponentNotInitialized.Error(nil)
}
if e := vpr.UnmarshalKey(key, &cfg); e != nil {
} else if !vpr.Viper().IsSet(key) {
return nil, ErrorParamInvalid.Error(fmt.Errorf("missing config key '%s'", key))
} else if e := vpr.UnmarshalKey(key, &cfg); e != nil {
return nil, ErrorParamInvalid.Error(e)
}

View File

@@ -29,10 +29,9 @@ 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/header"
)
type ComponentHead interface {

View File

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

View File

@@ -29,9 +29,8 @@ package http
import (
"fmt"
libvpr "github.com/nabbar/golib/viper"
htpool "github.com/nabbar/golib/httpserver/pool"
libvpr "github.com/nabbar/golib/viper"
spfcbr "github.com/spf13/cobra"
)
@@ -51,9 +50,9 @@ func (o *componentHttp) _getConfig() (*htpool.Config, error) {
return nil, ErrorComponentNotInitialized.Error(nil)
} else if key = o._getKey(); len(key) < 1 {
return nil, ErrorComponentNotInitialized.Error(nil)
}
if e := vpr.UnmarshalKey(key, &cfg); e != nil {
} else if !vpr.Viper().IsSet(key) {
return nil, ErrorParamInvalid.Error(fmt.Errorf("missing config key '%s'", key))
} else if e := vpr.UnmarshalKey(key, &cfg); e != nil {
return nil, ErrorParamInvalid.Error(e)
}

View File

@@ -0,0 +1,171 @@
/*
* MIT License
*
* Copyright (c) 2022 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 httpcli
import (
"fmt"
cfgtps "github.com/nabbar/golib/config/types"
htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
libver "github.com/nabbar/golib/version"
libvpr "github.com/nabbar/golib/viper"
spfvbr "github.com/spf13/viper"
)
func (o *componentHttpClient) _getKey() string {
if i, l := o.x.Load(keyCptKey); !l {
return ""
} else if i == nil {
return ""
} else if v, k := i.(string); !k {
return ""
} else {
return v
}
}
func (o *componentHttpClient) _getFctVpr() libvpr.FuncViper {
if i, l := o.x.Load(keyFctViper); !l {
return nil
} else if i == nil {
return nil
} else if f, k := i.(libvpr.FuncViper); !k {
return nil
} else {
return f
}
}
func (o *componentHttpClient) _getViper() libvpr.Viper {
if f := o._getFctVpr(); f == nil {
return nil
} else if v := f(); v == nil {
return nil
} else {
return v
}
}
func (o *componentHttpClient) _getSPFViper() *spfvbr.Viper {
if f := o._getViper(); f == nil {
return nil
} else if v := f.Viper(); v == nil {
return nil
} else {
return v
}
}
func (o *componentHttpClient) _getFctCpt() cfgtps.FuncCptGet {
if i, l := o.x.Load(keyFctGetCpt); !l {
return nil
} else if i == nil {
return nil
} else if f, k := i.(cfgtps.FuncCptGet); !k {
return nil
} else {
return f
}
}
func (o *componentHttpClient) _getVersion() libver.Version {
if i, l := o.x.Load(keyCptVersion); !l {
return nil
} else if i == nil {
return nil
} else if v, k := i.(libver.Version); !k {
return nil
} else {
return v
}
}
func (o *componentHttpClient) _getFct() (cfgtps.FuncCptEvent, cfgtps.FuncCptEvent) {
if o.IsStarted() {
return o._getFctEvt(keyFctRelBef), o._getFctEvt(keyFctRelAft)
} else {
return o._getFctEvt(keyFctStaBef), o._getFctEvt(keyFctStaAft)
}
}
func (o *componentHttpClient) _getFctEvt(key uint8) cfgtps.FuncCptEvent {
if i, l := o.x.Load(key); !l {
return nil
} else if i == nil {
return nil
} else if f, k := i.(cfgtps.FuncCptEvent); !k {
return nil
} else {
return f
}
}
func (o *componentHttpClient) _runFct(fct func(cpt cfgtps.Component) error) error {
if fct != nil {
return fct(o)
}
return nil
}
func (o *componentHttpClient) _runCli() error {
var (
err error
prt = ErrorComponentReload
dns htcdns.DNSMapper
cfg *htcdns.Config
)
if !o.IsStarted() {
prt = ErrorComponentStart
}
if cfg, err = o._getConfig(); err != nil {
return prt.Error(err)
} else if dns = cfg.New(o.x.GetContext(), o.getRootCA); dns == nil {
return prt.Error(fmt.Errorf("cannot create DNS Mapper"))
}
o.setConfig(*cfg)
o.setDNSMapper(dns)
return nil
}
func (o *componentHttpClient) _run() error {
fb, fa := o._getFct()
if err := o._runFct(fb); err != nil {
return err
} else if err = o._runCli(); err != nil {
return err
} else if err = o._runFct(fa); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,130 @@
/*
* MIT License
*
* Copyright (c) 2022 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 httpcli
import (
cfgtps "github.com/nabbar/golib/config/types"
libctx "github.com/nabbar/golib/context"
liblog "github.com/nabbar/golib/logger"
libver "github.com/nabbar/golib/version"
libvpr "github.com/nabbar/golib/viper"
)
const (
ComponentType = "tls"
keyCptKey = iota + 1
keyCptDependencies
keyFctViper
keyFctGetCpt
keyCptVersion
keyCptLogger
keyFctStaBef
keyFctStaAft
keyFctRelBef
keyFctRelAft
keyFctMonitorPool
)
func (o *componentHttpClient) Type() string {
return ComponentType
}
func (o *componentHttpClient) Init(key string, ctx libctx.FuncContext, get cfgtps.FuncCptGet, vpr libvpr.FuncViper, vrs libver.Version, log liblog.FuncLog) {
o.x.Store(keyCptKey, key)
o.x.Store(keyFctGetCpt, get)
o.x.Store(keyFctViper, vpr)
o.x.Store(keyCptVersion, vrs)
o.x.Store(keyCptLogger, log)
}
func (o *componentHttpClient) RegisterFuncStart(before, after cfgtps.FuncCptEvent) {
o.x.Store(keyFctStaBef, before)
o.x.Store(keyFctStaAft, after)
}
func (o *componentHttpClient) RegisterFuncReload(before, after cfgtps.FuncCptEvent) {
o.x.Store(keyFctRelBef, before)
o.x.Store(keyFctRelAft, after)
}
func (o *componentHttpClient) IsStarted() bool {
return o.getDNSMapper() != nil
}
func (o *componentHttpClient) IsRunning() bool {
return o.IsStarted()
}
func (o *componentHttpClient) Start() error {
return o._run()
}
func (o *componentHttpClient) Reload() error {
return o._run()
}
func (o *componentHttpClient) Stop() {
return
}
func (o *componentHttpClient) Dependencies() []string {
var def = make([]string, 0)
if o == nil {
return def
} else if o.x == nil {
return def
} else if i, l := o.x.Load(keyCptDependencies); !l {
return def
} else if v, k := i.([]string); !k {
return def
} else if len(v) > 0 {
return v
} else {
return def
}
}
func (o *componentHttpClient) SetDependencies(d []string) error {
if o.x == nil {
return ErrorComponentNotInitialized.Error(nil)
} else {
o.x.Store(keyCptDependencies, d)
return nil
}
}
func (o *componentHttpClient) getLogger() liblog.Logger {
if i, l := o.x.Load(keyCptLogger); !l {
return nil
} else if v, k := i.(liblog.FuncLog); !k {
return nil
} else {
return v()
}
}

View File

@@ -0,0 +1,62 @@
/*
* MIT License
*
* Copyright (c) 2022 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 httpcli
import (
"fmt"
htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
libvpr "github.com/nabbar/golib/viper"
spfcbr "github.com/spf13/cobra"
)
func (o *componentHttpClient) RegisterFlag(Command *spfcbr.Command) error {
return nil
}
func (o *componentHttpClient) _getConfig() (*htcdns.Config, error) {
var (
key string
cfg htcdns.Config
vpr libvpr.Viper
err error
)
if vpr = o._getViper(); vpr == nil {
return nil, ErrorComponentNotInitialized.Error(nil)
} else if key = o._getKey(); len(key) < 1 {
return nil, ErrorComponentNotInitialized.Error(nil)
} else if !vpr.Viper().IsSet(key) {
return nil, ErrorParamInvalid.Error(fmt.Errorf("missing config key '%s'", key))
} else if e := vpr.UnmarshalKey(key, &cfg); e != nil {
return nil, ErrorParamInvalid.Error(e)
} else if err = cfg.Validate(); err != nil {
return nil, ErrorConfigInvalid.Error(err)
}
return &cfg, nil
}

View File

@@ -0,0 +1,39 @@
/*
* MIT License
*
* Copyright (c) 2022 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 httpcli
import (
htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
)
func DefaultConfig(indent string) []byte {
return htcdns.DefaultConfig(indent)
}
func (o *componentHttpClient) DefaultConfig(indent string) []byte {
return htcdns.DefaultConfig(indent)
}

View File

@@ -0,0 +1,103 @@
/*
* MIT License
*
* Copyright (c) 2022 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 httpcli
import (
"context"
"net"
"net/http"
"time"
htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
)
func (o *componentHttpClient) Add(endpoint string, ip string) {
if d := o.getDNSMapper(); d != nil {
d.Add(endpoint, ip)
o.setDNSMapper(d)
}
}
func (o *componentHttpClient) Get(endpoint string) string {
if d := o.getDNSMapper(); d != nil {
return d.Get(endpoint)
}
return ""
}
func (o *componentHttpClient) Del(endpoint string) {
if d := o.getDNSMapper(); d != nil {
d.Del(endpoint)
o.setDNSMapper(d)
}
}
func (o *componentHttpClient) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
if d := o.getDNSMapper(); d != nil {
return d.DialContext(ctx, network, address)
}
return nil, ErrorComponentNotInitialized.Error()
}
func (o *componentHttpClient) Transport(cfg htcdns.TransportConfig) *http.Transport {
if d := o.getDNSMapper(); d != nil {
return d.Transport(cfg)
}
return nil
}
func (o *componentHttpClient) Client(cfg htcdns.TransportConfig) *http.Client {
if d := o.getDNSMapper(); d != nil {
return d.Client(cfg)
}
return nil
}
func (o *componentHttpClient) DefaultTransport() *http.Transport {
if d := o.getDNSMapper(); d != nil {
return d.DefaultTransport()
}
return nil
}
func (o *componentHttpClient) DefaultClient() *http.Client {
if d := o.getDNSMapper(); d != nil {
return d.DefaultClient()
}
return nil
}
func (o *componentHttpClient) TimeCleaner(ctx context.Context, dur time.Duration) {
if d := o.getDNSMapper(); d != nil {
d.TimeCleaner(ctx, dur)
}
}

View File

@@ -0,0 +1,69 @@
/*
* MIT License
*
* Copyright (c) 2022 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 httpcli
import (
"fmt"
libcfg "github.com/nabbar/golib/config"
liberr "github.com/nabbar/golib/errors"
)
const (
ErrorParamEmpty liberr.CodeError = iota + libcfg.MinErrorComponentHttpCli
ErrorParamInvalid
ErrorComponentNotInitialized
ErrorConfigInvalid
ErrorComponentStart
ErrorComponentReload
)
func init() {
if liberr.ExistInMapMessage(ErrorParamEmpty) {
panic(fmt.Errorf("error code collision with package golib/config/components/httpcli"))
}
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
}
func getMessage(code liberr.CodeError) (message string) {
switch code {
case ErrorParamEmpty:
return "at least one given parameters is empty"
case ErrorParamInvalid:
return "at least one given parameters is invalid"
case ErrorComponentNotInitialized:
return "this component seems to not be correctly initialized"
case ErrorConfigInvalid:
return "server invalid config"
case ErrorComponentStart:
return "cannot start http client / dns mapper with config"
case ErrorComponentReload:
return "cannot update http client / dns mapper with new config"
}
return liberr.NullMessage
}

View File

@@ -0,0 +1,85 @@
/*
* MIT License
*
* Copyright (c) 2022 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 httpcli
import (
"sync/atomic"
libtls "github.com/nabbar/golib/certificates"
libcfg "github.com/nabbar/golib/config"
cfgtps "github.com/nabbar/golib/config/types"
libctx "github.com/nabbar/golib/context"
htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
)
type ComponentHTTPClient interface {
cfgtps.Component
htcdns.DNSMapper
Config() htcdns.Config
SetDefault()
SetAsDefaultHTTPClient(flag bool)
}
func New(ctx libctx.FuncContext, defCARoot libtls.FctRootCA, isDeftHTTPClient bool) ComponentHTTPClient {
c := &componentHttpClient{
x: libctx.NewConfig[uint8](ctx),
c: new(atomic.Value),
d: new(atomic.Value),
f: new(atomic.Value),
s: new(atomic.Bool),
}
if defCARoot == nil {
defCARoot = func() []string {
return make([]string, 0)
}
}
c.f.Store(defCARoot)
c.s.Store(isDeftHTTPClient)
return c
}
func Register(cfg libcfg.Config, key string, cpt ComponentHTTPClient) {
cfg.ComponentSet(key, cpt)
}
func RegisterNew(ctx libctx.FuncContext, cfg libcfg.Config, key string, defCARoot libtls.FctRootCA, isDeftHTTPClient bool) {
cfg.ComponentSet(key, New(ctx, defCARoot, isDeftHTTPClient))
}
func Load(getCpt cfgtps.FuncCptGet, key string) ComponentHTTPClient {
if c := getCpt(key); c == nil {
return nil
} else if h, ok := c.(ComponentHTTPClient); !ok {
return nil
} else {
return h
}
}

View File

@@ -0,0 +1,98 @@
/*
* MIT License
*
* Copyright (c) 2022 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 httpcli
import (
"sync/atomic"
libtls "github.com/nabbar/golib/certificates"
libctx "github.com/nabbar/golib/context"
libhtc "github.com/nabbar/golib/httpcli"
htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
)
type componentHttpClient struct {
x libctx.Config[uint8]
c *atomic.Value // htcdns.Config
d *atomic.Value // htcdns.DNSMapper
f *atomic.Value // FuncDefaultCARoot
s *atomic.Bool // is Default at start / update
}
func (o *componentHttpClient) getRootCA() []string {
if i := o.f.Load(); i == nil {
return make([]string, 0)
} else if v, k := i.(libtls.FctRootCA); !k {
return make([]string, 0)
} else if r := v(); len(r) < 1 {
return make([]string, 0)
} else {
return r
}
}
func (o *componentHttpClient) getDNSMapper() htcdns.DNSMapper {
if i := o.d.Load(); i == nil {
return nil
} else if v, k := i.(htcdns.DNSMapper); !k {
return nil
} else {
return v
}
}
func (o *componentHttpClient) setDNSMapper(dns htcdns.DNSMapper) {
if o.s.Load() {
defer o.SetDefault()
}
if dns != nil {
o.d.Store(dns)
}
}
func (o *componentHttpClient) Config() htcdns.Config {
if i := o.c.Load(); i == nil {
return htcdns.Config{}
} else if v, k := i.(*htcdns.Config); !k {
return htcdns.Config{}
} else {
return *v
}
}
func (o *componentHttpClient) setConfig(cfg htcdns.Config) {
o.c.Store(&cfg)
}
func (o *componentHttpClient) SetDefault() {
libhtc.SetDefaultDNSMapper(o.getDNSMapper())
}
func (o *componentHttpClient) SetAsDefaultHTTPClient(flag bool) {
o.s.Store(flag)
}

View File

@@ -0,0 +1,34 @@
/*
* MIT License
*
* Copyright (c) 2022 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 httpcli
import (
montps "github.com/nabbar/golib/monitor/types"
)
func (o *componentHttpClient) RegisterMonitorPool(fct montps.FuncPool) {
}

View File

@@ -27,6 +27,8 @@
package ldap
import (
"fmt"
lbldap "github.com/nabbar/golib/ldap"
libvpr "github.com/nabbar/golib/viper"
spfcbr "github.com/spf13/cobra"
@@ -48,13 +50,11 @@ func (o *componentLDAP) _getConfig() (*lbldap.Config, error) {
return nil, ErrorComponentNotInitialized.Error(nil)
} else if key = o._getKey(); len(key) < 1 {
return nil, ErrorComponentNotInitialized.Error(nil)
}
if e := vpr.UnmarshalKey(key, &cfg); e != nil {
} else if !vpr.Viper().IsSet(key) {
return nil, ErrorParamInvalid.Error(fmt.Errorf("missing config key '%s'", key))
} else if e := vpr.UnmarshalKey(key, &cfg); e != nil {
return nil, ErrorParamInvalid.Error(e)
}
if err = cfg.Validate(); err != nil {
} else if err = cfg.Validate(); err != nil {
return nil, ErrorConfigInvalid.Error(err)
}

View File

@@ -27,6 +27,8 @@
package log
import (
"fmt"
logcfg "github.com/nabbar/golib/logger/config"
libvpr "github.com/nabbar/golib/viper"
spfcbr "github.com/spf13/cobra"
@@ -82,9 +84,9 @@ func (o *componentLog) _getConfig() (*logcfg.Options, error) {
return nil, ErrorComponentNotInitialized.Error(nil)
} else if key = o._getKey(); len(key) < 1 {
return nil, ErrorComponentNotInitialized.Error(nil)
}
if e := vpr.UnmarshalKey(key, &cfg); e != nil {
} else if !vpr.Viper().IsSet(key) {
return nil, ErrorParamInvalid.Error(fmt.Errorf("missing config key '%s'", key))
} else if e := vpr.UnmarshalKey(key, &cfg); e != nil {
return nil, ErrorParamInvalid.Error(e)
}

View File

@@ -27,6 +27,8 @@
package mail
import (
"fmt"
libmail "github.com/nabbar/golib/mail"
libvpr "github.com/nabbar/golib/viper"
spfcbr "github.com/spf13/cobra"
@@ -90,9 +92,9 @@ func (o *componentMail) _getConfig() (*libmail.Config, error) {
return nil, ErrorComponentNotInitialized.Error(nil)
} else if key = o._getKey(); len(key) < 1 {
return nil, ErrorComponentNotInitialized.Error(nil)
}
if e := vpr.UnmarshalKey(key, &cfg); e != nil {
} else if !vpr.Viper().IsSet(key) {
return nil, ErrorParamInvalid.Error(fmt.Errorf("missing config key '%s'", key))
} else if e := vpr.UnmarshalKey(key, &cfg); e != nil {
return nil, ErrorParamInvalid.Error(e)
}

View File

@@ -29,8 +29,6 @@ package request
import (
"context"
libtls "github.com/nabbar/golib/certificates"
cpttls "github.com/nabbar/golib/config/components/tls"
cfgtps "github.com/nabbar/golib/config/types"
libreq "github.com/nabbar/golib/request"
libver "github.com/nabbar/golib/version"
@@ -39,9 +37,6 @@ import (
)
func (o *componentRequest) _getKey() string {
o.m.RLock()
defer o.m.RUnlock()
if i, l := o.x.Load(keyCptKey); !l {
return ""
} else if i == nil {
@@ -54,9 +49,6 @@ func (o *componentRequest) _getKey() string {
}
func (o *componentRequest) _getFctVpr() libvpr.FuncViper {
o.m.RLock()
defer o.m.RUnlock()
if i, l := o.x.Load(keyFctViper); !l {
return nil
} else if i == nil {
@@ -89,9 +81,6 @@ func (o *componentRequest) _getSPFViper() *spfvbr.Viper {
}
func (o *componentRequest) _getFctCpt() cfgtps.FuncCptGet {
o.m.RLock()
defer o.m.RUnlock()
if i, l := o.x.Load(keyFctGetCpt); !l {
return nil
} else if i == nil {
@@ -104,16 +93,10 @@ func (o *componentRequest) _getFctCpt() cfgtps.FuncCptGet {
}
func (o *componentRequest) _getContext() context.Context {
o.m.RLock()
defer o.m.RUnlock()
return o.x.GetContext()
}
func (o *componentRequest) _getVersion() libver.Version {
o.m.RLock()
defer o.m.RUnlock()
if i, l := o.x.Load(keyCptVersion); !l {
return nil
} else if i == nil {
@@ -125,23 +108,6 @@ func (o *componentRequest) _getVersion() libver.Version {
}
}
func (o *componentRequest) _GetTLS() libtls.TLSConfig {
o.m.RLock()
defer o.m.RUnlock()
if o.t == "" {
return nil
}
if i := cpttls.Load(o._getFctCpt(), o.t); i == nil {
return nil
} else if tls := i.GetTLS(); tls == nil {
return nil
} else {
return tls
}
}
func (o *componentRequest) _getFct() (cfgtps.FuncCptEvent, cfgtps.FuncCptEvent) {
if o.IsStarted() {
return o._getFctEvt(keyFctRelBef), o._getFctEvt(keyFctRelAft)
@@ -151,9 +117,6 @@ func (o *componentRequest) _getFct() (cfgtps.FuncCptEvent, cfgtps.FuncCptEvent)
}
func (o *componentRequest) _getFctEvt(key uint8) cfgtps.FuncCptEvent {
o.m.RLock()
defer o.m.RUnlock()
if i, l := o.x.Load(key); !l {
return nil
} else if i == nil {
@@ -185,29 +148,27 @@ func (o *componentRequest) _runCli() error {
if !o.IsStarted() {
prt = ErrorComponentStart
} else {
req = o.r
req = o.getRequest()
}
if cfg, err = o._getConfig(); err != nil {
return prt.Error(err)
}
cfg.SetDefaultTLS(o._GetTLS)
cfg.SetDefaultLog(o.getLogger)
if req != nil {
if req, e = cfg.Update(o.x.GetContext, req); err != nil {
return prt.Error(e)
}
req.RegisterHTTPClient(o.getClient())
} else {
if req, e = cfg.New(o.x.GetContext); err != nil {
if req, e = cfg.New(o.x.GetContext, o.getClient()); err != nil {
return prt.Error(e)
}
}
o.m.Lock()
o.r = req
o.m.Unlock()
o.setRequest(req)
if e = o._registerMonitor(cfg); e != nil {
return prt.Error(e)

View File

@@ -56,17 +56,6 @@ func (o *componentRequest) Type() string {
}
func (o *componentRequest) Init(key string, ctx libctx.FuncContext, get cfgtps.FuncCptGet, vpr libvpr.FuncViper, vrs libver.Version, log liblog.FuncLog) {
o.m.Lock()
defer o.m.Unlock()
if o.x == nil {
o.x = libctx.NewConfig[uint8](ctx)
} else {
x := libctx.NewConfig[uint8](ctx)
x.Merge(o.x)
o.x = x
}
o.x.Store(keyCptKey, key)
o.x.Store(keyFctGetCpt, get)
o.x.Store(keyFctViper, vpr)
@@ -85,9 +74,6 @@ func (o *componentRequest) RegisterFuncReload(before, after cfgtps.FuncCptEvent)
}
func (o *componentRequest) IsStarted() bool {
o.m.RLock()
defer o.m.RUnlock()
return o != nil && o.r != nil
}
@@ -104,23 +90,14 @@ func (o *componentRequest) Reload() error {
}
func (o *componentRequest) Stop() {
o.m.Lock()
defer o.m.Unlock()
o.r = nil
return
o.setRequest(nil)
}
func (o *componentRequest) Dependencies() []string {
o.m.RLock()
defer o.m.RUnlock()
var def = []string{cpttls.ComponentType}
if o == nil {
return def
} else if len(o.t) > 0 {
def = []string{o.t}
}
if o.x == nil {
@@ -137,9 +114,6 @@ func (o *componentRequest) Dependencies() []string {
}
func (o *componentRequest) SetDependencies(d []string) error {
o.m.RLock()
defer o.m.RUnlock()
if o.x == nil {
return ErrorComponentNotInitialized.Error(nil)
} else {

View File

@@ -27,6 +27,8 @@
package request
import (
"fmt"
libreq "github.com/nabbar/golib/request"
libvpr "github.com/nabbar/golib/viper"
spfcbr "github.com/spf13/cobra"
@@ -48,13 +50,11 @@ func (o *componentRequest) _getConfig() (*libreq.Options, error) {
return nil, ErrorComponentNotInitialized.Error(nil)
} else if key = o._getKey(); len(key) < 1 {
return nil, ErrorComponentNotInitialized.Error(nil)
}
if e := vpr.UnmarshalKey(key, &cfg); e != nil {
} else if !vpr.Viper().IsSet(key) {
return nil, ErrorParamInvalid.Error(fmt.Errorf("missing config key '%s'", key))
} else if e := vpr.UnmarshalKey(key, &cfg); e != nil {
return nil, ErrorParamInvalid.Error(e)
}
if err = cfg.Validate(); err != nil {
} else if err = cfg.Validate(); err != nil {
return nil, ErrorConfigInvalid.Error(err)
}

View File

@@ -31,13 +31,11 @@ import (
"encoding/json"
cfgcst "github.com/nabbar/golib/config/const"
libhtc "github.com/nabbar/golib/httpcli"
moncfg "github.com/nabbar/golib/monitor/types"
)
var _defaultConfig = []byte(`{
"endpoint":"https://endpoint.example.com/path",
"http_client": ` + string(libhtc.DefaultConfig(cfgcst.JSONIndent)) + `,
"auth": {
"basic":{
"enable": false,

View File

@@ -27,36 +27,43 @@
package request
import (
"sync"
"sync/atomic"
libcfg "github.com/nabbar/golib/config"
cfgtps "github.com/nabbar/golib/config/types"
libctx "github.com/nabbar/golib/context"
libhtc "github.com/nabbar/golib/httpcli"
libreq "github.com/nabbar/golib/request"
)
type ComponentRequest interface {
cfgtps.Component
SetDefaultTLS(key string)
Request() (libreq.Request, error)
SetHTTPClient(cli libhtc.HttpClient)
Request() libreq.Request
}
func New(ctx libctx.FuncContext, tls string) ComponentRequest {
return &componentRequest{
m: sync.RWMutex{},
func New(ctx libctx.FuncContext, cli libhtc.HttpClient) ComponentRequest {
o := &componentRequest{
x: libctx.NewConfig[uint8](ctx),
r: nil,
t: tls,
r: new(atomic.Value),
c: new(atomic.Value),
p: new(atomic.Value),
}
if cli != nil {
o.c.Store(cli)
}
return o
}
func Register(cfg libcfg.Config, key string, cpt ComponentRequest) {
cfg.ComponentSet(key, cpt)
}
func RegisterNew(ctx libctx.FuncContext, cfg libcfg.Config, key, tls string) {
cfg.ComponentSet(key, New(ctx, tls))
func RegisterNew(ctx libctx.FuncContext, cfg libcfg.Config, key string, cli libhtc.HttpClient) {
cfg.ComponentSet(key, New(ctx, cli))
}
func Load(getCpt cfgtps.FuncCptGet, key string) ComponentRequest {

View File

@@ -27,31 +27,86 @@
package request
import (
"sync"
"sync/atomic"
libctx "github.com/nabbar/golib/context"
libhtc "github.com/nabbar/golib/httpcli"
montps "github.com/nabbar/golib/monitor/types"
libreq "github.com/nabbar/golib/request"
)
type componentRequest struct {
m sync.RWMutex
x libctx.Config[uint8]
r libreq.Request
t string
p montps.FuncPool
r *atomic.Value // libreq.Request
c *atomic.Value // libhtc.HttpClient
p *atomic.Value // montps.FuncPool
}
func (o *componentRequest) SetDefaultTLS(key string) {
o.m.Lock()
defer o.m.Unlock()
o.t = key
func (o *componentRequest) SetHTTPClient(cli libhtc.HttpClient) {
o.setClient(cli)
}
func (o *componentRequest) Request() (libreq.Request, error) {
o.m.RLock()
defer o.m.RUnlock()
return o.r.Clone()
func (o *componentRequest) Request() libreq.Request {
return o.getRequest()
}
func (o *componentRequest) RegisterMonitorPool(fct montps.FuncPool) {
o.setPool(fct)
}
func (o *componentRequest) getRequest() libreq.Request {
if i := o.r.Load(); i == nil {
return nil
} else if v, k := i.(libreq.Request); !k {
return nil
} else {
return v
}
}
func (o *componentRequest) setRequest(req libreq.Request) {
if req == nil {
return
}
o.r.Store(req)
}
func (o *componentRequest) getClient() libhtc.HttpClient {
if i := o.c.Load(); i == nil {
return nil
} else if v, k := i.(libhtc.HttpClient); !k {
return nil
} else {
return v
}
}
func (o *componentRequest) setClient(cli libhtc.HttpClient) {
if cli == nil {
return
}
o.c.Store(cli)
}
func (o *componentRequest) getPool() montps.Pool {
if i := o.p.Load(); i == nil {
return nil
} else if v, k := i.(montps.FuncPool); !k {
return nil
} else if p := v(); p == nil {
return nil
} else {
return p
}
}
func (o *componentRequest) setPool(fct montps.FuncPool) {
if fct == nil {
fct = func() montps.Pool {
return nil
}
}
o.p.Store(fct)
}

View File

@@ -34,26 +34,6 @@ import (
libver "github.com/nabbar/golib/version"
)
func (o *componentRequest) RegisterMonitorPool(fct montps.FuncPool) {
o.m.Lock()
defer o.m.Unlock()
o.p = fct
}
func (o *componentRequest) _getMonitorPool() montps.Pool {
o.m.RLock()
defer o.m.RUnlock()
if o.p == nil {
return nil
} else if p := o.p(); p == nil {
return nil
} else {
return p
}
}
func (o *componentRequest) _registerMonitor(cfg *libreq.Options) error {
var (
e error
@@ -63,7 +43,7 @@ func (o *componentRequest) _registerMonitor(cfg *libreq.Options) error {
ctx = o._getContext()
)
if o._getMonitorPool() == nil {
if o.getPool() == nil {
return nil
} else if len(key) < 1 {
return ErrorComponentNotInitialized.Error(nil)
@@ -107,15 +87,13 @@ func (o *componentRequest) _registerMonitor(cfg *libreq.Options) error {
}
func (o *componentRequest) _newMonitor(ctx context.Context, vrs libver.Version) (montps.Monitor, error) {
o.m.RLock()
defer o.m.RUnlock()
return o.r.Monitor(ctx, vrs)
return o.getRequest().Monitor(ctx, vrs)
}
func (o *componentRequest) _getMonitor(key string) montps.Monitor {
var (
mon montps.Monitor
pol = o._getMonitorPool()
pol = o.getPool()
)
if pol == nil {
@@ -127,7 +105,7 @@ func (o *componentRequest) _getMonitor(key string) montps.Monitor {
}
func (o *componentRequest) _setMonitor(mon montps.Monitor) error {
var pol = o._getMonitorPool()
var pol = o.getPool()
if pol == nil {
return nil

View File

@@ -27,6 +27,8 @@
package smtp
import (
"fmt"
libmon "github.com/nabbar/golib/monitor/types"
smtpcf "github.com/nabbar/golib/smtp/config"
libvpr "github.com/nabbar/golib/viper"
@@ -67,9 +69,9 @@ func (o *componentSmtp) _getConfig() (smtpcf.Config, *libmon.Config, error) {
return nil, nil, ErrorComponentNotInitialized.Error(nil)
} else if key = o._getKey(); len(key) < 1 {
return nil, nil, ErrorComponentNotInitialized.Error(nil)
}
if e := vpr.UnmarshalKey(key, &cfg); e != nil {
} else if !vpr.Viper().IsSet(key) {
return nil, nil, ErrorParamInvalid.Error(fmt.Errorf("missing config key '%s'", key))
} else if e := vpr.UnmarshalKey(key, &cfg); e != nil {
return nil, nil, ErrorParamInvalid.Error(e)
}

View File

@@ -27,6 +27,8 @@
package tls
import (
"fmt"
libtls "github.com/nabbar/golib/certificates"
libvpr "github.com/nabbar/golib/viper"
spfcbr "github.com/spf13/cobra"
@@ -48,13 +50,11 @@ func (o *componentTls) _getConfig() (*libtls.Config, error) {
return nil, ErrorComponentNotInitialized.Error(nil)
} else if key = o._getKey(); len(key) < 1 {
return nil, ErrorComponentNotInitialized.Error(nil)
}
if e := vpr.UnmarshalKey(key, &cfg); e != nil {
} else if !vpr.Viper().IsSet(key) {
return nil, ErrorParamInvalid.Error(fmt.Errorf("missing config key '%s'", key))
} else if e := vpr.UnmarshalKey(key, &cfg); e != nil {
return nil, ErrorParamInvalid.Error(e)
}
if err = cfg.Validate(); err != nil {
} else if err = cfg.Validate(); err != nil {
return nil, ErrorConfigInvalid.Error(err)
}

View File

@@ -60,9 +60,9 @@ func getMessage(code liberr.CodeError) (message string) {
case ErrorConfigInvalid:
return "server invalid config"
case ErrorComponentStart:
return "cannot open database connection with config"
return "cannot initiate new TLSConfig with config"
case ErrorComponentReload:
return "cannot update database connection with new config"
return "cannot update TLSConfig with new config"
}
return liberr.NullMessage

View File

@@ -35,8 +35,6 @@ import (
libctx "github.com/nabbar/golib/context"
)
type FuncDefaultCARoot func() []string
type ComponentTlS interface {
cfgtps.Component
Config() *libtls.Config
@@ -44,12 +42,13 @@ type ComponentTlS interface {
SetTLS(tls libtls.TLSConfig)
}
func New(ctx libctx.FuncContext, defCARoot FuncDefaultCARoot) ComponentTlS {
func New(ctx libctx.FuncContext, defCARoot libtls.FctRootCA) ComponentTlS {
return &componentTls{
m: sync.RWMutex{},
x: libctx.NewConfig[uint8](ctx),
t: nil,
c: nil,
f: defCARoot,
}
}
@@ -57,7 +56,7 @@ func Register(cfg libcfg.Config, key string, cpt ComponentTlS) {
cfg.ComponentSet(key, cpt)
}
func RegisterNew(ctx libctx.FuncContext, cfg libcfg.Config, key string, defCARoot FuncDefaultCARoot) {
func RegisterNew(ctx libctx.FuncContext, cfg libcfg.Config, key string, defCARoot libtls.FctRootCA) {
cfg.ComponentSet(key, New(ctx, defCARoot))
}

View File

@@ -38,7 +38,7 @@ type componentTls struct {
x libctx.Config[uint8]
t libtls.TLSConfig
c *libtls.Config
f FuncDefaultCARoot
f libtls.FctRootCA
}
func (o *componentTls) Config() *libtls.Config {

View File

@@ -48,7 +48,8 @@ const (
MinErrorComponentDatabase = MinErrorComponentAws + 10
MinErrorComponentHead = MinErrorComponentDatabase + 10
MinErrorComponentHttp = MinErrorComponentHead + 10
MinErrorComponentLdap = MinErrorComponentHttp + 10
MinErrorComponentHttpCli = MinErrorComponentHttp + 10
MinErrorComponentLdap = MinErrorComponentHttpCli + 10
MinErrorComponentLog = MinErrorComponentLdap + 10
MinErrorComponentMail = MinErrorComponentLog + 10
MinErrorComponentNats = MinErrorComponentMail + 10

View File

@@ -27,8 +27,11 @@
package crypt
import (
"bytes"
"fmt"
"io"
libsck "github.com/nabbar/golib/socket"
)
type reader struct {
@@ -77,7 +80,11 @@ func (o *crt) ReaderHex(r io.Reader) io.Reader {
if n, err = r.Read(b); err != nil {
return 0, err
} else if a, err = o.DecodeHex(b[:n]); err != nil {
} else if bytes.HasSuffix(b[:n], []byte{libsck.EOL}) {
n = n - len([]byte{libsck.EOL})
}
if a, err = o.DecodeHex(b[:n]); err != nil {
return 0, err
} else {
copy(p, a)

View File

@@ -45,11 +45,12 @@ const (
MinPkgDatabaseKVTbl = baseSub + MinPkgDatabaseKVMap
MinPkgDatabaseKVItm = baseSub + MinPkgDatabaseKVTbl
MinPkgFileProgress = baseInc + MinPkgDatabaseGorm
MinPkgFTPClient = baseInc + MinPkgFileProgress
MinPkgHttpCli = baseInc + MinPkgFTPClient
MinPkgFileProgress = baseInc + MinPkgDatabaseGorm
MinPkgFTPClient = baseInc + MinPkgFileProgress
MinPkgHttpCli = baseInc + MinPkgFTPClient
MinPkgHttpCliDNSMapper = baseSub + MinPkgHttpCli
MinPkgHttpServer = baseInc + MinPkgHttpCli
MinPkgHttpServer = baseInc + MinPkgHttpCliDNSMapper
MinPkgHttpServerPool = baseSub + MinPkgHttpServer
MinPkgIOUtils = baseInc + MinPkgHttpServer

90
go.mod
View File

@@ -2,24 +2,24 @@ module github.com/nabbar/golib
go 1.21
toolchain go1.21.5
toolchain go1.21.6
require (
github.com/aws/aws-sdk-go v1.50.10
github.com/aws/aws-sdk-go-v2 v1.24.1
github.com/aws/aws-sdk-go-v2/config v1.26.6
github.com/aws/aws-sdk-go-v2/credentials v1.16.16
github.com/aws/aws-sdk-go-v2/service/iam v1.28.7
github.com/aws/aws-sdk-go-v2/service/s3 v1.48.1
github.com/aws/smithy-go v1.19.0
github.com/aws/aws-sdk-go v1.50.19
github.com/aws/aws-sdk-go-v2 v1.25.0
github.com/aws/aws-sdk-go-v2/config v1.27.0
github.com/aws/aws-sdk-go-v2/credentials v1.17.0
github.com/aws/aws-sdk-go-v2/service/iam v1.29.0
github.com/aws/aws-sdk-go-v2/service/s3 v1.49.0
github.com/aws/smithy-go v1.20.0
github.com/bits-and-blooms/bitset v1.13.0
github.com/c-bata/go-prompt v0.2.6
github.com/fatih/color v1.16.0
github.com/fsnotify/fsnotify v1.7.0
github.com/fxamacker/cbor/v2 v2.5.0
github.com/fxamacker/cbor/v2 v2.6.0
github.com/gin-gonic/gin v1.9.1
github.com/go-ldap/ldap/v3 v3.4.6
github.com/go-playground/validator/v10 v10.17.0
github.com/go-playground/validator/v10 v10.18.0
github.com/google/go-github/v33 v33.0.0
github.com/hashicorp/go-hclog v1.6.2
github.com/hashicorp/go-retryablehttp v0.7.5
@@ -31,9 +31,9 @@ require (
github.com/mattn/go-colorable v0.1.13
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.5.0
github.com/nats-io/jwt/v2 v2.5.3
github.com/nats-io/nats-server/v2 v2.10.10
github.com/nats-io/nats.go v1.32.0
github.com/nats-io/jwt/v2 v2.5.4
github.com/nats-io/nats-server/v2 v2.10.11
github.com/nats-io/nats.go v1.33.0
github.com/nutsdb/nutsdb v0.14.3
github.com/onsi/ginkgo/v2 v2.15.0
github.com/onsi/gomega v1.31.1
@@ -45,23 +45,23 @@ require (
github.com/spf13/jwalterweatherman v1.1.0
github.com/spf13/viper v1.18.2
github.com/ugorji/go/codec v1.2.12
github.com/vbauerster/mpb/v8 v8.6.2
github.com/vbauerster/mpb/v8 v8.7.2
github.com/xanzy/go-gitlab v0.97.0
github.com/xhit/go-simple-mail v2.2.2+incompatible
github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a
golang.org/x/net v0.20.0
golang.org/x/oauth2 v0.16.0
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
golang.org/x/net v0.21.0
golang.org/x/oauth2 v0.17.0
golang.org/x/sync v0.6.0
golang.org/x/sys v0.16.0
golang.org/x/term v0.16.0
golang.org/x/sys v0.17.0
golang.org/x/term v0.17.0
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/clickhouse v0.6.0
gorm.io/driver/mysql v1.5.2
gorm.io/driver/postgres v1.5.4
gorm.io/driver/sqlite v1.5.4
gorm.io/driver/sqlserver v1.5.2
gorm.io/gorm v1.25.6
gorm.io/driver/mysql v1.5.4
gorm.io/driver/postgres v1.5.6
gorm.io/driver/sqlite v1.5.5
gorm.io/driver/sqlserver v1.5.3
gorm.io/gorm v1.25.7
)
require (
@@ -78,21 +78,21 @@ require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/antlabs/stl v0.0.2 // indirect
github.com/antlabs/timer v0.1.1 // indirect
github.com/antlabs/timer v0.1.3 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.10 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.0 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.19.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.22.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.27.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bwmarrin/snowflake v0.3.0 // indirect
github.com/bytedance/sonic v1.10.2 // indirect
@@ -125,7 +125,7 @@ require (
github.com/google/btree v1.0.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/pprof v0.0.0-20240130152714-0ed6a68c8d9e // indirect
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
@@ -150,7 +150,7 @@ require (
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/juju/ratelimit v1.0.2-0.20191002062651-f60b32039441 // indirect
github.com/klauspost/compress v1.17.5 // indirect
github.com/klauspost/compress v1.17.6 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
@@ -180,7 +180,7 @@ require (
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/rivo/uniseg v0.4.6 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
@@ -203,14 +203,14 @@ require (
github.com/x448/float16 v0.8.4 // indirect
github.com/xujiajun/mmap-go v1.0.1 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.opentelemetry.io/otel v1.22.0 // indirect
go.opentelemetry.io/otel/trace v1.22.0 // indirect
go.opentelemetry.io/otel v1.23.1 // indirect
go.opentelemetry.io/otel/trace v1.23.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.17.0 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect

View File

@@ -28,162 +28,87 @@ package httpcli
import (
"context"
"crypto/tls"
"net"
"net/http"
"net/url"
"sync/atomic"
"time"
liberr "github.com/nabbar/golib/errors"
libptc "github.com/nabbar/golib/network/protocol"
"golang.org/x/net/http2"
libtls "github.com/nabbar/golib/certificates"
libdur "github.com/nabbar/golib/duration"
htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
)
const (
ClientTimeout30Sec = 30 * time.Second
ClientTimeout10Sec = 10 * time.Second
ClientTimeout5Sec = 5 * time.Second
ClientTimeout1Sec = 1 * time.Second
ClientNetworkTCP = "tcp"
ClientNetworkUDP = "udp"
ClientTimeout5Sec = 5 * time.Second
)
var trp = new(atomic.Value)
var (
dns = new(atomic.Value)
ctx context.Context
cnl context.CancelFunc
)
func init() {
trp.Store(&http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSHandshakeTimeout: 10 * time.Second,
DisableKeepAlives: false,
DisableCompression: false,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 1,
MaxConnsPerHost: 25,
IdleConnTimeout: 90 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
ForceAttemptHTTP2: true,
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS13,
func initDNSMapper() htcdns.DNSMapper {
if cnl != nil {
cnl()
}
ctx, cnl = context.WithCancel(context.Background())
return htcdns.New(ctx, &htcdns.Config{
DNSMapper: make(map[string]string),
TimerClean: libdur.ParseDuration(3 * time.Minute),
Transport: htcdns.TransportConfig{
Proxy: nil,
TLSConfig: &libtls.Config{},
DisableHTTP2: false,
DisableKeepAlive: false,
DisableCompression: false,
MaxIdleConns: 50,
MaxIdleConnsPerHost: 5,
MaxConnsPerHost: 25,
TimeoutGlobal: libdur.ParseDuration(30 * time.Second),
TimeoutKeepAlive: libdur.ParseDuration(15 * time.Second),
TimeoutTLSHandshake: libdur.ParseDuration(10 * time.Second),
TimeoutExpectContinue: libdur.ParseDuration(3 * time.Second),
TimeoutIdleConn: libdur.ParseDuration(30 * time.Second),
TimeoutResponseHeader: 0,
},
})
}, nil)
}
func DefaultDNSMapper() htcdns.DNSMapper {
if i := dns.Load(); i == nil {
d := initDNSMapper()
dns.Store(d)
return d
} else if d, k := i.(htcdns.DNSMapper); !k {
d = initDNSMapper()
dns.Store(d)
return d
} else {
return d
}
}
func SetDefaultDNSMapper(d htcdns.DNSMapper) {
if d == nil {
return
}
if cnl != nil {
cnl()
}
dns.Store(d)
}
type FctHttpClient func() *http.Client
type FctHttpClientSrv func(servername string) *http.Client
type HttpClient interface {
Do(req *http.Request) (*http.Response, error)
}
func ForceUpdateTransport(cfg *tls.Config, proxyUrl *url.URL) *http.Transport {
t := &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: cfg.Clone(),
TLSHandshakeTimeout: 10 * time.Second,
DisableKeepAlives: false,
DisableCompression: false,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 1,
MaxConnsPerHost: 25,
IdleConnTimeout: 90 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
ForceAttemptHTTP2: true,
}
if proxyUrl != nil {
t.Proxy = http.ProxyURL(proxyUrl)
}
trp.Store(t)
return t
}
func GetTransport(tlsConfig *tls.Config, proxyURL *url.URL, DisableKeepAlive, DisableCompression, ForceHTTP2 bool) *http.Transport {
var tr *http.Transport
if i := trp.Load(); i != nil {
if t, k := i.(*http.Transport); k {
tr = t.Clone()
}
}
if tr == nil {
tr = &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSHandshakeTimeout: 10 * time.Second,
DisableKeepAlives: false,
DisableCompression: false,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 1,
MaxConnsPerHost: 25,
IdleConnTimeout: 90 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
ForceAttemptHTTP2: true,
}
}
tr.DisableCompression = DisableCompression
tr.DisableKeepAlives = DisableKeepAlive
tr.TLSClientConfig = tlsConfig.Clone()
if proxyURL != nil {
tr.Proxy = http.ProxyURL(proxyURL)
}
return tr
}
func SetTransportDial(tr *http.Transport, forceIp bool, netw libptc.NetworkProtocol, ip, local string) {
var (
dial = &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}
fctDial func(ctx context.Context, network, address string) (net.Conn, error)
)
if forceIp && len(local) > 0 {
u := &url.URL{
Host: local,
}
fctDial = func(ctx context.Context, network, address string) (net.Conn, error) {
dial.LocalAddr = &net.TCPAddr{
IP: net.ParseIP(u.Hostname()),
}
return dial.DialContext(ctx, netw.Code(), ip)
}
} else if forceIp {
fctDial = func(ctx context.Context, network, address string) (net.Conn, error) {
return dial.DialContext(ctx, netw.Code(), ip)
}
} else {
fctDial = dial.DialContext
}
tr.DialContext = fctDial
tr.DialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
return tls.DialWithDialer(dial, network, addr, tr.TLSClientConfig)
}
}
func GetClient(tr *http.Transport, http2Tr bool, GlobalTimeout time.Duration) (*http.Client, liberr.Error) {
if http2Tr {
if e := http2.ConfigureTransport(tr); e != nil {
return nil, ErrorClientTransportHttp2.Error(e)
}
}
c := &http.Client{
Transport: tr,
}
if GlobalTimeout != 0 {
c.Timeout = GlobalTimeout
}
return c, nil
func GetClient() *http.Client {
return DefaultDNSMapper().DefaultClient()
}

View File

@@ -0,0 +1,126 @@
/*
* MIT License
*
* Copyright (c) 2020 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 dns_mapper
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/url"
libval "github.com/go-playground/validator/v10"
libtls "github.com/nabbar/golib/certificates"
cmptls "github.com/nabbar/golib/config/components/tls"
cfgcst "github.com/nabbar/golib/config/const"
libdur "github.com/nabbar/golib/duration"
liberr "github.com/nabbar/golib/errors"
)
type TransportConfig struct {
Proxy *url.URL `json:"proxy,omitempty" yaml:"proxy,omitempty" toml:"proxy,omitempty" mapstructure:"proxy,omitempty"`
TLSConfig *libtls.Config `json:"tls-config,omitempty" yaml:"tls-config,omitempty" toml:"tls-config,omitempty" mapstructure:"tls-config,omitempty"`
DisableHTTP2 bool `json:"disable-http2" yaml:"disable-http2" toml:"disable-http2" mapstructure:"disable-http2"`
DisableKeepAlive bool `json:"disable-keepalive" yaml:"disable-keepalive" toml:"disable-keepalive" mapstructure:"disable-keepalive"`
DisableCompression bool `json:"disable-compression" yaml:"disable-compression" toml:"disable-compression" mapstructure:"disable-compression"`
MaxIdleConns int `json:"max-idle-conns" yaml:"max-idle-conns" toml:"max-idle-conns" mapstructure:"max-idle-conns"`
MaxIdleConnsPerHost int `json:"max-idle-conns-per-host" yaml:"max-idle-conns-per-host" toml:"max-idle-conns-per-host" mapstructure:"max-idle-conns-per-host"`
MaxConnsPerHost int `json:"max-conns-per-host" yaml:"max-conns-per-host" toml:"max-conns-per-host" mapstructure:"max-conns-per-host"`
TimeoutGlobal libdur.Duration `json:"timeout-global,omitempty" yaml:"timeout-global,omitempty" toml:"timeout-global,omitempty" mapstructure:"timeout-global,omitempty"`
TimeoutKeepAlive libdur.Duration `json:"timeout-keepalive,omitempty" yaml:"timeout-keepalive" toml:"timeout-keepalive" mapstructure:"timeout-keepalive,omitempty"`
TimeoutTLSHandshake libdur.Duration `json:"timeout-tls-handshake,omitempty" yaml:"timeout-tls-handshake,omitempty" toml:"timeout-tls-handshake,omitempty" mapstructure:"timeout-tls-handshake,omitempty"`
TimeoutExpectContinue libdur.Duration `json:"timeout-expect-continue,omitempty" yaml:"timeout-expect-continue,omitempty" toml:"timeout-expect-continue,omitempty" mapstructure:"timeout-expect-continue,omitempty"`
TimeoutIdleConn libdur.Duration `json:"timeout-idle-conn,omitempty" yaml:"timeout-idle-conn,omitempty" toml:"timeout-idle-conn,omitempty" mapstructure:"timeout-idle-conn,omitempty"`
TimeoutResponseHeader libdur.Duration `json:"timeout-response-header,omitempty" yaml:"timeout-response-headern,omitempty" toml:"timeout-response-header,omitempty" mapstructure:"timeout-response-header,omitempty"`
}
type Config struct {
DNSMapper map[string]string `json:"dns-mapper,omitempty" yaml:"dns-mapper,omitempty" toml:"dns-mapper,omitempty" mapstructure:"dns-mapper,omitempty"`
TimerClean libdur.Duration `json:"timer-clean,omitempty" yaml:"timer-clean,omitempty" toml:"timer-clean,omitempty" mapstructure:"timer-clean,omitempty"`
Transport TransportConfig `json:"transport,omitempty" yaml:"transport,omitempty" toml:"transport,omitempty" mapstructure:"transport,omitempty"`
}
func DefaultConfig(indent string) []byte {
var (
res = bytes.NewBuffer(make([]byte, 0))
def = []byte(`{
"dns-mapper": {
"localhost":"127.0.0.1"
},
"timer-clean": "3m",
"transport": {
"proxy": null,
"tls-config": ` + string(cmptls.DefaultConfig(cfgcst.JSONIndent)) + `,
"disable-http2": false,
"disable-keepalive": false,
"disable-compression": false,
"max-idle-conns": 50,
"max-idle-conns-per-host": 5,
"max-conns-per-host": 25,
"timeout-global": "30s",
"timeout-keepalive": "15s",
"timeout-tls-handshake": "10s",
"timeout-expect-continue": "3s",
"timeout-idle-conn": "30s",
"timeout-response-header": "0s"
}
}`)
)
if err := json.Indent(res, def, indent, cfgcst.JSONIndent); err != nil {
return def
} else {
return res.Bytes()
}
}
func (o Config) Validate() liberr.Error {
var e = ErrorValidatorError.Error(nil)
if err := libval.New().Struct(o); err != nil {
if er, ok := err.(*libval.InvalidValidationError); ok {
e.Add(er)
}
for _, er := range err.(libval.ValidationErrors) {
//nolint #goerr113
e.Add(fmt.Errorf("config field '%s' is not validated by constraint '%s'", er.Namespace(), er.ActualTag()))
}
}
if !e.HasParent() {
e = nil
}
return e
}
func (o Config) New(ctx context.Context, fct libtls.FctRootCA) DNSMapper {
return New(ctx, &o, fct)
}

View File

@@ -0,0 +1,62 @@
/*
* MIT License
*
* Copyright (c) 2020 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 dns_mapper
import (
"fmt"
liberr "github.com/nabbar/golib/errors"
)
const (
ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgHttpCliDNSMapper
ErrorParamInvalid
ErrorValidatorError
ErrorClientTransportHttp2
)
func init() {
if liberr.ExistInMapMessage(ErrorParamEmpty) {
panic(fmt.Errorf("error code collision with package golib/httpcli"))
}
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
}
func getMessage(code liberr.CodeError) (message string) {
switch code {
case ErrorParamEmpty:
return "at least one given parameters is empty"
case ErrorParamInvalid:
return "at least one given parameters is invalid"
case ErrorValidatorError:
return "config seems to be invalid"
case ErrorClientTransportHttp2:
return "error while configure http2 transport for client"
}
return liberr.NullMessage
}

View File

@@ -0,0 +1,91 @@
/*
* MIT License
*
* Copyright (c) 2020 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 dns_mapper
import (
"context"
"net"
"net/http"
"sync"
"sync/atomic"
"time"
libtls "github.com/nabbar/golib/certificates"
libdur "github.com/nabbar/golib/duration"
)
type DNSMapper interface {
Add(endpoint, ip string)
Get(endpoint string) string
Del(endpoint string)
DialContext(ctx context.Context, network, address string) (net.Conn, error)
Transport(cfg TransportConfig) *http.Transport
Client(cfg TransportConfig) *http.Client
DefaultTransport() *http.Transport
DefaultClient() *http.Client
TimeCleaner(ctx context.Context, dur time.Duration)
}
func New(ctx context.Context, cfg *Config, fct libtls.FctRootCA) DNSMapper {
if cfg == nil {
cfg = &Config{
DNSMapper: make(map[string]string),
TimerClean: libdur.ParseDuration(3 * time.Minute),
Transport: TransportConfig{
Proxy: nil,
TLSConfig: nil,
},
}
}
if fct == nil {
fct = func() []string {
return make([]string, 0)
}
}
d := &dmp{
d: new(sync.Map),
z: new(sync.Map),
c: new(atomic.Value),
t: new(atomic.Value),
f: fct,
}
for edp, adr := range cfg.DNSMapper {
d.Add(edp, adr)
}
d.c.Store(cfg)
_ = d.DefaultTransport()
d.TimeCleaner(ctx, cfg.TimerClean.Time())
return d
}

209
httpcli/dns-mapper/model.go Normal file
View File

@@ -0,0 +1,209 @@
/*
* MIT License
*
* Copyright (c) 2020 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 dns_mapper
import (
"context"
"net"
"strings"
"sync"
"sync/atomic"
"time"
libtls "github.com/nabbar/golib/certificates"
)
type dmp struct {
d *sync.Map
z *sync.Map
c *atomic.Value // *Config
t *atomic.Value // *http transport
f libtls.FctRootCA
}
func (o *dmp) config() *Config {
var cfg = &Config{}
if i := o.c.Load(); i == nil {
return cfg
} else if c, k := i.(*Config); !k {
return cfg
} else {
*cfg = *c
return cfg
}
}
func (o *dmp) configDialerTimeout() time.Duration {
if cfg := o.config(); cfg == nil {
return 30 * time.Second
} else if cfg.Transport.TimeoutGlobal == 0 {
return 30 * time.Second
} else {
return cfg.Transport.TimeoutGlobal.Time()
}
}
func (o *dmp) configDialerKeepAlive() time.Duration {
if cfg := o.config(); cfg == nil {
return 15 * time.Second
} else if cfg.Transport.TimeoutKeepAlive == 0 {
return 15 * time.Second
} else {
return cfg.Transport.TimeoutKeepAlive.Time()
}
}
func (o *dmp) CacheHas(endpoint string) bool {
_, l := o.z.Load(endpoint)
return l
}
func (o *dmp) CacheGet(endpoint string) string {
if i, l := o.z.Load(endpoint); !l {
return ""
} else if v, k := i.(string); !k {
return ""
} else {
return v
}
}
func (o *dmp) CacheSet(endpoint, ip string) {
o.z.Store(endpoint, ip)
}
func (o *dmp) Add(endpoint, ip string) {
o.d.Store(endpoint, ip)
}
func (o *dmp) Get(endpoint string) string {
if i, l := o.d.Load(endpoint); !l {
return ""
} else if s, k := i.(string); !k {
return ""
} else {
return s
}
}
func (o *dmp) Search(endpoint string) string {
var res string
o.d.Range(func(key, value any) bool {
var (
e error
k bool
h string
src string
dst string
)
if src, k = key.(string); !k {
return true
} else if dst, k = value.(string); !k {
return true
}
if strings.EqualFold(src, endpoint) {
res = dst
return false
}
h, _, e = net.SplitHostPort(src)
if e == nil {
src = h
}
if strings.EqualFold(src, endpoint) {
res = dst
return false
} else if strings.HasPrefix(src, "*.") {
// search for wildcard
f := src
t := endpoint
for strings.HasPrefix(f, "*.") {
if p := strings.SplitAfterN(f, ".", 2); len(p) > 1 {
f = p[1]
} else {
break
}
if p := strings.SplitAfterN(t, ".", 2); len(p) > 1 {
t = p[1]
}
}
if strings.EqualFold(f, t) {
res = dst
return false
}
}
return true
})
return res
}
func (o *dmp) Del(endpoint string) {
o.d.Delete(endpoint)
}
func (o *dmp) TimeCleaner(ctx context.Context, dur time.Duration) {
if dur < 5*time.Second {
dur = 5 * time.Minute
}
go func() {
var tck = time.NewTicker(dur)
defer tck.Stop()
for {
if ctx.Err() != nil {
return
}
select {
case <-tck.C:
o.DefaultTransport().CloseIdleConnections()
case <-ctx.Done():
return
}
}
}()
}
func (o *dmp) Len() int {
var i int
o.d.Range(func(key, value any) bool {
i++
return true
})
return i
}

View File

@@ -0,0 +1,199 @@
/*
* MIT License
*
* Copyright (c) 2020 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 dns_mapper
import (
"context"
"crypto/tls"
"net"
"net/http"
"net/url"
"time"
libtls "github.com/nabbar/golib/certificates"
libdur "github.com/nabbar/golib/duration"
)
func (o *dmp) dialer() *net.Dialer {
return &net.Dialer{
Timeout: o.configDialerTimeout(),
DualStack: true,
KeepAlive: o.configDialerKeepAlive(),
}
}
func (o *dmp) Dial(network, address string) (net.Conn, error) {
return o.DialContext(context.Background(), network, address)
}
func (o *dmp) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
var (
e error
d = o.dialer()
a string
hs string
ps string
)
if o.CacheHas(address) {
a = o.CacheGet(address)
}
if len(a) > 0 {
return d.DialContext(ctx, network, a)
} else {
a = o.Get(address)
}
hs, ps, e = net.SplitHostPort(address)
if e != nil {
return nil, e
}
if len(a) < 1 {
a = o.Get(hs)
}
if len(a) < 1 {
a = o.Search(hs)
}
if len(a) < 1 {
o.CacheSet(address, address)
return d.DialContext(ctx, network, address)
} else if _, _, e = net.SplitHostPort(a); e == nil {
o.CacheSet(address, a)
return d.DialContext(ctx, network, a)
} else {
a = net.JoinHostPort(a, ps)
o.CacheSet(address, a)
return d.DialContext(ctx, network, a)
}
}
func (o *dmp) Transport(cfg TransportConfig) *http.Transport {
var prx func(*http.Request) (*url.URL, error)
if cfg.Proxy == nil {
prx = http.ProxyFromEnvironment
} else {
prx = http.ProxyURL(cfg.Proxy)
}
var (
err error
ssl libtls.TLSConfig
)
if cfg.TLSConfig == nil {
ssl = libtls.New()
ssl.SetVersionMin(tls.VersionTLS12)
ssl.SetVersionMax(tls.VersionTLS13)
} else if ssl, err = cfg.TLSConfig.New(); err != nil {
ssl = libtls.New()
ssl.SetVersionMin(tls.VersionTLS12)
ssl.SetVersionMax(tls.VersionTLS13)
}
for _, c := range o.f() {
ssl.AddRootCAString(c)
}
if cfg.TimeoutGlobal == 0 {
cfg.TimeoutGlobal = libdur.ParseDuration(30 * time.Second)
}
if cfg.TimeoutKeepAlive == 0 {
cfg.TimeoutKeepAlive = libdur.ParseDuration(15 * time.Second)
}
if cfg.TimeoutTLSHandshake == 0 {
cfg.TimeoutTLSHandshake = libdur.ParseDuration(10 * time.Second)
}
if cfg.TimeoutExpectContinue == 0 {
cfg.TimeoutExpectContinue = libdur.ParseDuration(3 * time.Second)
}
if cfg.TimeoutIdleConn == 0 {
cfg.TimeoutIdleConn = libdur.ParseDuration(90 * time.Second)
}
if cfg.MaxConnsPerHost == 0 {
cfg.MaxIdleConns = 25
}
if cfg.MaxIdleConnsPerHost == 0 {
cfg.MaxIdleConnsPerHost = 5
}
if cfg.MaxIdleConns == 0 {
cfg.MaxIdleConns = 25
}
return &http.Transport{
Proxy: prx,
Dial: o.Dial,
DialContext: o.DialContext,
TLSClientConfig: ssl.TlsConfig(""),
TLSHandshakeTimeout: cfg.TimeoutTLSHandshake.Time(),
DisableKeepAlives: cfg.DisableKeepAlive,
DisableCompression: cfg.DisableCompression,
MaxIdleConns: cfg.MaxIdleConns,
MaxIdleConnsPerHost: cfg.MaxIdleConnsPerHost,
MaxConnsPerHost: cfg.MaxConnsPerHost,
IdleConnTimeout: cfg.TimeoutIdleConn.Time(),
ResponseHeaderTimeout: cfg.TimeoutResponseHeader.Time(),
ExpectContinueTimeout: cfg.TimeoutExpectContinue.Time(),
ForceAttemptHTTP2: !cfg.DisableHTTP2,
}
}
func (o *dmp) Client(cfg TransportConfig) *http.Client {
return &http.Client{
Transport: o.Transport(cfg),
}
}
func (o *dmp) DefaultTransport() *http.Transport {
i := o.t.Load()
if i != nil {
if t, k := i.(*http.Transport); k {
return t
}
}
t := o.Transport(o.config().Transport)
o.t.Store(t)
return t
}
func (o *dmp) DefaultClient() *http.Client {
return &http.Client{
Transport: o.DefaultTransport(),
}
}

View File

@@ -47,10 +47,19 @@ var srv = &http.Server{
Handler: Hello(),
}
var (
ctx context.Context
cnl context.CancelFunc
)
func TestGolibHttpCliHelper(t *testing.T) {
defer func() {
_ = srv.Shutdown(context.Background())
}()
ctx, cnl = context.WithCancel(context.Background())
defer cnl()
go func() {
if e := srv.ListenAndServe(); e != nil {
if !errors.Is(e, http.ErrServerClosed) {
@@ -58,6 +67,7 @@ func TestGolibHttpCliHelper(t *testing.T) {
}
}
}()
time.Sleep(500 * time.Millisecond)
RegisterFailHandler(Fail)

View File

@@ -28,11 +28,11 @@ package httpcli_test
import (
"io"
"net/http"
"time"
libptc "github.com/nabbar/golib/network/protocol"
libdur "github.com/nabbar/golib/duration"
htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
libtls "github.com/nabbar/golib/certificates"
"github.com/nabbar/golib/httpcli"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
@@ -40,7 +40,8 @@ import (
var (
cli *http.Client
err error
opt httpcli.Options
opt htcdns.Config
dns htcdns.DNSMapper
rsp *http.Response
)
@@ -52,24 +53,29 @@ var _ = Describe("HttpCli", func() {
}()
Context("Get URL with a Force IP", func() {
It("Create new client must succeed", func() {
opt = httpcli.Options{
Timeout: 0,
Http2: true,
TLS: httpcli.OptionTLS{
Enable: false,
Config: libtls.Config{},
},
ForceIP: httpcli.OptionForceIP{
Enable: true,
Net: libptc.NetworkTCP,
IP: "127.0.0.1:8080",
},
opt = htcdns.Config{
DNSMapper: make(map[string]string),
TimerClean: libdur.ParseDuration(30 * time.Second),
Transport: htcdns.TransportConfig{},
}
cli, err = opt.GetClient(nil, "")
Expect(err).ToNot(HaveOccurred())
dns = htcdns.New(ctx, &opt, nil)
cli = dns.DefaultClient()
Expect(cli).ToNot(BeNil())
})
It("Get URL must succeed", func() {
It("Get URL must succeed for DNS Mapper with host", func() {
dns.Del("test.me.example.com:80")
dns.Add("test.me.example.com", "127.0.0.1:8080")
rsp, err = cli.Get("http://test.me.example.com/path/any/thing")
Expect(err).ToNot(HaveOccurred())
Expect(rsp).ToNot(BeNil())
})
It("Get URL must succeed for DNS Mapper with host & port", func() {
dns.Del("test.me.example.com")
dns.Add("test.me.example.com:80", "127.0.0.1:8080")
rsp, err = cli.Get("http://test.me.example.com/path/any/thing")
Expect(err).ToNot(HaveOccurred())
Expect(rsp).ToNot(BeNil())

View File

@@ -27,8 +27,6 @@
package httpcli
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
@@ -36,9 +34,8 @@ import (
libval "github.com/go-playground/validator/v10"
libtls "github.com/nabbar/golib/certificates"
cmptls "github.com/nabbar/golib/config/components/tls"
cfgcst "github.com/nabbar/golib/config/const"
liberr "github.com/nabbar/golib/errors"
htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
libptc "github.com/nabbar/golib/network/protocol"
)
@@ -72,33 +69,7 @@ type Options struct {
}
func DefaultConfig(indent string) []byte {
var (
res = bytes.NewBuffer(make([]byte, 0))
def = []byte(`{
"timeout":"0s",
"disable-keep-alive": false,
"disable-compression": false,
"http2": true,
"tls": ` + string(cmptls.DefaultConfig(cfgcst.JSONIndent)) + `,
"force_ip": {
"enable": false,
"net":"tcp",
"ip":"127.0.0.1:8080",
"local":"127.0.0.1"
},
"proxy": {
"enable": false,
"endpoint":"http://example.com",
"username":"example",
"password":"example"
}
}`)
)
if err := json.Indent(res, def, indent, cfgcst.JSONIndent); err != nil {
return def
} else {
return res.Bytes()
}
return htcdns.DefaultConfig(indent)
}
func (o Options) Validate() liberr.Error {
@@ -123,60 +94,5 @@ func (o Options) Validate() liberr.Error {
}
func (o Options) GetClient(def libtls.TLSConfig, servername string) (*http.Client, liberr.Error) {
var (
tls libtls.TLSConfig
edp *url.URL
)
if t, e := o._GetTLS(def); e != nil {
return nil, e
} else {
tls = t
}
if o.Proxy.Enable && o.Proxy.Endpoint != nil {
edp = &url.URL{
Scheme: o.Proxy.Endpoint.Scheme,
Opaque: o.Proxy.Endpoint.Opaque,
User: nil,
Host: o.Proxy.Endpoint.Host,
Path: o.Proxy.Endpoint.Path,
RawPath: o.Proxy.Endpoint.RawPath,
OmitHost: o.Proxy.Endpoint.OmitHost,
ForceQuery: o.Proxy.Endpoint.ForceQuery,
RawQuery: o.Proxy.Endpoint.RawQuery,
Fragment: o.Proxy.Endpoint.Fragment,
RawFragment: o.Proxy.Endpoint.RawFragment,
}
if len(o.Proxy.Password) > 0 {
edp.User = url.UserPassword(o.Proxy.Username, o.Proxy.Password)
} else if len(o.Proxy.Username) > 0 {
edp.User = url.User(o.Proxy.Username)
} else if o.Proxy.Endpoint.User != nil {
if p, k := o.Proxy.Endpoint.User.Password(); k {
edp.User = url.UserPassword(o.Proxy.Endpoint.User.Username(), p)
} else {
edp.User = url.User(o.Proxy.Endpoint.User.Username())
}
}
if edp != nil && len(edp.String()) < 1 {
edp = nil
}
}
var tr *http.Transport
tr = GetTransport(tls.TlsConfig(""), edp, o.DisableKeepAlive, o.DisableCompression, o.Http2)
SetTransportDial(tr, o.ForceIP.Enable, o.ForceIP.Net, o.ForceIP.IP, o.ForceIP.Local)
return GetClient(tr, o.Http2, o.Timeout)
}
func (o Options) _GetTLS(def libtls.TLSConfig) (libtls.TLSConfig, liberr.Error) {
if o.TLS.Enable {
return o.TLS.Config.NewFrom(def)
} else {
return libtls.Default.Clone(), nil
}
return GetClient(), nil
}

View File

@@ -29,10 +29,9 @@ package httpserver
import (
"sync"
liblog "github.com/nabbar/golib/logger"
libctx "github.com/nabbar/golib/context"
srvtps "github.com/nabbar/golib/httpserver/types"
liblog "github.com/nabbar/golib/logger"
montps "github.com/nabbar/golib/monitor/types"
libsrv "github.com/nabbar/golib/server"
libver "github.com/nabbar/golib/version"

View File

@@ -30,14 +30,15 @@ import (
"context"
"errors"
"fmt"
"net"
"runtime"
logent "github.com/nabbar/golib/logger/entry"
loglvl "github.com/nabbar/golib/logger/level"
libmon "github.com/nabbar/golib/monitor"
moninf "github.com/nabbar/golib/monitor/info"
montps "github.com/nabbar/golib/monitor/types"
libptc "github.com/nabbar/golib/network/protocol"
libver "github.com/nabbar/golib/version"
)
@@ -90,9 +91,16 @@ func (o *srv) runAndHealthy(ctx context.Context) error {
return errNotRunning
} else if e := o.PortNotUse(ctx, o.GetBindable()); e != nil {
return e
} else {
d := &net.Dialer{}
co, ce := d.DialContext(ctx, libptc.NetworkTCP.Code(), o.GetBindable())
defer func() {
if co != nil {
_ = co.Close()
}
}()
return ce
}
return nil
}
func (o *srv) MonitorName() string {

View File

@@ -28,6 +28,7 @@ package pool
import (
"context"
"time"
libhtp "github.com/nabbar/golib/httpserver"
)
@@ -106,3 +107,17 @@ func (o *pool) IsRunning() bool {
return run
}
func (o *pool) Uptime() time.Duration {
var res time.Duration
o.Walk(func(name string, val libhtp.Server) bool {
if dur := val.Uptime(); res < dur {
res = dur
}
return true
})
return res
}

View File

@@ -31,6 +31,7 @@ import (
"fmt"
"net"
"net/http"
"time"
srvtps "github.com/nabbar/golib/httpserver/types"
loglvl "github.com/nabbar/golib/logger/level"
@@ -227,3 +228,14 @@ func (o *srv) runFuncStop(ctx context.Context) (err error) {
return err
}
func (o *srv) Uptime() time.Duration {
o.m.RLock()
defer o.m.RUnlock()
if o.r != nil {
return o.r.Uptime()
}
return 0
}

View File

@@ -30,6 +30,7 @@ import (
"context"
"fmt"
"strings"
"time"
montps "github.com/nabbar/golib/monitor/types"
)
@@ -98,3 +99,18 @@ func (o *pool) IsRunning() bool {
return res
}
func (o *pool) Uptime() time.Duration {
var res time.Duration
o.MonitorWalk(func(name string, val montps.Monitor) bool {
if dur := val.Uptime(); res < dur {
res = dur
}
return true
})
return res
}

View File

@@ -33,13 +33,12 @@ import (
"net/http"
"net/url"
"sync"
"sync/atomic"
liblog "github.com/nabbar/golib/logger"
montps "github.com/nabbar/golib/monitor/types"
libtls "github.com/nabbar/golib/certificates"
libctx "github.com/nabbar/golib/context"
libhtc "github.com/nabbar/golib/httpcli"
liblog "github.com/nabbar/golib/logger"
montps "github.com/nabbar/golib/monitor/types"
libver "github.com/nabbar/golib/version"
)
@@ -105,7 +104,7 @@ type Request interface {
GetOption() *Options
SetOption(opt *Options) error
RegisterHTTPClient(fct libtls.FctHttpClient)
RegisterHTTPClient(cli libhtc.HttpClient)
RegisterDefaultLogger(fct liblog.FuncLog)
RegisterContext(fct libctx.FuncContext)
@@ -120,20 +119,23 @@ type Request interface {
HealthCheck(ctx context.Context) error
}
func New(ctx libctx.FuncContext, opt *Options) (Request, error) {
func New(ctx libctx.FuncContext, opt *Options, cli libhtc.HttpClient) (Request, error) {
r := &request{
s: sync.Mutex{},
o: nil,
x: ctx,
f: nil,
l: nil,
u: nil,
h: make(url.Values),
p: make(url.Values),
b: bytes.NewBuffer(make([]byte, 0)),
m: http.MethodGet,
e: nil,
c: new(atomic.Value),
}
r.c.Store(cli)
if e := r.SetOption(opt); e != nil {
return nil, e
} else {

View File

@@ -29,15 +29,13 @@ package request
import (
"context"
"io"
"net/http"
"net/url"
"sync"
"sync/atomic"
liblog "github.com/nabbar/golib/logger"
libtls "github.com/nabbar/golib/certificates"
libctx "github.com/nabbar/golib/context"
libhtc "github.com/nabbar/golib/httpcli"
liblog "github.com/nabbar/golib/logger"
)
const (
@@ -51,16 +49,16 @@ const (
type request struct {
s sync.Mutex
o *atomic.Value // Options
x libctx.FuncContext // Context function
f libtls.FctHttpClient // Http client func
l liblog.FuncLog // Default logger
u *url.URL // endpoint url
h url.Values // header values
p url.Values // parameters values
b io.Reader // body io reader
m string // method
e *requestError // Error pointer
o *atomic.Value // Options
x libctx.FuncContext // Context function
l liblog.FuncLog // Default logger
u *url.URL // endpoint url
h url.Values // header values
p url.Values // parameters values
b io.Reader // body io reader
m string // method
e *requestError // Error pointer
c *atomic.Value // libhtc HTTPClient
}
func (r *request) Clone() (Request, error) {
@@ -97,7 +95,7 @@ func (r *request) New() (Request, error) {
c = &Options{}
}
if i, e := New(r.x, c); e != nil {
if i, e := New(r.x, c, r.client()); e != nil {
return nil, e
} else {
n = i.(*request)
@@ -122,10 +120,6 @@ func (r *request) New() (Request, error) {
n.l = r.l
}
if r.f != nil {
n.f = r.f
}
return n, nil
}
@@ -139,28 +133,16 @@ func (r *request) context() context.Context {
return context.Background()
}
func (r *request) client() *http.Client {
var h string
if r.u != nil {
h = r.u.Hostname()
func (r *request) client() libhtc.HttpClient {
if i := r.c.Load(); i != nil {
if c, k := i.(libhtc.HttpClient); k {
return c
}
}
if r.f == nil {
return r.clientDefault(h)
} else if c := r.f(r.defaultTLS(), h); c != nil {
return c
} else {
return r.clientDefault(h)
}
}
func (r *request) clientDefault(h string) *http.Client {
if cfg := r.options(); cfg != nil {
return cfg.ClientHTTP(h)
} else {
return &http.Client{}
}
c := libhtc.GetClient()
r.c.Store(c)
return c
}
func (r *request) Error() Error {

View File

@@ -36,9 +36,7 @@ import (
"runtime"
logent "github.com/nabbar/golib/logger/entry"
loglvl "github.com/nabbar/golib/logger/level"
libmon "github.com/nabbar/golib/monitor"
moninf "github.com/nabbar/golib/monitor/info"
montps "github.com/nabbar/golib/monitor/types"

View File

@@ -28,17 +28,14 @@ package request
import (
"fmt"
"net/http"
"sync/atomic"
liblog "github.com/nabbar/golib/logger"
moncfg "github.com/nabbar/golib/monitor/types"
libval "github.com/go-playground/validator/v10"
libtls "github.com/nabbar/golib/certificates"
libctx "github.com/nabbar/golib/context"
libhtc "github.com/nabbar/golib/httpcli"
liblog "github.com/nabbar/golib/logger"
moncfg "github.com/nabbar/golib/monitor/types"
)
type OptionsCredentials struct {
@@ -73,10 +70,9 @@ type OptionsHealthResult struct {
}
type Options struct {
Endpoint string `json:"endpoint" yaml:"endpoint" toml:"endpoint" mapstructure:"endpoint" validate:"url"`
HttpClient libhtc.Options `json:"http_client" yaml:"http_client" toml:"http_client" mapstructure:"http_client" validate:""`
Auth OptionsAuth `json:"auth" yaml:"auth" toml:"auth" mapstructure:"auth" validate:""`
Health OptionsHealth `json:"health" yaml:"health" toml:"health" mapstructure:"health" validate:""`
Endpoint string `json:"endpoint" yaml:"endpoint" toml:"endpoint" mapstructure:"endpoint" validate:"url"`
Auth OptionsAuth `json:"auth" yaml:"auth" toml:"auth" mapstructure:"auth" validate:""`
Health OptionsHealth `json:"health" yaml:"health" toml:"health" mapstructure:"health" validate:""`
tls libtls.FctTLSDefault
log liblog.FuncLog
@@ -140,20 +136,8 @@ func (o *Options) SetDefaultLog(fct liblog.FuncLog) {
o.log = fct
}
func (o *Options) ClientHTTPTLS(tls libtls.TLSConfig, servername string) *http.Client {
if c, e := o.HttpClient.GetClient(tls, servername); e == nil {
return c
}
return &http.Client{}
}
func (o *Options) ClientHTTP(servername string) *http.Client {
return o.ClientHTTPTLS(o.defaultTLS(), servername)
}
func (o *Options) New(ctx libctx.FuncContext) (Request, error) {
if n, e := New(ctx, o); e != nil {
func (o *Options) New(ctx libctx.FuncContext, cli libhtc.HttpClient) (Request, error) {
if n, e := New(ctx, o, cli); e != nil {
return nil, e
} else {
if o.log != nil {
@@ -166,7 +150,6 @@ func (o *Options) New(ctx libctx.FuncContext) (Request, error) {
return l
})
}
n.RegisterHTTPClient(o.ClientHTTPTLS)
return n, nil
}
}
@@ -200,8 +183,6 @@ func (o *Options) Update(ctx libctx.FuncContext, req Request) (Request, error) {
})
}
n.RegisterHTTPClient(o.ClientHTTPTLS)
return n, nil
}
@@ -245,11 +226,11 @@ func (r *request) SetOption(opt *Options) error {
return nil
}
func (r *request) RegisterHTTPClient(fct libtls.FctHttpClient) {
r.s.Lock()
defer r.s.Unlock()
r.f = fct
func (r *request) RegisterHTTPClient(cli libhtc.HttpClient) {
if cli == nil {
return
}
r.c.Store(cli)
}
func (r *request) RegisterDefaultLogger(fct liblog.FuncLog) {

View File

@@ -53,7 +53,7 @@ func (o *sem) defOpts(unit interface{}, name, job string, bar semtps.Bar) []sdkm
if len(name) > 0 {
dec = append(dec,
mpbdec.Name(name, mpbdec.WC{W: len(name) + 1, C: mpbdec.DidentRight}),
mpbdec.Name(name, mpbdec.WC{W: len(name) + 1, C: mpbdec.DindentRight}),
)
}
@@ -64,7 +64,7 @@ func (o *sem) defOpts(unit interface{}, name, job string, bar semtps.Bar) []sdkm
)
}
dec = append(dec,
mpbdec.Name(job, mpbdec.WC{W: len(job) + 1, C: mpbdec.DidentRight | mpbdec.DextraSpace}),
mpbdec.Name(job, mpbdec.WC{W: len(job) + 1, C: mpbdec.DindentRight | mpbdec.DextraSpace}),
)
}

View File

@@ -28,6 +28,7 @@ package server
import (
"context"
"time"
)
type Action func(ctx context.Context) error
@@ -44,6 +45,9 @@ type Server interface {
// IsRunning return true if the server is currently running
IsRunning() bool
//Uptime return the duration since last launch
Uptime() time.Duration
}
type WaitNotify interface {

View File

@@ -44,6 +44,7 @@ func New(start, stop func(ctx context.Context) error) StartStop {
e: new(atomic.Value),
f: start,
s: stop,
t: new(atomic.Value),
c: new(atomic.Value),
}
}

View File

@@ -52,6 +52,7 @@ type run struct {
e *atomic.Value // slice []error
f libsrv.Action
s libsrv.Action
t *atomic.Value
c *atomic.Value // chan struct{}
}
@@ -96,6 +97,8 @@ func (o *run) Stop(ctx context.Context) error {
t = time.NewTicker(pollStop)
)
o.t.Store(time.Time{})
defer func() {
if rec := recover(); rec != nil {
_, _ = fmt.Fprintf(os.Stderr, "recovering panic thread on Stop function in gollib/server/startStop/model.\n%v\n", rec)
@@ -133,6 +136,7 @@ func (o *run) Start(ctx context.Context) error {
var can context.CancelFunc
ctx, can = context.WithCancel(ctx)
o.t.Store(time.Now())
go func(x context.Context, n context.CancelFunc) {
defer n()
@@ -191,3 +195,13 @@ func (o *run) checkMeStart(ctx context.Context) error {
return nil
}
func (o *run) Uptime() time.Duration {
if i := o.t.Load(); i == nil {
return 0
} else if t, k := i.(time.Time); !k {
return 0
} else {
return time.Since(t)
}
}

View File

@@ -45,6 +45,7 @@ func New(tick time.Duration, fct func(ctx context.Context, tck *time.Ticker) err
e: new(atomic.Value),
f: fct,
d: tick,
t: new(atomic.Value),
c: new(atomic.Value),
}
}

View File

@@ -51,6 +51,7 @@ type run struct {
e *atomic.Value // slice []error
f func(ctx context.Context, tck *time.Ticker) error
d time.Duration
t *atomic.Value
c *atomic.Value // chan struct{}
}
@@ -78,7 +79,11 @@ func (o *run) Restart(ctx context.Context) error {
func (o *run) Stop(ctx context.Context) error {
if e := o.checkMe(); e != nil {
return e
} else if !o.IsRunning() {
}
o.t.Store(time.Time{})
if !o.IsRunning() {
return nil
}
@@ -123,6 +128,8 @@ func (o *run) Start(ctx context.Context) error {
o.chanClose()
}()
o.t.Store(time.Now())
o.chanInit()
o.errorsClean()
@@ -172,3 +179,13 @@ func (o *run) checkMeStart(ctx context.Context) error {
return nil
}
func (o *run) Uptime() time.Duration {
if i := o.t.Load(); i == nil {
return 0
} else if t, k := i.(time.Time); !k {
return 0
} else {
return time.Since(t)
}
}

View File

@@ -31,9 +31,7 @@ import (
"sync/atomic"
libptc "github.com/nabbar/golib/network/protocol"
libsiz "github.com/nabbar/golib/size"
libsck "github.com/nabbar/golib/socket"
)

View File

@@ -30,10 +30,8 @@ import (
"net"
"sync/atomic"
libsiz "github.com/nabbar/golib/size"
libptc "github.com/nabbar/golib/network/protocol"
libsiz "github.com/nabbar/golib/size"
libsck "github.com/nabbar/golib/socket"
)

View File

@@ -33,7 +33,6 @@ import (
"sync/atomic"
libsiz "github.com/nabbar/golib/size"
libsck "github.com/nabbar/golib/socket"
)

View File

@@ -171,7 +171,9 @@ func (o *cli) sendRequest(con net.Conn, r io.Reader) {
if !errors.Is(err, io.EOF) {
o.fctError(err)
}
return
if len(buf) < 1 {
return
}
}
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionWrite)

View File

@@ -33,7 +33,6 @@ import (
"sync/atomic"
libsiz "github.com/nabbar/golib/size"
libsck "github.com/nabbar/golib/socket"
)

View File

@@ -139,7 +139,7 @@ func (o *srv) Listen(ctx context.Context) error {
if co, ce := l.Accept(); ce != nil && !s.Load() {
o.fctError(ce)
} else {
} else if co != nil {
o.fctInfo(co.LocalAddr(), co.RemoteAddr(), libsck.ConnectionNew)
go o.Conn(co)
}
@@ -171,7 +171,9 @@ func (o *srv) Conn(conn net.Conn) {
if err != io.EOF {
o.fctError(err)
}
break
if len(msg) < 1 {
break
}
}
var buf = bytes.NewBuffer(msg)

View File

@@ -34,9 +34,8 @@ import (
"sync/atomic"
"time"
libptc "github.com/nabbar/golib/network/protocol"
libtls "github.com/nabbar/golib/certificates"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
)

View File

@@ -162,7 +162,9 @@ func (o *srv) Listen(ctx context.Context) error {
if !stp.Load() {
o.fctError(rer)
}
continue
if nbr < 1 {
continue
}
}
go func(la, ra net.Addr, b []byte) {

View File

@@ -33,9 +33,8 @@ import (
"sync/atomic"
"time"
libptc "github.com/nabbar/golib/network/protocol"
libtls "github.com/nabbar/golib/certificates"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
)

View File

@@ -44,7 +44,6 @@ import (
"syscall"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
)
@@ -220,7 +219,7 @@ func (o *srv) Listen(ctx context.Context) error {
if co, ce := l.Accept(); ce != nil && !s.Load() {
o.fctError(ce)
} else {
} else if co != nil {
o.fctInfo(co.LocalAddr(), co.RemoteAddr(), libsck.ConnectionNew)
go o.Conn(co)
}
@@ -252,7 +251,9 @@ func (o *srv) Conn(con net.Conn) {
if err != io.EOF {
o.fctError(err)
}
break
if len(msg) < 1 {
break
}
}
var buf = bytes.NewBuffer(msg)

View File

@@ -37,9 +37,8 @@ import (
"sync/atomic"
"time"
libptc "github.com/nabbar/golib/network/protocol"
libtls "github.com/nabbar/golib/certificates"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
)

View File

@@ -43,7 +43,6 @@ import (
"syscall"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
)
@@ -232,7 +231,9 @@ func (o *srv) Listen(ctx context.Context) error {
if !stp.Load() {
o.fctError(rer)
}
continue
if nbr < 1 {
continue
}
}
go func(la, ra net.Addr, b []byte) {

View File

@@ -37,9 +37,8 @@ import (
"sync/atomic"
"time"
libptc "github.com/nabbar/golib/network/protocol"
libtls "github.com/nabbar/golib/certificates"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
)