Package Certificates:

- fix bug with cert type marshall/unmarshall
- add old config to allow retro compatibility
- add new type function to retrieve a tls root ca cert instead of a slice of string to get root ca

Package HTTPCli:
- fix default DNS Mapper
- optimze global DNS Mapper
- fix non closing sub goroutine

Package HTTPCli/DNS-Mapper:
- change request function of Root CA with function of root ca cert instance
- add function to return a root ca cert from a function that return a slice of root ca string

Package Config/Components:
- httpcli: bump sub package of certificate, httpcli
- httpcli: adjust code following bump
- httpcli: change request function of Root CA with function of root ca cert instance
- httpcli: add function to return a root ca cert from a function that return a slice of root ca string
- tls: change request function of Root CA with function of root ca cert instance
- tls: add function to return a root ca cert from a function that return a slice of root ca string

Package IOUtils/mapCloser:
- fix bug with mapcloser not stopped
- optimize code & goroutine

Package Logger:
- rework mapCloser call
- optimize mapClaoser managment

Package Request:
- rework error managment
- using []byte instead of buffer to read response body
- add free capability
- optimize memory consumption

Package Socket / Server:
- add filtering error capability
- add params to specify a function called on each new connection and before using the connection
- the new function param allow to update the network incomming connection (like buffer, deadline...)
- rework some useless atomic to direct value to optimize code

Package Socket/Delim:
- rework to optimize memory & variable use
- remove capabilities of update the instance when running, prefert recreate new one if necessary

Other:
- bump dependencies
- minor bug / fix
This commit is contained in:
Nicolas JUHEL
2025-01-06 11:32:54 +01:00
parent 22b364593e
commit 61a73ba606
67 changed files with 1220 additions and 527 deletions

View File

@@ -58,7 +58,10 @@ type Cert interface {
cbor.Unmarshaler cbor.Unmarshaler
fmt.Stringer fmt.Stringer
Len() int
AppendPool(p *x509.CertPool) AppendPool(p *x509.CertPool)
AppendBytes(p []byte) error
AppendString(str string) error
} }
func Parse(str string) (Cert, error) { func Parse(str string) (Cert, error) {

View File

@@ -37,6 +37,30 @@ type mod struct {
c []*x509.Certificate c []*x509.Certificate
} }
func (m *mod) Len() int {
return len(m.c)
}
func (m *mod) AppendBytes(p []byte) error {
c := &mod{
c: make([]*x509.Certificate, 0),
}
if e := c.unMarshall(p); e != nil {
return e
}
for _, i := range c.c {
m.c = append(m.c, i)
}
return nil
}
func (m *mod) AppendString(str string) error {
return m.AppendBytes([]byte(str))
}
func ViperDecoderHook() libmap.DecodeHookFuncType { func ViperDecoderHook() libmap.DecodeHookFuncType {
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) { return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
var ( var (

View File

@@ -27,9 +27,6 @@ package certificates_test
import ( import (
"os" "os"
"path/filepath"
"reflect"
"strings"
"testing" "testing"
"time" "time"
@@ -44,32 +41,23 @@ import (
type EmptyStruct struct{} type EmptyStruct struct{}
var ( const (
keyFile string keyFile = "test_ed25519.key"
pubFile string pubFile = "test_ed25519.pub"
) )
// TestGolibEncodingAESHelper tests the Golib AES Encoding Helper function. // TestGolibEncodingAESHelper tests the Golib AES Encoding Helper function.
func TestGolibArchiveHelper(t *testing.T) { func TestGolibCertificatesHelper(t *testing.T) {
time.Sleep(500 * time.Millisecond) // Adding delay for better testing synchronization time.Sleep(500 * time.Millisecond) // Adding delay for better testing synchronization
RegisterFailHandler(Fail) // Registering fail handler for better test failure reporting RegisterFailHandler(Fail) // Registering fail handler for better test failure reporting
RunSpecs(t, "Certificates Helper Suite") // Running the test suite for Encoding AES Helper RunSpecs(t, "Certificates Helper Suite") // Running the test suite for Encoding AES Helper
} }
var _ = BeforeSuite(func() {
keyFile = filepath.Join(os.Getenv("GOPATH"), "src", strings.Replace(reflect.TypeOf(EmptyStruct{}).PkgPath(), "_test", "", -1), "test_ed25519.key")
pubFile = filepath.Join(os.Getenv("GOPATH"), "src", strings.Replace(reflect.TypeOf(EmptyStruct{}).PkgPath(), "_test", "", -1), "test_ed25519.pub")
})
var _ = AfterSuite(func() { var _ = AfterSuite(func() {
if keyFile != "" { if _, e := os.Stat(keyFile); e == nil {
if _, e := os.Stat(keyFile); e == nil { Expect(os.Remove(keyFile)).ToNot(HaveOccurred())
Expect(os.Remove(keyFile)).ToNot(HaveOccurred())
}
} }
if pubFile != "" { if _, e := os.Stat(pubFile); e == nil {
if _, e := os.Stat(pubFile); e == nil { Expect(os.Remove(pubFile)).ToNot(HaveOccurred())
Expect(os.Remove(pubFile)).ToNot(HaveOccurred())
}
} }
}) })

View File

@@ -27,6 +27,7 @@
package certs package certs
import ( import (
"bytes"
"crypto" "crypto"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/rsa" "crypto/rsa"
@@ -58,8 +59,28 @@ func cleanPem(s string) string {
return strings.TrimSpace(s) return strings.TrimSpace(s)
} }
func cleanPemByte(s []byte) []byte {
s = bytes.TrimSpace(s)
// remove \n\r
s = bytes.Trim(s, "\n")
s = bytes.Trim(s, "\r")
// do again if \r\n
s = bytes.Trim(s, "\n")
s = bytes.Trim(s, "\r")
return bytes.TrimSpace(s)
}
type Config interface { type Config interface {
Cert() (*tls.Certificate, error) Cert() (*tls.Certificate, error)
IsChain() bool
IsPair() bool
IsFile() bool
GetCerts() []string
} }
type ConfigPair struct { type ConfigPair struct {
@@ -68,34 +89,75 @@ type ConfigPair struct {
} }
func (c *ConfigPair) Cert() (*tls.Certificate, error) { func (c *ConfigPair) Cert() (*tls.Certificate, error) {
c.Key = cleanPem(c.Key)
c.Pub = cleanPem(c.Pub)
if c == nil { if c == nil {
return nil, ErrInvalidPairCertificate return nil, ErrInvalidPairCertificate
} else if len(c.Key) < 1 || len(c.Pub) < 1 { }
var (
k = cleanPemByte([]byte(c.Key))
p = cleanPemByte([]byte(c.Pub))
)
if len(k) < 1 || len(p) < 1 {
return nil, ErrInvalidPairCertificate return nil, ErrInvalidPairCertificate
} }
if _, e := os.Stat(c.Key); e == nil { if _, e := os.Stat(string(k)); e == nil {
if b, e := os.ReadFile(c.Key); e == nil { if b, e := os.ReadFile(string(k)); e == nil {
c.Key = cleanPem(string(b)) k = cleanPemByte(b)
} }
} }
if _, e := os.Stat(c.Pub); e == nil { if _, e := os.Stat(string(p)); e == nil {
if b, e := os.ReadFile(c.Pub); e == nil { if b, e := os.ReadFile(string(p)); e == nil {
c.Pub = cleanPem(string(b)) p = cleanPemByte(b)
} }
} }
if crt, err := tls.X509KeyPair([]byte(c.Pub), []byte(c.Key)); err != nil { if crt, err := tls.X509KeyPair(p, k); err != nil {
return nil, err return nil, err
} else { } else {
return &crt, nil return &crt, nil
} }
} }
func (c *ConfigPair) IsChain() bool {
return false
}
func (c *ConfigPair) IsPair() bool {
return true
}
func (c *ConfigPair) IsFile() bool {
if c == nil {
return false
}
var (
k = cleanPemByte([]byte(c.Key))
p = cleanPemByte([]byte(c.Pub))
)
if len(k) < 1 || len(p) < 1 {
return false
}
if _, e := os.Stat(string(k)); e == nil {
return true
}
if _, e := os.Stat(string(p)); e == nil {
return true
}
return false
}
func (c *ConfigPair) GetCerts() []string {
return []string{c.Key, c.Pub}
}
type ConfigChain string type ConfigChain string
func (c *ConfigChain) Cert() (*tls.Certificate, error) { func (c *ConfigChain) Cert() (*tls.Certificate, error) {
@@ -163,3 +225,26 @@ func (c *ConfigChain) getPrivateKey(der []byte) (crypto.PrivateKey, error) {
} }
return nil, ErrInvalidPrivateKey return nil, ErrInvalidPrivateKey
} }
func (c *ConfigChain) IsChain() bool {
return true
}
func (c *ConfigChain) IsPair() bool {
return false
}
func (c *ConfigChain) IsFile() bool {
if c == nil {
return false
}
if _, e := os.Stat(string(*c)); e == nil {
return true
}
return false
}
func (c *ConfigChain) GetCerts() []string {
return []string{string(*c)}
}

View File

@@ -67,6 +67,7 @@ func (o *Certif) UnmarshalText(text []byte) error {
} else if crt == nil || len(crt.Certificate) == 0 { } else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate return ErrInvalidPairCertificate
} else { } else {
o.g = &chn
o.c = *crt o.c = *crt
return nil return nil
} }
@@ -81,8 +82,22 @@ func (o *Certif) UnmarshalBinary(data []byte) error {
} }
func (o *Certif) MarshalJSON() ([]byte, error) { func (o *Certif) MarshalJSON() ([]byte, error) {
t := o.String() var cfg any
return json.Marshal(t)
if o == nil || o.g == nil {
return []byte(""), nil
} else if p := o.g.GetCerts(); len(p) == 1 {
cfg = ConfigChain(o.g.GetCerts()[0])
} else if len(p) == 2 {
cfg = ConfigPair{
Key: p[0],
Pub: p[1],
}
} else {
cfg = o.g
}
return json.Marshal(cfg)
} }
func (o *Certif) UnmarshalJSON(bytes []byte) error { func (o *Certif) UnmarshalJSON(bytes []byte) error {
@@ -93,21 +108,23 @@ func (o *Certif) UnmarshalJSON(bytes []byte) error {
err error err error
) )
if err = json.Unmarshal(bytes, &cfg); err == nil { if err = json.Unmarshal(bytes, &cfg); err == nil && len(cfg.Key) > 0 && len(cfg.Pub) > 0 {
if crt, err = cfg.Cert(); err != nil { if crt, err = cfg.Cert(); err != nil {
return err return err
} else if crt == nil || len(crt.Certificate) == 0 { } else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate return ErrInvalidPairCertificate
} else { } else {
o.g = &cfg
o.c = *crt o.c = *crt
return nil return nil
} }
} else if err = json.Unmarshal(bytes, &chn); err == nil { } else if err = json.Unmarshal(bytes, &chn); err == nil && len(chn) > 0 {
if crt, err = chn.Cert(); err != nil { if crt, err = chn.Cert(); err != nil {
return err return err
} else if crt == nil || len(crt.Certificate) == 0 { } else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate return ErrInvalidPairCertificate
} else { } else {
o.g = &chn
o.c = *crt o.c = *crt
return nil return nil
} }
@@ -117,8 +134,22 @@ func (o *Certif) UnmarshalJSON(bytes []byte) error {
} }
func (o *Certif) MarshalYAML() (interface{}, error) { func (o *Certif) MarshalYAML() (interface{}, error) {
t := o.String() var cfg any
return yaml.Marshal(t)
if o == nil || o.g == nil {
return []byte(""), nil
} else if p := o.g.GetCerts(); len(p) == 1 {
cfg = ConfigChain(o.g.GetCerts()[0])
} else if len(p) == 2 {
cfg = ConfigPair{
Key: p[0],
Pub: p[1],
}
} else {
cfg = o.g
}
return yaml.Marshal(cfg)
} }
func (o *Certif) UnmarshalYAML(value *yaml.Node) error { func (o *Certif) UnmarshalYAML(value *yaml.Node) error {
@@ -130,21 +161,23 @@ func (o *Certif) UnmarshalYAML(value *yaml.Node) error {
err error err error
) )
if err = yaml.Unmarshal(src, &cfg); err == nil { if err = yaml.Unmarshal(src, &cfg); err == nil && len(cfg.Key) > 0 && len(cfg.Pub) > 0 {
if crt, err = cfg.Cert(); err != nil { if crt, err = cfg.Cert(); err != nil {
return err return err
} else if crt == nil || len(crt.Certificate) == 0 { } else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate return ErrInvalidPairCertificate
} else { } else {
o.g = &cfg
o.c = *crt o.c = *crt
return nil return nil
} }
} else if err = yaml.Unmarshal(src, &chn); err == nil { } else if err = yaml.Unmarshal(src, &chn); err == nil && len(chn) > 0 {
if crt, err = chn.Cert(); err != nil { if crt, err = chn.Cert(); err != nil {
return err return err
} else if crt == nil || len(crt.Certificate) == 0 { } else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate return ErrInvalidPairCertificate
} else { } else {
o.g = &chn
o.c = *crt o.c = *crt
return nil return nil
} }
@@ -154,8 +187,22 @@ func (o *Certif) UnmarshalYAML(value *yaml.Node) error {
} }
func (o *Certif) MarshalTOML() ([]byte, error) { func (o *Certif) MarshalTOML() ([]byte, error) {
t := o.String() var cfg any
return toml.Marshal(t)
if o == nil || o.g == nil {
return []byte(""), nil
} else if p := o.g.GetCerts(); len(p) == 1 {
cfg = ConfigChain(o.g.GetCerts()[0])
} else if len(p) == 2 {
cfg = ConfigPair{
Key: p[0],
Pub: p[1],
}
} else {
cfg = o.g
}
return toml.Marshal(cfg)
} }
func (o *Certif) UnmarshalTOML(i interface{}) error { func (o *Certif) UnmarshalTOML(i interface{}) error {
@@ -184,21 +231,23 @@ func (o *Certif) UnmarshalTOML(i interface{}) error {
err error err error
) )
if err = toml.Unmarshal(p, &cfg); err == nil { if err = toml.Unmarshal(p, &cfg); err == nil && len(cfg.Key) > 0 && len(cfg.Pub) > 0 {
if crt, err = cfg.Cert(); err != nil { if crt, err = cfg.Cert(); err != nil {
return err return err
} else if crt == nil || len(crt.Certificate) == 0 { } else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate return ErrInvalidPairCertificate
} else { } else {
o.g = &cfg
o.c = *crt o.c = *crt
return nil return nil
} }
} else if err = toml.Unmarshal(p, &chn); err == nil { } else if err = toml.Unmarshal(p, &chn); err == nil && len(chn) > 0 {
if crt, err = chn.Cert(); err != nil { if crt, err = chn.Cert(); err != nil {
return err return err
} else if crt == nil || len(crt.Certificate) == 0 { } else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate return ErrInvalidPairCertificate
} else { } else {
o.g = &chn
o.c = *crt o.c = *crt
return nil return nil
} }
@@ -208,8 +257,22 @@ func (o *Certif) UnmarshalTOML(i interface{}) error {
} }
func (o *Certif) MarshalCBOR() ([]byte, error) { func (o *Certif) MarshalCBOR() ([]byte, error) {
t := o.String() var cfg any
return cbor.Marshal(t)
if o == nil || o.g == nil {
return []byte(""), nil
} else if p := o.g.GetCerts(); len(p) == 1 {
cfg = ConfigChain(o.g.GetCerts()[0])
} else if len(p) == 2 {
cfg = ConfigPair{
Key: p[0],
Pub: p[1],
}
} else {
cfg = o.g
}
return cbor.Marshal(cfg)
} }
func (o *Certif) UnmarshalCBOR(bytes []byte) error { func (o *Certif) UnmarshalCBOR(bytes []byte) error {
@@ -220,21 +283,23 @@ func (o *Certif) UnmarshalCBOR(bytes []byte) error {
err error err error
) )
if err = cbor.Unmarshal(bytes, &cfg); err == nil { if err = cbor.Unmarshal(bytes, &cfg); err == nil && len(cfg.Key) > 0 && len(cfg.Pub) > 0 {
if crt, err = cfg.Cert(); err != nil { if crt, err = cfg.Cert(); err != nil {
return err return err
} else if crt == nil || len(crt.Certificate) == 0 { } else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate return ErrInvalidPairCertificate
} else { } else {
o.g = &cfg
o.c = *crt o.c = *crt
return nil return nil
} }
} else if err = cbor.Unmarshal(bytes, &chn); err == nil { } else if err = cbor.Unmarshal(bytes, &chn); err == nil && len(chn) > 0 {
if crt, err = chn.Cert(); err != nil { if crt, err = chn.Cert(); err != nil {
return err return err
} else if crt == nil || len(crt.Certificate) == 0 { } else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate return ErrInvalidPairCertificate
} else { } else {
o.g = &chn
o.c = *crt o.c = *crt
return nil return nil
} }

View File

@@ -34,11 +34,19 @@ import (
) )
func (o *Certif) String() string { func (o *Certif) String() string {
str, _ := o.Chain() if o == nil {
return str return ""
}
s, _ := o.Chain()
return cleanPem(s)
} }
func (o *Certif) Pair() (pub string, key string, err error) { func (o *Certif) Pair() (pub string, key string, err error) {
if o == nil {
return "", "", ErrInvalidPairCertificate
}
var ( var (
bufPub = bytes.NewBuffer(make([]byte, 0)) bufPub = bytes.NewBuffer(make([]byte, 0))
bufKey = bytes.NewBuffer(make([]byte, 0)) bufKey = bytes.NewBuffer(make([]byte, 0))
@@ -82,5 +90,8 @@ func (o *Certif) Chain() (string, error) {
} }
func (o *Certif) TLS() tls.Certificate { func (o *Certif) TLS() tls.Certificate {
if o == nil {
return tls.Certificate{}
}
return o.c return o.c
} }

View File

@@ -54,6 +54,12 @@ type Cert interface {
TLS() tls.Certificate TLS() tls.Certificate
Model() Certif Model() Certif
IsChain() bool
IsPair() bool
IsFile() bool
GetCerts() []string
} }
func Parse(chain string) (Cert, error) { func Parse(chain string) (Cert, error) {
@@ -71,6 +77,6 @@ func parseCert(cfg Config) (Cert, error) {
} else if c == nil { } else if c == nil {
return nil, ErrInvalidPairCertificate return nil, ErrInvalidPairCertificate
} else { } else {
return &Certif{c: *c}, nil return &Certif{g: cfg, c: *c}, nil
} }
} }

View File

@@ -34,6 +34,7 @@ import (
) )
type Certif struct { type Certif struct {
g Config
c tls.Certificate c tls.Certificate
} }
@@ -42,9 +43,40 @@ func (o *Certif) Cert() Cert {
} }
func (o *Certif) Model() Certif { func (o *Certif) Model() Certif {
if o == nil {
return Certif{}
}
return *o return *o
} }
func (o *Certif) IsChain() bool {
if o == nil {
return false
}
return o.g.IsChain()
}
func (o *Certif) IsPair() bool {
if o == nil {
return false
}
return o.g.IsPair()
}
func (o *Certif) IsFile() bool {
if o == nil {
return false
}
return o.g.IsFile()
}
func (o *Certif) GetCerts() []string {
if o == nil {
return make([]string, 0)
}
return o.g.GetCerts()
}
func ViperDecoderHook() libmap.DecodeHookFuncType { func ViperDecoderHook() libmap.DecodeHookFuncType {
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) { return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
var ( var (

View File

@@ -38,26 +38,64 @@ func (v Cipher) Code() []string {
switch v { switch v {
case TLS_RSA_WITH_AES_128_GCM_SHA256: case TLS_RSA_WITH_AES_128_GCM_SHA256:
return []string{"rsa", "aes", "128", "gcm", "sha256"} return []string{"rsa", "aes", "128", "gcm", "sha256"}
case TLS_RSA_WITH_AES_128_GCM:
return []string{"rsa", "aes", "128", "gcm"}
case TLS_RSA_WITH_AES128_GCM:
return []string{"rsa", "aes128", "gcm"}
case TLS_RSA_WITH_AES_256_GCM_SHA384: case TLS_RSA_WITH_AES_256_GCM_SHA384:
return []string{"rsa", "aes", "256", "gcm", "sha384"} return []string{"rsa", "aes", "256", "gcm", "sha384"}
case TLS_RSA_WITH_AES_256_GCM:
return []string{"rsa", "aes", "256", "gcm"}
case TLS_RSA_WITH_AES256_GCM:
return []string{"rsa", "aes256", "gcm"}
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
return []string{"ecdhe", "rsa", "aes", "128", "gcm", "sha256"} return []string{"ecdhe", "rsa", "aes", "128", "gcm", "sha256"}
case TLS_ECDHE_RSA_WITH_AES_128_GCM:
return []string{"ecdhe", "rsa", "aes", "128", "gcm"}
case TLS_ECDHE_RSA_WITH_AES128_GCM:
return []string{"ecdhe", "rsa", "aes128", "gcm"}
case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
return []string{"ecdhe", "ecdsa", "aes", "128", "gcm", "sha256"} return []string{"ecdhe", "ecdsa", "aes", "128", "gcm", "sha256"}
case TLS_ECDHE_ECDSA_WITH_AES_128_GCM:
return []string{"ecdhe", "ecdsa", "aes", "128", "gcm"}
case TLS_ECDHE_ECDSA_WITH_AES128_GCM:
return []string{"ecdhe", "ecdsa", "aes128", "gcm"}
case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
return []string{"ecdhe", "rsa", "aes", "256", "gcm", "sha384"} return []string{"ecdhe", "rsa", "aes", "256", "gcm", "sha384"}
case TLS_ECDHE_RSA_WITH_AES_256_GCM:
return []string{"ecdhe", "rsa", "aes", "256", "gcm"}
case TLS_ECDHE_RSA_WITH_AES256_GCM:
return []string{"ecdhe", "rsa", "aes256", "gcm"}
case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
return []string{"ecdhe", "ecdsa", "aes", "256", "gcm", "sha384"} return []string{"ecdhe", "ecdsa", "aes", "256", "gcm", "sha384"}
case TLS_ECDHE_ECDSA_WITH_AES_256_GCM:
return []string{"ecdhe", "ecdsa", "aes", "256", "gcm"}
case TLS_ECDHE_ECDSA_WITH_AES256_GCM:
return []string{"ecdhe", "ecdsa", "aes256", "gcm"}
case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
return []string{"ecdhe", "rsa", "chacha20", "poly1305", "sha256"} return []string{"ecdhe", "rsa", "chacha20", "poly1305", "sha256"}
case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305:
return []string{"ecdhe", "rsa", "chacha20", "poly1305"}
case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
return []string{"ecdhe", "ecdsa", "chacha20", "poly1305", "sha256"} return []string{"ecdhe", "ecdsa", "chacha20", "poly1305", "sha256"}
case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:
return []string{"ecdhe", "ecdsa", "chacha20", "poly1305"}
case TLS_AES_128_GCM_SHA256: case TLS_AES_128_GCM_SHA256:
return []string{"aes", "128", "gcm", "sha256"} return []string{"aes", "128", "gcm", "sha256"}
case TLS_AES_128_GCM:
return []string{"aes", "128", "gcm"}
case TLS_AES128_GCM:
return []string{"aes128", "gcm"}
case TLS_AES_256_GCM_SHA384: case TLS_AES_256_GCM_SHA384:
return []string{"aes", "256", "gcm", "sha384"} return []string{"aes", "256", "gcm", "sha384"}
case TLS_AES_256_GCM:
return []string{"aes", "256", "gcm"}
case TLS_AES256_GCM:
return []string{"aes256", "gcm"}
case TLS_CHACHA20_POLY1305_SHA256: case TLS_CHACHA20_POLY1305_SHA256:
return []string{"chacha20", "poly1305", "sha256"} return []string{"chacha20", "poly1305", "sha256"}
case TLS_CHACHA20_POLY1305:
return []string{"chacha20", "poly1305"}
default: default:
return []string{} return []string{}
} }

View File

@@ -53,6 +53,30 @@ const (
TLS_AES_256_GCM_SHA384 = Cipher(tls.TLS_AES_256_GCM_SHA384) TLS_AES_256_GCM_SHA384 = Cipher(tls.TLS_AES_256_GCM_SHA384)
TLS_CHACHA20_POLY1305_SHA256 = Cipher(tls.TLS_CHACHA20_POLY1305_SHA256) TLS_CHACHA20_POLY1305_SHA256 = Cipher(tls.TLS_CHACHA20_POLY1305_SHA256)
) )
const (
// TLS 1.0 - 1.2 cipher suites no sha for retro compt
TLS_RSA_WITH_AES_128_GCM Cipher = iota + 1
TLS_RSA_WITH_AES_256_GCM
TLS_ECDHE_RSA_WITH_AES_128_GCM
TLS_ECDHE_ECDSA_WITH_AES_128_GCM
TLS_ECDHE_RSA_WITH_AES_256_GCM
TLS_ECDHE_ECDSA_WITH_AES_256_GCM
TLS_RSA_WITH_AES128_GCM Cipher = iota + 1
TLS_RSA_WITH_AES256_GCM
TLS_ECDHE_RSA_WITH_AES128_GCM
TLS_ECDHE_ECDSA_WITH_AES128_GCM
TLS_ECDHE_RSA_WITH_AES256_GCM
TLS_ECDHE_ECDSA_WITH_AES256_GCM
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
// TLS 1.3 cipher suites retro compat
TLS_AES_128_GCM
TLS_AES_256_GCM
TLS_AES128_GCM
TLS_AES256_GCM
TLS_CHACHA20_POLY1305
)
func List() []Cipher { func List() []Cipher {
return []Cipher{ return []Cipher{
@@ -113,6 +137,47 @@ func Parse(s string) Cipher {
return TLS_AES_128_GCM_SHA256 return TLS_AES_128_GCM_SHA256
case containString(p, TLS_AES_256_GCM_SHA384.Code()): case containString(p, TLS_AES_256_GCM_SHA384.Code()):
return TLS_AES_256_GCM_SHA384 return TLS_AES_256_GCM_SHA384
// retro compat
case containString(p, TLS_ECDHE_RSA_WITH_AES_128_GCM.Code()):
return TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
case containString(p, TLS_ECDHE_ECDSA_WITH_AES_128_GCM.Code()):
return TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
case containString(p, TLS_ECDHE_RSA_WITH_AES_256_GCM.Code()):
return TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
case containString(p, TLS_ECDHE_ECDSA_WITH_AES_256_GCM.Code()):
return TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
case containString(p, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305.Code()):
return TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
case containString(p, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305.Code()):
return TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
case containString(p, TLS_CHACHA20_POLY1305.Code()):
return TLS_CHACHA20_POLY1305_SHA256
case containString(p, TLS_RSA_WITH_AES_128_GCM.Code()):
return TLS_RSA_WITH_AES_128_GCM_SHA256
case containString(p, TLS_RSA_WITH_AES_256_GCM.Code()):
return TLS_RSA_WITH_AES_256_GCM_SHA384
case containString(p, TLS_AES_128_GCM.Code()):
return TLS_AES_128_GCM_SHA256
case containString(p, TLS_AES_256_GCM.Code()):
return TLS_AES_256_GCM_SHA384
case containString(p, TLS_ECDHE_RSA_WITH_AES128_GCM.Code()):
return TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
case containString(p, TLS_ECDHE_ECDSA_WITH_AES128_GCM.Code()):
return TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
case containString(p, TLS_ECDHE_RSA_WITH_AES256_GCM.Code()):
return TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
case containString(p, TLS_ECDHE_ECDSA_WITH_AES256_GCM.Code()):
return TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
case containString(p, TLS_RSA_WITH_AES128_GCM.Code()):
return TLS_RSA_WITH_AES_128_GCM_SHA256
case containString(p, TLS_RSA_WITH_AES256_GCM.Code()):
return TLS_RSA_WITH_AES_256_GCM_SHA384
case containString(p, TLS_AES128_GCM.Code()):
return TLS_AES_128_GCM_SHA256
case containString(p, TLS_AES256_GCM.Code()):
return TLS_AES_256_GCM_SHA384
// not found
default: default:
return Unknown return Unknown
} }

View File

@@ -32,6 +32,35 @@ import (
libmap "github.com/mitchellh/mapstructure" libmap "github.com/mitchellh/mapstructure"
) )
func (v Cipher) Check() bool {
switch v {
case TLS_RSA_WITH_AES_128_GCM_SHA256:
return true
case TLS_RSA_WITH_AES_256_GCM_SHA384:
return true
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
return true
case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
return true
case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
return true
case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
return true
case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
return true
case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
return true
case TLS_AES_128_GCM_SHA256:
return true
case TLS_AES_256_GCM_SHA384:
return true
case TLS_CHACHA20_POLY1305_SHA256:
return true
default:
return false
}
}
func ViperDecoderHook() libmap.DecodeHookFuncType { func ViperDecoderHook() libmap.DecodeHookFuncType {
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) { return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
var ( var (

143
certificates/config_old.go Normal file
View File

@@ -0,0 +1,143 @@
/*
* 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 certificates
import (
tlsaut "github.com/nabbar/golib/certificates/auth"
tlscas "github.com/nabbar/golib/certificates/ca"
tlscrt "github.com/nabbar/golib/certificates/certs"
tlscpr "github.com/nabbar/golib/certificates/cipher"
tlscrv "github.com/nabbar/golib/certificates/curves"
tlsvrs "github.com/nabbar/golib/certificates/tlsversion"
)
type CertifOld struct {
Key string `mapstructure:"key" json:"key" yaml:"key" toml:"key"`
Pem string `mapstructure:"pem" json:"pem" yaml:"pem" toml:"pem"`
}
type ConfigOld struct {
CurveList []string `mapstructure:"curveList" json:"curveList" yaml:"curveList" toml:"curveList"`
CipherList []string `mapstructure:"cipherList" json:"cipherList" yaml:"cipherList" toml:"cipherList"`
RootCAString []string `mapstructure:"rootCA" json:"rootCA" yaml:"rootCA" toml:"rootCA"`
RootCAFile []string `mapstructure:"rootCAFiles" json:"rootCAFiles" yaml:"rootCAFiles" toml:"rootCAFiles"`
ClientCAString []string `mapstructure:"clientCA" json:"clientCA" yaml:"clientCA" toml:"clientCA"`
ClientCAFiles []string `mapstructure:"clientCAFiles" json:"clientCAFiles" yaml:"clientCAFiles" toml:"clientCAFiles"`
CertPairString []CertifOld `mapstructure:"certPair" json:"certPair" yaml:"certPair" toml:"certPair"`
CertPairFile []CertifOld `mapstructure:"certPairFiles" json:"certPairFiles" yaml:"certPairFiles" toml:"certPairFiles"`
VersionMin string `mapstructure:"versionMin" json:"versionMin" yaml:"versionMin" toml:"versionMin"`
VersionMax string `mapstructure:"versionMax" json:"versionMax" yaml:"versionMax" toml:"versionMax"`
AuthClient string `mapstructure:"authClient" json:"authClient" yaml:"authClient" toml:"authClient"`
InheritDefault bool `mapstructure:"inheritDefault" json:"inheritDefault" yaml:"inheritDefault" toml:"inheritDefault"`
DynamicSizingDisable bool `mapstructure:"dynamicSizingDisable" json:"dynamicSizingDisable" yaml:"dynamicSizingDisable" toml:"dynamicSizingDisable"`
SessionTicketDisable bool `mapstructure:"sessionTicketDisable" json:"sessionTicketDisable" yaml:"sessionTicketDisable" toml:"sessionTicketDisable"`
}
func (c *ConfigOld) ToConfig() Config {
var car tlscas.Cert
for _, v := range c.RootCAString {
if car == nil {
if i, e := tlscas.Parse(v); e == nil {
car = i
}
} else {
_ = car.AppendString(v)
}
}
for _, v := range c.RootCAFile {
if car == nil {
if i, e := tlscas.Parse(v); e == nil {
car = i
}
} else {
_ = car.AppendString(v)
}
}
var cac tlscas.Cert
for _, v := range c.ClientCAFiles {
if cac == nil {
if i, e := tlscas.Parse(v); e == nil {
cac = i
}
} else {
_ = cac.AppendString(v)
}
}
for _, v := range c.ClientCAString {
if cac == nil {
if i, e := tlscas.Parse(v); e == nil {
cac = i
}
} else {
_ = cac.AppendString(v)
}
}
var crt = make([]tlscrt.Certif, 0)
for _, v := range c.CertPairFile {
if i, e := tlscrt.ParsePair(v.Key, v.Pem); e == nil {
crt = append(crt, i.Model())
}
}
for _, v := range c.CertPairString {
if i, e := tlscrt.ParsePair(v.Key, v.Pem); e == nil {
crt = append(crt, i.Model())
}
}
cip := make([]tlscpr.Cipher, 0)
for _, v := range c.CipherList {
if i := tlscpr.Parse(v); i.Check() {
cip = append(cip, i)
}
}
crv := make([]tlscrv.Curves, 0)
for _, v := range c.CurveList {
if i := tlscrv.Parse(v); i.Check() {
crv = append(crv, i)
}
}
return Config{
CurveList: crv,
CipherList: cip,
RootCA: append(make([]tlscas.Cert, 0), car),
ClientCA: append(make([]tlscas.Cert, 0), cac),
Certs: crt,
VersionMin: tlsvrs.Parse(c.VersionMin),
VersionMax: tlsvrs.Parse(c.VersionMax),
AuthClient: tlsaut.Parse(c.AuthClient),
InheritDefault: c.InheritDefault,
DynamicSizingDisable: c.DynamicSizingDisable,
SessionTicketDisable: c.SessionTicketDisable,
}
}

View File

@@ -32,6 +32,21 @@ import (
libmap "github.com/mitchellh/mapstructure" libmap "github.com/mitchellh/mapstructure"
) )
func (v Curves) Check() bool {
switch v {
case X25519:
return true
case P256:
return true
case P384:
return true
case P521:
return true
default:
return false
}
}
func ViperDecoderHook() libmap.DecodeHookFuncType { func ViperDecoderHook() libmap.DecodeHookFuncType {
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) { return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
var ( var (

View File

@@ -43,10 +43,12 @@ import (
type FctHttpClient func(def TLSConfig, servername string) *http.Client type FctHttpClient func(def TLSConfig, servername string) *http.Client
type FctTLSDefault func() TLSConfig type FctTLSDefault func() TLSConfig
type FctRootCA func() []string type FctRootCA func() []string
type FctRootCACert func() tlscas.Cert
type TLSConfig interface { type TLSConfig interface {
RegisterRand(rand io.Reader) RegisterRand(rand io.Reader)
AddRootCA(rootCA tlscas.Cert) bool
AddRootCAString(rootCA string) bool AddRootCAString(rootCA string) bool
AddRootCAFile(pemFile string) error AddRootCAFile(pemFile string) error
GetRootCA() []tlscas.Cert GetRootCA() []tlscas.Cert

View File

@@ -50,6 +50,15 @@ func (o *config) GetRootCAPool() *x509.CertPool {
return res return res
} }
func (o *config) AddRootCA(rootCA tlscas.Cert) bool {
if rootCA != nil && rootCA.Len() > 0 {
o.caRoot = append(o.caRoot, rootCA)
return true
}
return false
}
func (o *config) AddRootCAString(rootCA string) bool { func (o *config) AddRootCAString(rootCA string) bool {
if rootCA != "" { if rootCA != "" {
if c, e := tlscas.Parse(rootCA); e == nil { if c, e := tlscas.Parse(rootCA); e == nil {

View File

@@ -32,6 +32,21 @@ import (
libmap "github.com/mitchellh/mapstructure" libmap "github.com/mitchellh/mapstructure"
) )
func (v Version) Check() bool {
switch v {
case VersionTLS10:
return true
case VersionTLS11:
return true
case VersionTLS12:
return true
case VersionTLS13:
return true
default:
return false
}
}
func ViperDecoderHook() libmap.DecodeHookFuncType { func ViperDecoderHook() libmap.DecodeHookFuncType {
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) { return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
var ( var (

View File

@@ -35,6 +35,14 @@ import (
htcdns "github.com/nabbar/golib/httpcli/dns-mapper" htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
) )
func (o *componentHttpClient) Close() error {
if d := o.getDNSMapper(); d != nil {
return d.Close()
}
return nil
}
func (o *componentHttpClient) Add(from string, to string) { func (o *componentHttpClient) Add(from string, to string) {
if d := o.getDNSMapper(); d != nil { if d := o.getDNSMapper(); d != nil {
d.Add(from, to) d.Add(from, to)

View File

@@ -29,7 +29,9 @@ package httpcli
import ( import (
"sync/atomic" "sync/atomic"
libatm "github.com/nabbar/golib/atomic"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
tlscas "github.com/nabbar/golib/certificates/ca"
libcfg "github.com/nabbar/golib/config" libcfg "github.com/nabbar/golib/config"
cfgtps "github.com/nabbar/golib/config/types" cfgtps "github.com/nabbar/golib/config/types"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
@@ -46,19 +48,33 @@ type ComponentHTTPClient interface {
SetFuncMessage(f htcdns.FuncMessage) SetFuncMessage(f htcdns.FuncMessage)
} }
func New(ctx libctx.FuncContext, defCARoot libtls.FctRootCA, isDeftHTTPClient bool, msg htcdns.FuncMessage) ComponentHTTPClient { func GetRootCaCert(fct libtls.FctRootCA) tlscas.Cert {
var res tlscas.Cert
for _, c := range fct() {
if res == nil {
res, _ = tlscas.Parse(c)
} else {
_ = res.AppendString(c)
}
}
return res
}
func New(ctx libctx.FuncContext, defCARoot libtls.FctRootCACert, isDeftHTTPClient bool, msg htcdns.FuncMessage) ComponentHTTPClient {
c := &componentHttpClient{ c := &componentHttpClient{
x: libctx.NewConfig[uint8](ctx), x: libctx.NewConfig[uint8](ctx),
c: new(atomic.Value), c: libatm.NewValue[*htcdns.Config](),
d: new(atomic.Value), d: libatm.NewValue[htcdns.DNSMapper](),
f: new(atomic.Value), f: libatm.NewValue[libtls.FctRootCACert](),
m: libatm.NewValue[htcdns.FuncMessage](),
s: new(atomic.Bool), s: new(atomic.Bool),
m: new(atomic.Value),
} }
if defCARoot == nil { if defCARoot == nil {
defCARoot = func() []string { defCARoot = func() tlscas.Cert {
return make([]string, 0) return nil
} }
} }
@@ -77,7 +93,7 @@ func Register(cfg libcfg.Config, key string, cpt ComponentHTTPClient) {
cfg.ComponentSet(key, cpt) cfg.ComponentSet(key, cpt)
} }
func RegisterNew(ctx libctx.FuncContext, cfg libcfg.Config, key string, defCARoot libtls.FctRootCA, isDeftHTTPClient bool, msg htcdns.FuncMessage) { func RegisterNew(ctx libctx.FuncContext, cfg libcfg.Config, key string, defCARoot libtls.FctRootCACert, isDeftHTTPClient bool, msg htcdns.FuncMessage) {
cfg.ComponentSet(key, New(ctx, defCARoot, isDeftHTTPClient, msg)) cfg.ComponentSet(key, New(ctx, defCARoot, isDeftHTTPClient, msg))
} }

View File

@@ -29,7 +29,9 @@ package httpcli
import ( import (
"sync/atomic" "sync/atomic"
libatm "github.com/nabbar/golib/atomic"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
tlscas "github.com/nabbar/golib/certificates/ca"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
libhtc "github.com/nabbar/golib/httpcli" libhtc "github.com/nabbar/golib/httpcli"
htcdns "github.com/nabbar/golib/httpcli/dns-mapper" htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
@@ -37,32 +39,30 @@ import (
type componentHttpClient struct { type componentHttpClient struct {
x libctx.Config[uint8] x libctx.Config[uint8]
c *atomic.Value // htcdns.Config
d *atomic.Value // htcdns.DNSMapper c libatm.Value[*htcdns.Config] // htcdns.Config
f *atomic.Value // FuncDefaultCARoot d libatm.Value[htcdns.DNSMapper] // htcdns.DNSMapper
s *atomic.Bool // is Default at start / update f libatm.Value[libtls.FctRootCACert] // FuncDefaultCARoot
m *atomic.Value // htcdns.FctMessage m libatm.Value[htcdns.FuncMessage] // htcdns.FctMessage
s *atomic.Bool // is Default at start / update
} }
func (o *componentHttpClient) getRootCA() []string { func (o *componentHttpClient) getRootCA() tlscas.Cert {
if i := o.f.Load(); i == nil { if i := o.f.Load(); i == nil {
return make([]string, 0) return nil
} else if v, k := i.(libtls.FctRootCA); !k { } else if v := i(); v != nil && v.Len() < 1 {
return make([]string, 0) return nil
} else if r := v(); len(r) < 1 {
return make([]string, 0)
} else { } else {
return r return v
} }
} }
func (o *componentHttpClient) getMessage() htcdns.FuncMessage { func (o *componentHttpClient) getMessage() htcdns.FuncMessage {
if i := o.m.Load(); i == nil { if i := o.m.Load(); i == nil {
return nil return nil
} else if v, k := i.(htcdns.FuncMessage); !k {
return nil
} else { } else {
return v return i
} }
} }
@@ -87,18 +87,22 @@ func (o *componentHttpClient) setDNSMapper(dns htcdns.DNSMapper) {
defer o.SetDefault() defer o.SetDefault()
} }
var old htcdns.DNSMapper
if dns != nil { if dns != nil {
o.d.Store(dns) old = o.d.Swap(dns)
}
if old != nil {
_ = old.Close()
} }
} }
func (o *componentHttpClient) Config() htcdns.Config { func (o *componentHttpClient) Config() htcdns.Config {
if i := o.c.Load(); i == nil { if i := o.c.Load(); i == nil {
return htcdns.Config{} return htcdns.Config{}
} else if v, k := i.(*htcdns.Config); !k {
return htcdns.Config{}
} else { } else {
return *v return *i
} }
} }

View File

@@ -164,8 +164,8 @@ func (o *componentTls) _runCli() error {
} else if tls = cfg.New(); tls == nil { } else if tls = cfg.New(); tls == nil {
return prt.Error(fmt.Errorf("cannot use tls config for new instance")) return prt.Error(fmt.Errorf("cannot use tls config for new instance"))
} else if o.f != nil { } else if o.f != nil {
for _, s := range o.f() { if v := o.f(); v != nil && v.Len() > 0 {
tls.AddRootCAString(s) tls.AddRootCA(v)
} }
} }

View File

@@ -30,6 +30,7 @@ import (
"sync" "sync"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
tlscas "github.com/nabbar/golib/certificates/ca"
libcfg "github.com/nabbar/golib/config" libcfg "github.com/nabbar/golib/config"
cfgtps "github.com/nabbar/golib/config/types" cfgtps "github.com/nabbar/golib/config/types"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
@@ -42,7 +43,21 @@ type ComponentTlS interface {
SetTLS(tls libtls.TLSConfig) SetTLS(tls libtls.TLSConfig)
} }
func New(ctx libctx.FuncContext, defCARoot libtls.FctRootCA) ComponentTlS { func GetRootCaCert(fct libtls.FctRootCA) tlscas.Cert {
var res tlscas.Cert
for _, c := range fct() {
if res == nil {
res, _ = tlscas.Parse(c)
} else {
_ = res.AppendString(c)
}
}
return res
}
func New(ctx libctx.FuncContext, defCARoot libtls.FctRootCACert) ComponentTlS {
return &componentTls{ return &componentTls{
m: sync.RWMutex{}, m: sync.RWMutex{},
x: libctx.NewConfig[uint8](ctx), x: libctx.NewConfig[uint8](ctx),
@@ -56,7 +71,7 @@ func Register(cfg libcfg.Config, key string, cpt ComponentTlS) {
cfg.ComponentSet(key, cpt) cfg.ComponentSet(key, cpt)
} }
func RegisterNew(ctx libctx.FuncContext, cfg libcfg.Config, key string, defCARoot libtls.FctRootCA) { func RegisterNew(ctx libctx.FuncContext, cfg libcfg.Config, key string, defCARoot libtls.FctRootCACert) {
cfg.ComponentSet(key, New(ctx, defCARoot)) cfg.ComponentSet(key, New(ctx, defCARoot))
} }

View File

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

106
go.mod
View File

@@ -6,20 +6,20 @@ toolchain go1.23.3
require ( require (
github.com/aws/aws-sdk-go v1.55.5 github.com/aws/aws-sdk-go v1.55.5
github.com/aws/aws-sdk-go-v2 v1.32.5 github.com/aws/aws-sdk-go-v2 v1.32.7
github.com/aws/aws-sdk-go-v2/config v1.28.5 github.com/aws/aws-sdk-go-v2/config v1.28.7
github.com/aws/aws-sdk-go-v2/credentials v1.17.46 github.com/aws/aws-sdk-go-v2/credentials v1.17.48
github.com/aws/aws-sdk-go-v2/service/iam v1.38.1 github.com/aws/aws-sdk-go-v2/service/iam v1.38.3
github.com/aws/aws-sdk-go-v2/service/s3 v1.69.0 github.com/aws/aws-sdk-go-v2/service/s3 v1.72.0
github.com/aws/smithy-go v1.22.1 github.com/aws/smithy-go v1.22.1
github.com/bits-and-blooms/bitset v1.17.0 github.com/bits-and-blooms/bitset v1.20.0
github.com/c-bata/go-prompt v0.2.6 github.com/c-bata/go-prompt v0.2.6
github.com/dsnet/compress v0.0.1 github.com/dsnet/compress v0.0.1
github.com/fatih/color v1.18.0 github.com/fatih/color v1.18.0
github.com/fsnotify/fsnotify v1.8.0 github.com/fsnotify/fsnotify v1.8.0
github.com/fxamacker/cbor/v2 v2.7.0 github.com/fxamacker/cbor/v2 v2.7.0
github.com/gin-gonic/gin v1.10.0 github.com/gin-gonic/gin v1.10.0
github.com/go-ldap/ldap/v3 v3.4.8 github.com/go-ldap/ldap/v3 v3.4.10
github.com/go-playground/validator/v10 v10.23.0 github.com/go-playground/validator/v10 v10.23.0
github.com/google/go-github/v33 v33.0.0 github.com/google/go-github/v33 v33.0.0
github.com/hashicorp/go-hclog v1.6.3 github.com/hashicorp/go-hclog v1.6.3
@@ -31,13 +31,14 @@ require (
github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-colorable v0.1.13
github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/nats-io/jwt/v2 v2.7.2 github.com/nats-io/jwt/v2 v2.7.3
github.com/nats-io/nats-server/v2 v2.10.22 github.com/nats-io/nats-server/v2 v2.10.24
github.com/nats-io/nats.go v1.37.0 github.com/nats-io/nats.go v1.38.0
github.com/onsi/ginkgo/v2 v2.22.0 github.com/onsi/ginkgo/v2 v2.22.2
github.com/onsi/gomega v1.36.0 github.com/onsi/gomega v1.36.2
github.com/pelletier/go-toml v1.9.5 github.com/pelletier/go-toml v1.9.5
github.com/pierrec/lz4/v4 v4.1.21 github.com/pelletier/go-toml/v2 v2.2.3
github.com/pierrec/lz4/v4 v4.1.22
github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_golang v1.20.5
github.com/shirou/gopsutil v3.21.11+incompatible github.com/shirou/gopsutil v3.21.11+incompatible
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
@@ -47,18 +48,18 @@ require (
github.com/ugorji/go/codec v1.2.12 github.com/ugorji/go/codec v1.2.12
github.com/ulikunitz/xz v0.5.12 github.com/ulikunitz/xz v0.5.12
github.com/vbauerster/mpb/v8 v8.8.3 github.com/vbauerster/mpb/v8 v8.8.3
github.com/xanzy/go-gitlab v0.114.0 github.com/xanzy/go-gitlab v0.115.0
github.com/xhit/go-simple-mail v2.2.2+incompatible github.com/xhit/go-simple-mail v2.2.2+incompatible
golang.org/x/net v0.31.0 golang.org/x/net v0.33.0
golang.org/x/oauth2 v0.24.0 golang.org/x/oauth2 v0.25.0
golang.org/x/sync v0.9.0 golang.org/x/sync v0.10.0
golang.org/x/sys v0.27.0 golang.org/x/sys v0.29.0
golang.org/x/term v0.26.0 golang.org/x/term v0.28.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/clickhouse v0.6.1 gorm.io/driver/clickhouse v0.6.1
gorm.io/driver/mysql v1.5.7 gorm.io/driver/mysql v1.5.7
gorm.io/driver/postgres v1.5.10 gorm.io/driver/postgres v1.5.11
gorm.io/driver/sqlite v1.5.6 gorm.io/driver/sqlite v1.5.7
gorm.io/driver/sqlserver v1.5.4 gorm.io/driver/sqlserver v1.5.4
gorm.io/gorm v1.25.12 gorm.io/gorm v1.25.12
) )
@@ -71,32 +72,32 @@ require (
github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect
github.com/PuerkitoBio/goquery v1.10.0 // indirect github.com/PuerkitoBio/goquery v1.10.1 // indirect
github.com/VividCortex/ewma v1.2.0 // indirect github.com/VividCortex/ewma v1.2.0 // indirect
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
github.com/andybalholm/brotli v1.1.1 // indirect github.com/andybalholm/brotli v1.1.1 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.24 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.26 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.12.5 // indirect github.com/bytedance/sonic v1.12.6 // indirect
github.com/bytedance/sonic/loader v0.2.1 // indirect github.com/bytedance/sonic/loader v0.2.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.7 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v1.0.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
github.com/go-faster/city v1.0.1 // indirect github.com/go-faster/city v1.0.1 // indirect
github.com/go-faster/errors v0.7.1 // indirect github.com/go-faster/errors v0.7.1 // indirect
@@ -106,12 +107,12 @@ require (
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/goccy/go-json v0.10.3 // indirect github.com/goccy/go-json v0.10.4 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/pprof v0.0.0-20241122213907-cbe949e5a41b // indirect github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/css v1.0.1 // indirect github.com/gorilla/css v1.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
@@ -123,7 +124,7 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.1 // indirect github.com/jackc/pgx/v5 v5.7.2 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 // indirect github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
@@ -133,23 +134,22 @@ require (
github.com/klauspost/compress v1.17.11 // indirect github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/leodido/go-urn v1.4.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/magiconair/properties v1.8.9 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-sqlite3 v1.14.24 // indirect github.com/mattn/go-sqlite3 v1.14.24 // indirect
github.com/mattn/go-tty v0.0.7 // indirect github.com/mattn/go-tty v0.0.7 // indirect
github.com/microsoft/go-mssqldb v1.7.2 // indirect github.com/microsoft/go-mssqldb v1.8.0 // indirect
github.com/minio/highwayhash v1.0.3 // indirect github.com/minio/highwayhash v1.0.3 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nats-io/nkeys v0.4.8 // indirect github.com/nats-io/nkeys v0.4.9 // indirect
github.com/nats-io/nuid v1.0.1 // indirect github.com/nats-io/nuid v1.0.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/paulmach/orb v0.11.1 // indirect github.com/paulmach/orb v0.11.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/term v1.2.0-beta.2 // indirect github.com/pkg/term v1.2.0-beta.2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect
@@ -163,7 +163,7 @@ require (
github.com/shopspring/decimal v1.4.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/subosito/gotenv v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect
@@ -172,15 +172,15 @@ require (
github.com/vanng822/go-premailer v1.22.0 // indirect github.com/vanng822/go-premailer v1.22.0 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.opentelemetry.io/otel v1.32.0 // indirect go.opentelemetry.io/otel v1.33.0 // indirect
go.opentelemetry.io/otel/trace v1.32.0 // indirect go.opentelemetry.io/otel/trace v1.33.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.12.0 // indirect golang.org/x/arch v0.13.0 // indirect
golang.org/x/crypto v0.29.0 // indirect golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 // indirect
golang.org/x/text v0.20.0 // indirect golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.8.0 // indirect golang.org/x/time v0.9.0 // indirect
golang.org/x/tools v0.27.0 // indirect golang.org/x/tools v0.28.0 // indirect
google.golang.org/protobuf v1.35.2 // indirect google.golang.org/protobuf v1.36.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
) )

View File

@@ -29,9 +29,9 @@ package httpcli
import ( import (
"context" "context"
"net/http" "net/http"
"sync/atomic"
"time" "time"
libatm "github.com/nabbar/golib/atomic"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
libdur "github.com/nabbar/golib/duration" libdur "github.com/nabbar/golib/duration"
htcdns "github.com/nabbar/golib/httpcli/dns-mapper" htcdns "github.com/nabbar/golib/httpcli/dns-mapper"
@@ -41,20 +41,10 @@ const (
ClientTimeout5Sec = 5 * time.Second ClientTimeout5Sec = 5 * time.Second
) )
var ( var dns = libatm.NewValue[htcdns.DNSMapper]()
dns = new(atomic.Value)
ctx context.Context
cnl context.CancelFunc
)
func initDNSMapper() htcdns.DNSMapper { func initDNSMapper() htcdns.DNSMapper {
if cnl != nil { return htcdns.New(context.Background(), &htcdns.Config{
cnl()
}
ctx, cnl = context.WithCancel(context.Background())
return htcdns.New(ctx, &htcdns.Config{
DNSMapper: make(map[string]string), DNSMapper: make(map[string]string),
TimerClean: libdur.ParseDuration(3 * time.Minute), TimerClean: libdur.ParseDuration(3 * time.Minute),
Transport: htcdns.TransportConfig{ Transport: htcdns.TransportConfig{
@@ -77,17 +67,11 @@ func initDNSMapper() htcdns.DNSMapper {
} }
func DefaultDNSMapper() htcdns.DNSMapper { func DefaultDNSMapper() htcdns.DNSMapper {
if i := dns.Load(); i == nil { if dns.Load() == nil {
d := initDNSMapper() SetDefaultDNSMapper(initDNSMapper())
dns.Store(d)
return d
} else if d, k := i.(htcdns.DNSMapper); !k {
d = initDNSMapper()
dns.Store(d)
return d
} else {
return d
} }
return dns.Load()
} }
func SetDefaultDNSMapper(d htcdns.DNSMapper) { func SetDefaultDNSMapper(d htcdns.DNSMapper) {
@@ -95,11 +79,9 @@ func SetDefaultDNSMapper(d htcdns.DNSMapper) {
return return
} }
if cnl != nil { if o := dns.Swap(d); o != nil {
cnl() _ = o.Close()
} }
dns.Store(d)
} }
type FctHttpClient func() *http.Client type FctHttpClient func() *http.Client

View File

@@ -121,6 +121,6 @@ func (o Config) Validate() liberr.Error {
return e return e
} }
func (o Config) New(ctx context.Context, fct libtls.FctRootCA, msg FuncMessage) DNSMapper { func (o Config) New(ctx context.Context, fct libtls.FctRootCACert, msg FuncMessage) DNSMapper {
return New(ctx, &o, fct, msg) return New(ctx, &o, fct, msg)
} }

View File

@@ -31,10 +31,11 @@ import (
"net" "net"
"net/http" "net/http"
"sync" "sync"
"sync/atomic"
"time" "time"
libatm "github.com/nabbar/golib/atomic"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
tlscas "github.com/nabbar/golib/certificates/ca"
libdur "github.com/nabbar/golib/duration" libdur "github.com/nabbar/golib/duration"
) )
@@ -58,9 +59,24 @@ type DNSMapper interface {
DefaultClient() *http.Client DefaultClient() *http.Client
TimeCleaner(ctx context.Context, dur time.Duration) TimeCleaner(ctx context.Context, dur time.Duration)
Close() error
} }
func New(ctx context.Context, cfg *Config, fct libtls.FctRootCA, msg FuncMessage) DNSMapper { func GetRootCaCert(fct libtls.FctRootCA) tlscas.Cert {
var res tlscas.Cert
for _, c := range fct() {
if res == nil {
res, _ = tlscas.Parse(c)
} else {
_ = res.AppendString(c)
}
}
return res
}
func New(ctx context.Context, cfg *Config, fct libtls.FctRootCACert, msg FuncMessage) DNSMapper {
if cfg == nil { if cfg == nil {
cfg = &Config{ cfg = &Config{
DNSMapper: make(map[string]string), DNSMapper: make(map[string]string),
@@ -73,8 +89,8 @@ func New(ctx context.Context, cfg *Config, fct libtls.FctRootCA, msg FuncMessage
} }
if fct == nil { if fct == nil {
fct = func() []string { fct = func() tlscas.Cert {
return make([]string, 0) return nil
} }
} }
@@ -85,10 +101,12 @@ func New(ctx context.Context, cfg *Config, fct libtls.FctRootCA, msg FuncMessage
d := &dmp{ d := &dmp{
d: new(sync.Map), d: new(sync.Map),
z: new(sync.Map), z: new(sync.Map),
c: new(atomic.Value), c: libatm.NewValue[*Config](),
t: new(atomic.Value), t: libatm.NewValue[*http.Transport](),
f: fct, f: fct,
i: msg, i: msg,
n: libatm.NewValue[context.CancelFunc](),
x: libatm.NewValue[context.Context](),
} }
for edp, adr := range cfg.DNSMapper { for edp, adr := range cfg.DNSMapper {

View File

@@ -28,28 +28,37 @@ package dns_mapper
import ( import (
"context" "context"
"net/http"
"sync" "sync"
"sync/atomic"
"time" "time"
libatm "github.com/nabbar/golib/atomic"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
) )
type dmp struct { type dmp struct {
d *sync.Map d *sync.Map
z *sync.Map z *sync.Map
c *atomic.Value // *Config c libatm.Value[*Config]
t *atomic.Value // *http transport t libatm.Value[*http.Transport]
f libtls.FctRootCA n libatm.Value[context.CancelFunc]
x libatm.Value[context.Context]
f libtls.FctRootCACert
i func(msg string) i func(msg string)
} }
func (o *dmp) Close() error {
if i := o.n.Swap(func() {}); i != nil {
i()
}
return nil
}
func (o *dmp) config() *Config { func (o *dmp) config() *Config {
var cfg = &Config{} var cfg = &Config{}
if i := o.c.Load(); i == nil { if c := o.c.Load(); c == nil {
return cfg
} else if c, k := i.(*Config); !k {
return cfg return cfg
} else { } else {
*cfg = *c *cfg = *c
@@ -82,20 +91,35 @@ func (o *dmp) TimeCleaner(ctx context.Context, dur time.Duration) {
dur = 5 * time.Minute dur = 5 * time.Minute
} }
var (
x context.Context
n context.CancelFunc
)
if ctx != nil {
x, n = context.WithCancel(ctx)
o.x.Store(x)
if i := o.n.Swap(n); i != nil {
i()
}
}
go func() { go func() {
var tck = time.NewTicker(dur) var (
defer tck.Stop() tk = time.NewTicker(dur)
cx = o.x.Load()
)
defer func() {
tk.Stop()
}()
for { for {
if ctx.Err() != nil {
return
}
select { select {
case <-tck.C: case <-cx.Done():
o.DefaultTransport().CloseIdleConnections()
case <-ctx.Done():
return return
case <-tk.C:
o.DefaultTransport().CloseIdleConnections()
} }
} }
}() }()

View File

@@ -87,8 +87,8 @@ func (o *dmp) Transport(cfg TransportConfig) *http.Transport {
ssl.SetVersionMax(tls.VersionTLS13) ssl.SetVersionMax(tls.VersionTLS13)
} }
for _, c := range o.f() { if v := o.f(); v != nil && v.Len() > 0 {
ssl.AddRootCAString(c) ssl.AddRootCA(v)
} }
if cfg.TimeoutGlobal == 0 { if cfg.TimeoutGlobal == 0 {
@@ -150,9 +150,7 @@ func (o *dmp) Client(cfg TransportConfig) *http.Client {
func (o *dmp) DefaultTransport() *http.Transport { func (o *dmp) DefaultTransport() *http.Transport {
i := o.t.Load() i := o.t.Load()
if i != nil { if i != nil {
if t, k := i.(*http.Transport); k { return i
return t
}
} }
t := o.Transport(o.config().Transport) t := o.Transport(o.config().Transport)

View File

@@ -28,8 +28,10 @@
package mapCloser package mapCloser
import ( import (
"context"
"io" "io"
"sync/atomic" "sync/atomic"
"time"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
) )
@@ -44,19 +46,33 @@ type Closer interface {
Close() error Close() error
} }
func New(ctx libctx.FuncContext) Closer { func New(ctx context.Context) Closer {
var (
x, n = context.WithCancel(ctx)
fx = func() context.Context {
return x
}
)
c := &closer{ c := &closer{
f: n,
i: new(atomic.Uint64), i: new(atomic.Uint64),
x: libctx.NewConfig[uint64](ctx), c: new(atomic.Bool),
x: libctx.NewConfig[uint64](fx),
} }
c.c.Store(false)
c.i.Store(0) c.i.Store(0)
go func() { go func() {
select { for !c.c.Load() {
case <-c.x.Done(): select {
_ = c.Close() case <-c.x.Done():
return _ = c.Close()
return
default:
time.Sleep(time.Millisecond * 100)
}
} }
}() }()

View File

@@ -38,6 +38,8 @@ import (
) )
type closer struct { type closer struct {
c *atomic.Bool
f func() // Context Func Cancel
i *atomic.Uint64 i *atomic.Uint64
x libctx.Config[uint64] x libctx.Config[uint64]
} }
@@ -130,7 +132,12 @@ func (o *closer) Clone() Closer {
i := new(atomic.Uint64) i := new(atomic.Uint64)
i.Store(o.idx()) i.Store(o.idx())
c := new(atomic.Bool)
c.Store(o.c.Load())
return &closer{ return &closer{
c: c,
f: o.f,
i: i, i: i,
x: o.x.Clone(nil), x: o.x.Clone(nil),
} }
@@ -141,7 +148,15 @@ func (o *closer) Close() error {
if o == nil { if o == nil {
return fmt.Errorf("not initialized") return fmt.Errorf("not initialized")
} else if o.x == nil { }
o.c.Store(true)
if o.f != nil {
defer o.f()
}
if o.x == nil {
return fmt.Errorf("not initialized") return fmt.Errorf("not initialized")
} else if o.x.Err() != nil { } else if o.x.Err() != nil {
return o.x.Err() return o.x.Err()

View File

@@ -34,8 +34,6 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
iotclo "github.com/nabbar/golib/ioutils/mapCloser"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
logcfg "github.com/nabbar/golib/logger/config" logcfg "github.com/nabbar/golib/logger/config"
logent "github.com/nabbar/golib/logger/entry" logent "github.com/nabbar/golib/logger/entry"
@@ -133,7 +131,6 @@ func New(ctx libctx.FuncContext) Logger {
c: new(atomic.Value), c: new(atomic.Value),
} }
l.c.Store(iotclo.New(ctx))
l.SetLevel(loglvl.InfoLevel) l.SetLevel(loglvl.InfoLevel)
return l return l

View File

@@ -35,21 +35,11 @@ import (
) )
func (o *logger) Close() error { func (o *logger) Close() error {
if o == nil { if o != nil && o.hasCloser() {
return nil o.switchCloser(nil)
} }
c := o.newCloser() return nil
if c == nil {
return nil
}
s := o.switchCloser(c)
if s == nil {
return nil
}
return s.Close()
} }
func (o *logger) Write(p []byte) (n int, err error) { func (o *logger) Write(p []byte) (n int, err error) {

View File

@@ -52,16 +52,31 @@ func (o *logger) getCloser() iotclo.Closer {
return c return c
} }
c := iotclo.New(o.x.GetContext) c := o.newCloser()
o.c.Store(c) o.c.Store(c)
return c return c
} }
func (o *logger) switchCloser(c iotclo.Closer) iotclo.Closer { func (o *logger) switchCloser(c iotclo.Closer) {
b := o.getCloser() if o == nil {
o.c.Store(c) return
return b } else if c == nil {
c = o.newCloser()
}
i := o.c.Swap(c)
if i == nil {
return
} else if v, k := i.(iotclo.Closer); k && v != nil {
go func() {
// temp waiting all still calling log finish
time.Sleep(10 * time.Second)
_ = v.Close()
v = nil
}()
}
} }
func (o *logger) newCloser() iotclo.Closer { func (o *logger) newCloser() iotclo.Closer {
@@ -69,7 +84,21 @@ func (o *logger) newCloser() iotclo.Closer {
return nil return nil
} }
return iotclo.New(o.x.GetContext) return iotclo.New(o.x.GetContext())
}
func (o *logger) hasCloser() bool {
if o == nil || o.x == nil {
return false
}
if i := o.c.Load(); i != nil {
if _, k := i.(iotclo.Closer); k {
return true
}
}
return false
} }
func (o *logger) Clone() Logger { func (o *logger) Clone() Logger {
@@ -222,24 +251,24 @@ func (o *logger) SetOptions(opt *logcfg.Options) error {
} }
} }
var clo = o.newCloser() if len(hkl) > 0 {
var clo = o.newCloser()
for _, h := range hkl { for _, h := range hkl {
clo.Add(h) clo.Add(h)
h.RegisterHook(obj) h.RegisterHook(obj)
go h.Run(o.x.GetContext()) go h.Run(o.x.GetContext())
}
o.switchCloser(clo)
} else if o.hasCloser() {
o.switchCloser(nil)
} }
o.x.Store(keyOptions, opt) o.x.Store(keyOptions, opt)
o.x.Store(keyLogrus, obj) o.x.Store(keyLogrus, obj)
o.runFuncUpdateLogger() o.runFuncUpdateLogger()
clo = o.switchCloser(clo)
go func(c iotclo.Closer) {
time.Sleep(3 * time.Second)
_ = c.Close()
}(clo)
return nil return nil
} }

View File

@@ -33,6 +33,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"runtime/debug"
"runtime/pprof" "runtime/pprof"
"time" "time"
@@ -132,6 +133,7 @@ func ProfilingMemRun(ctx context.Context, tck *time.Ticker) error {
}() }()
runtime.GC() runtime.GC()
debug.FreeOSMemory()
if e = pprof.WriteHeapProfile(h); e != nil { if e = pprof.WriteHeapProfile(h); e != nil {
return e return e

52
request/DoRequest.go Normal file
View File

@@ -0,0 +1,52 @@
/*
* 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 request
type DoRequestOptions struct {
Retry int
Checksum256 []byte
ValidStatusCodes []int
Model interface{}
}
func (r *request) DoParse(model interface{}, validStatus ...int) error {
return r.DoWithOptions(&DoRequestOptions{
Retry: 0,
Checksum256: nil,
ValidStatusCodes: validStatus,
Model: model,
})
}
func (r *request) DoParseRetry(retry int, model interface{}, validStatus ...int) error {
return r.DoWithOptions(&DoRequestOptions{
Retry: retry,
Checksum256: nil,
ValidStatusCodes: validStatus,
Model: model,
})
}

View File

@@ -35,8 +35,10 @@ type requestError struct {
code int code int
status string status string
statusErr bool statusErr bool
bufBody *bytes.Buffer bufBody []byte
bodyErr bool bodyErr bool
checksum []byte
isSame bool
err error err error
} }
@@ -49,7 +51,16 @@ func (r *requestError) Status() string {
} }
func (r *requestError) Body() *bytes.Buffer { func (r *requestError) Body() *bytes.Buffer {
return r.bufBody if len(r.bufBody) > 0 {
b := make([]byte, 0, len(r.bufBody))
copy(b, r.bufBody)
return bytes.NewBuffer(b)
}
return bytes.NewBuffer(make([]byte, 0))
}
func (r *requestError) CheckSum() []byte {
return r.checksum
} }
func (r *requestError) Error() error { func (r *requestError) Error() error {
@@ -68,9 +79,13 @@ func (r *requestError) IsBodyError() bool {
return r.bodyErr return r.bodyErr
} }
func (r *requestError) IsBodySame() bool {
return r.isSame
}
func (r *requestError) ParseBody(i interface{}) bool { func (r *requestError) ParseBody(i interface{}) bool {
if r.bufBody != nil && r.bufBody.Len() > 0 { if len(r.bufBody) > 0 {
if e := json.Unmarshal(r.bufBody.Bytes(), i); e == nil { if e := json.Unmarshal(r.bufBody, i); e == nil {
return true return true
} }
} }
@@ -78,13 +93,22 @@ func (r *requestError) ParseBody(i interface{}) bool {
return false return false
} }
func (r *requestError) Free() {
if len(r.bufBody) > 0 {
r.bufBody = r.bufBody[:0]
}
r.bufBody = nil
}
func (r *request) newError() { func (r *request) newError() {
r.err.Store(&requestError{ r.err.Store(&requestError{
code: 0, code: 0,
status: "", status: "",
statusErr: false, statusErr: false,
bufBody: bytes.NewBuffer(make([]byte, 0)), bufBody: nil,
bodyErr: false, bodyErr: false,
checksum: nil,
isSame: false,
err: nil, err: nil,
}) })
} }
@@ -100,8 +124,10 @@ func (r *request) getError() *requestError {
code: 0, code: 0,
status: "", status: "",
statusErr: false, statusErr: false,
bufBody: bytes.NewBuffer(make([]byte, 0)), bufBody: nil,
bodyErr: false, bodyErr: false,
checksum: nil,
isSame: false,
err: nil, err: nil,
} }
} }
@@ -112,8 +138,10 @@ func (r *request) setError(e *requestError) {
code: 0, code: 0,
status: "", status: "",
statusErr: false, statusErr: false,
bufBody: bytes.NewBuffer(make([]byte, 0)), bufBody: nil,
bodyErr: false, bodyErr: false,
checksum: nil,
isSame: false,
err: nil, err: nil,
} }
} }

View File

@@ -46,11 +46,13 @@ type Error interface {
StatusCode() int StatusCode() int
Status() string Status() string
Body() *bytes.Buffer Body() *bytes.Buffer
CheckSum() []byte
Error() error Error() error
IsError() bool IsError() bool
IsStatusError() bool IsStatusError() bool
IsBodyError() bool IsBodyError() bool
IsBodySame() bool
ParseBody(i interface{}) bool ParseBody(i interface{}) bool
} }
@@ -105,6 +107,7 @@ type Request interface {
Clone() (Request, error) Clone() (Request, error)
New() (Request, error) New() (Request, error)
Free()
GetOption() *Options GetOption() *Options
SetOption(opt *Options) error SetOption(opt *Options) error
@@ -116,7 +119,13 @@ type Request interface {
IsError() bool IsError() bool
Do() (*http.Response, error) Do() (*http.Response, error)
DoWithOptions(opt *DoRequestOptions) error
// DoParse
//Deprecated: use DoWithOptions instead of DoParse
DoParse(model interface{}, validStatus ...int) error DoParse(model interface{}, validStatus ...int) error
// DoParseRetry
//Deprecated: use DoWithOptions instead of DoParseRetry
DoParseRetry(retry int, model interface{}, validStatus ...int) error DoParseRetry(retry int, model interface{}, validStatus ...int) error
Monitor(ctx context.Context, vrs libver.Version) (montps.Monitor, error) Monitor(ctx context.Context, vrs libver.Version) (montps.Monitor, error)

View File

@@ -128,6 +128,15 @@ func (r *request) New() (Request, error) {
return n, nil return n, nil
} }
func (r *request) Free() {
if i := r.err.Load(); i != nil {
if v, k := i.(*requestError); !k {
v.Free()
r.err.Store(&requestError{})
}
}
}
func (r *request) RegisterDefaultLogger(fct liblog.FuncLog) { func (r *request) RegisterDefaultLogger(fct liblog.FuncLog) {
if fct == nil { if fct == nil {
fct = func() liblog.Logger { fct = func() liblog.Logger {

View File

@@ -27,7 +27,6 @@
package request package request
import ( import (
"bytes"
"context" "context"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
@@ -76,13 +75,19 @@ func (r *request) HealthCheck(ctx context.Context) error {
} }
var ( var (
e error
err error err error
buf *bytes.Buffer buf []byte
req *http.Request req *http.Request
rsp *http.Response rsp *http.Response
) )
defer func() {
if len(buf) > 0 {
buf = buf[:0]
buf = nil
}
}()
if ent != nil { if ent != nil {
ent.FieldAdd("endpoint", ednp) ent.FieldAdd("endpoint", ednp)
ent.FieldAdd("method", http.MethodGet) ent.FieldAdd("method", http.MethodGet)
@@ -92,23 +97,23 @@ func (r *request) HealthCheck(ctx context.Context) error {
if err != nil { if err != nil {
if ent != nil { if ent != nil {
ent.ErrorAdd(true, err).Check(loglvl.NilLevel) ent.ErrorAdd(true, err).Log()
} }
return err return err
} }
rsp, e = r.client().Do(req) rsp, err = r.client().Do(req)
if e != nil { if err != nil {
err = ErrorSendRequest.Error(e) err = ErrorSendRequest.Error(err)
if ent != nil { if ent != nil {
ent.ErrorAdd(true, err).Check(loglvl.NilLevel) ent.ErrorAdd(true, err).Log()
} }
return err return err
} }
if buf, err = r.checkResponse(rsp); err != nil { if buf, err = r.checkResponse(rsp); err != nil {
if ent != nil { if ent != nil {
ent.ErrorAdd(true, err).Check(loglvl.NilLevel) ent.ErrorAdd(true, err).Log()
} }
return err return err
} }
@@ -117,7 +122,7 @@ func (r *request) HealthCheck(ctx context.Context) error {
if !r.isValidCode(opts.Health.Result.ValidHTTPCode, rsp.StatusCode) { if !r.isValidCode(opts.Health.Result.ValidHTTPCode, rsp.StatusCode) {
err = ErrorResponseStatus.Error(fmt.Errorf("status: %s", rsp.Status)) err = ErrorResponseStatus.Error(fmt.Errorf("status: %s", rsp.Status))
if ent != nil { if ent != nil {
ent.ErrorAdd(true, err).Check(loglvl.NilLevel) ent.ErrorAdd(true, err).Log()
} }
return err return err
} }
@@ -125,7 +130,7 @@ func (r *request) HealthCheck(ctx context.Context) error {
if r.isValidCode(opts.Health.Result.InvalidHTTPCode, rsp.StatusCode) { if r.isValidCode(opts.Health.Result.InvalidHTTPCode, rsp.StatusCode) {
err = ErrorResponseStatus.Error(fmt.Errorf("status: %s", rsp.Status)) err = ErrorResponseStatus.Error(fmt.Errorf("status: %s", rsp.Status))
if ent != nil { if ent != nil {
ent.ErrorAdd(true, err).Check(loglvl.NilLevel) ent.ErrorAdd(true, err).Log()
} }
return err return err
} }
@@ -135,7 +140,7 @@ func (r *request) HealthCheck(ctx context.Context) error {
if !r.isValidContents(opts.Health.Result.Contain, buf) { if !r.isValidContents(opts.Health.Result.Contain, buf) {
err = ErrorResponseContainsNotFound.Error(nil) err = ErrorResponseContainsNotFound.Error(nil)
if ent != nil { if ent != nil {
ent.ErrorAdd(true, err).Check(loglvl.NilLevel) ent.ErrorAdd(true, err).Log()
} }
return err return err
} }
@@ -143,7 +148,7 @@ func (r *request) HealthCheck(ctx context.Context) error {
if r.isValidContents(opts.Health.Result.NotContain, buf) { if r.isValidContents(opts.Health.Result.NotContain, buf) {
err = ErrorResponseNotContainsFound.Error(nil) err = ErrorResponseNotContainsFound.Error(nil)
if ent != nil { if ent != nil {
ent.ErrorAdd(true, err).Check(loglvl.NilLevel) ent.ErrorAdd(true, err).Log()
} }
return err return err
} }

View File

@@ -29,11 +29,11 @@ package request
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/sha256"
"encoding/json" "encoding/json"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"strings"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
) )
@@ -67,10 +67,10 @@ func (r *request) makeRequest(ctx context.Context, u *url.URL, mtd string, body
return req, nil return req, nil
} }
func (r *request) checkResponse(rsp *http.Response, validStatus ...int) (*bytes.Buffer, error) { func (r *request) checkResponse(rsp *http.Response, validStatus ...int) ([]byte, error) {
var ( var (
e error e error
b = bytes.NewBuffer(make([]byte, 0)) b []byte
) )
defer func() { defer func() {
@@ -80,11 +80,11 @@ func (r *request) checkResponse(rsp *http.Response, validStatus ...int) (*bytes.
}() }()
if rsp == nil { if rsp == nil {
return b, ErrorResponseInvalid.Error(nil) return nil, ErrorResponseInvalid.Error(nil)
} }
if rsp.Body != nil { if rsp.Body != nil {
if _, e = io.Copy(b, rsp.Body); e != nil { if b, e = io.ReadAll(rsp.Body); e != nil {
return b, ErrorResponseLoadBody.Error(e) return b, ErrorResponseLoadBody.Error(e)
} }
} }
@@ -110,15 +110,15 @@ func (r *request) isValidCode(listValid []int, statusCode int) bool {
return false return false
} }
func (r *request) isValidContents(contains []string, buf *bytes.Buffer) bool { func (r *request) isValidContents(contains []string, buf []byte) bool {
if len(contains) < 1 { if len(contains) < 1 {
return true return true
} else if buf.Len() < 1 { } else if len(buf) < 1 {
return false return false
} }
for _, c := range contains { for _, c := range contains {
if strings.Contains(buf.String(), c) { if bytes.Contains(buf, []byte(c)) {
return true return true
} }
} }
@@ -135,7 +135,6 @@ func (r *request) Do() (*http.Response, error) {
} }
var ( var (
e error
req *http.Request req *http.Request
rer *requestError rer *requestError
rsp *http.Response rsp *http.Response
@@ -153,22 +152,19 @@ func (r *request) Do() (*http.Response, error) {
return nil, ErrorCreateRequest.Error(err) return nil, ErrorCreateRequest.Error(err)
} }
rsp, e = r.client().Do(req) rsp, err = r.client().Do(req)
if e != nil { if err != nil {
rer.err = e rer.err = err
r.setError(rer) r.setError(rer)
return nil, ErrorSendRequest.Error(e) return nil, ErrorSendRequest.Error(err)
} }
return rsp, nil return rsp, nil
} }
func (r *request) DoParse(model interface{}, validStatus ...int) error { func (r *request) doParse(opt *DoRequestOptions) error {
var ( var (
e error
b = bytes.NewBuffer(make([]byte, 0))
err error err error
rsp *http.Response rsp *http.Response
rer *requestError rer *requestError
@@ -184,10 +180,9 @@ func (r *request) DoParse(model interface{}, validStatus ...int) error {
rer.status = rsp.Status rer.status = rsp.Status
} }
b, err = r.checkResponse(rsp, validStatus...) rer.bufBody, err = r.checkResponse(rsp, opt.ValidStatusCodes...)
rer.bufBody = b
if er := liberr.Get(err); er != nil && er.HasCode(ErrorResponseStatus) { if liberr.Has(err, ErrorResponseStatus) {
rer.statusErr = true rer.statusErr = true
} else if err != nil { } else if err != nil {
rer.err = err rer.err = err
@@ -195,23 +190,39 @@ func (r *request) DoParse(model interface{}, validStatus ...int) error {
return err return err
} }
if b.Len() > 0 { if len(rer.bufBody) > 0 {
if e = json.Unmarshal(b.Bytes(), model); e != nil { v := sha256.Sum256(rer.bufBody)
rer.checksum = v[:]
if len(opt.Checksum256) > 0 && len(rer.checksum) > 0 {
if bytes.Equal(rer.CheckSum(), opt.Checksum256) {
rer.isSame = true
return nil
}
}
if err = json.Unmarshal(rer.bufBody, opt.Model); err != nil {
rer.bodyErr = true rer.bodyErr = true
rer.err = e rer.err = err
r.setError(rer) r.setError(rer)
return ErrorResponseUnmarshall.Error(e) return ErrorResponseUnmarshall.Error(err)
} }
} }
return nil return nil
} }
func (r *request) DoParseRetry(retry int, model interface{}, validStatus ...int) error { func (r *request) DoWithOptions(opt *DoRequestOptions) error {
var e error var (
e error
)
for i := 0; i < retry; i++ { if opt.Retry < 1 {
if e = r.DoParse(model, validStatus...); e != nil { opt.Retry = 1
}
for i := 0; i < opt.Retry; i++ {
if e = r.doParse(opt); e != nil {
continue continue
} else if r.IsError() { } else if r.IsError() {
continue continue

View File

@@ -64,15 +64,15 @@ type Test struct {
} }
type Standard struct { type Standard struct {
A int `json:"a" yaml:"a" toml:"a"` A int `json:"a" yaml:"a" toml:"a"`
b int b int
C string `json:"C" yaml:"C" toml:"C"` C string `json:"C" yaml:"C" toml:"C"`
D []string `json:"d" yaml:"d" toml:"d"` D []string `json:"d" yaml:"d" toml:"d"`
} }
type Address struct { type Address struct {
Street string `json:"street" ` Street string `json:"street" `
City string `json:"city,omitempty"` City string `json:"city,omitempty"`
} }
type Status int type Status int

View File

@@ -49,6 +49,6 @@ type ServerConfig struct {
// New returns a new server with the given handler and based on the ServerConfig // New returns a new server with the given handler and based on the ServerConfig
// handler libsck.Handler // handler libsck.Handler
// (libsck.Server, error) // (libsck.Server, error)
func (o ServerConfig) New(handler libsck.Handler) (libsck.Server, error) { func (o ServerConfig) New(updateCon libsck.UpdateConn, handler libsck.Handler) (libsck.Server, error) {
return scksrv.New(handler, o.Network, o.Address, o.PermFile, o.GroupPerm) return scksrv.New(updateCon, handler, o.Network, o.Address, o.PermFile, o.GroupPerm)
} }

View File

@@ -27,8 +27,8 @@
package delim package delim
import ( import (
"bufio"
"io" "io"
"sync/atomic"
libsiz "github.com/nabbar/golib/size" libsiz "github.com/nabbar/golib/size"
) )
@@ -37,29 +37,25 @@ type BufferDelim interface {
io.ReadCloser io.ReadCloser
io.WriterTo io.WriterTo
SetDelim(d rune) Delim() rune
GetDelim() rune
SetBufferSize(b libsiz.Size)
GetBufferSize() libsiz.Size
SetInput(i io.ReadCloser)
Reader() io.ReadCloser Reader() io.ReadCloser
Copy(w io.Writer) (n int64, err error) Copy(w io.Writer) (n int64, err error)
ReadBytes() ([]byte, error) ReadBytes() ([]byte, error)
UnRead() ([]byte, error)
} }
func New(r io.ReadCloser, delim rune, sizeBufferRead libsiz.Size) BufferDelim { func New(r io.ReadCloser, delim rune, sizeBufferRead libsiz.Size) BufferDelim {
d := &dlm{ var b *bufio.Reader
i: new(atomic.Value),
d: new(atomic.Int32), if sizeBufferRead > 0 {
s: new(atomic.Uint64), b = bufio.NewReaderSize(r, sizeBufferRead.Int())
r: new(atomic.Value), } else {
b = bufio.NewReader(r)
} }
d.SetDelim(delim) return &dlm{
d.SetBufferSize(sizeBufferRead) i: r,
d.SetInput(r) r: b,
d: delim,
return d }
} }

View File

@@ -37,44 +37,67 @@ func (o *dlm) Copy(w io.Writer) (n int64, err error) {
} }
func (o *dlm) Read(p []byte) (n int, err error) { func (o *dlm) Read(p []byte) (n int, err error) {
if r := o.getReader(); r == nil { if o == nil || o.r == nil {
return 0, ErrInstance return 0, ErrInstance
} else {
b, e := r.ReadBytes(o.getDelimByte())
if len(b) > 0 {
if cap(p) < len(b) {
p = append(p, make([]byte, len(b)-len(p))...)
}
copy(p, b)
}
return len(b), e
} }
b, e := o.r.ReadBytes(byte(o.d))
if len(b) > 0 {
if cap(p) < len(b) {
p = append(p, make([]byte, len(b)-len(p))...)
}
copy(p, b)
}
return len(b), e
}
func (o *dlm) UnRead() ([]byte, error) {
if o == nil || o.r == nil {
return nil, ErrInstance
}
if s := o.r.Buffered(); s > 0 {
b := make([]byte, s)
_, e := o.r.Read(b)
return b, e
}
return nil, nil
} }
func (o *dlm) ReadBytes() ([]byte, error) { func (o *dlm) ReadBytes() ([]byte, error) {
if r := o.getReader(); r == nil { if o.r == nil {
return make([]byte, 0), ErrInstance return nil, ErrInstance
} else {
return r.ReadBytes(o.getDelimByte())
} }
return o.r.ReadBytes(byte(o.d))
} }
func (o *dlm) Close() error { func (o *dlm) Close() error {
return o.getInput().Close() o.r.Reset(nil)
o.r = nil
return o.i.Close()
} }
func (o *dlm) WriteTo(w io.Writer) (n int64, err error) { func (o *dlm) WriteTo(w io.Writer) (n int64, err error) {
var ( var (
i int
s = 1
e error e error
i int
b []byte b []byte
s = 1
d = o.getDelimByte()
) )
for err == nil && s > 0 { if o.r == nil {
b, err = o.ReadBytes() return 0, ErrInstance
}
for err == nil {
b, err = o.r.ReadBytes(d)
s = len(b) s = len(b)
if s > 0 { if s > 0 {

View File

@@ -29,82 +29,18 @@ package delim
import ( import (
"bufio" "bufio"
"io" "io"
"sync/atomic"
libsiz "github.com/nabbar/golib/size"
) )
type dlm struct { type dlm struct {
i *atomic.Value // input io.ReadCloser i io.ReadCloser // input io.ReadCloser
d *atomic.Int32 // delimiter rune r *bufio.Reader // *bufio.Reader
s *atomic.Uint64 // buffer libsiz.Size d rune // delimiter rune
r *atomic.Value // *bufio.Reader
} }
func (o *dlm) SetDelim(delim rune) { func (o *dlm) Delim() rune {
o.d.Store(delim) return o.d
}
func (o *dlm) GetDelim() rune {
return o.d.Load()
} }
func (o *dlm) getDelimByte() byte { func (o *dlm) getDelimByte() byte {
return byte(o.GetDelim()) return byte(o.d)
}
func (o *dlm) SetBufferSize(b libsiz.Size) {
o.s.Store(b.Uint64())
}
func (o *dlm) GetBufferSize() libsiz.Size {
return libsiz.Size(o.s.Load())
}
func (o *dlm) SetInput(i io.ReadCloser) {
if i == nil {
i = &DiscardCloser{}
}
o.i.Store(i)
}
func (o *dlm) getInput() io.ReadCloser {
if i := o.i.Load(); i == nil {
return &DiscardCloser{}
} else if v, k := i.(io.ReadCloser); !k {
return &DiscardCloser{}
} else {
return v
}
}
func (o *dlm) newReader() *bufio.Reader {
if siz := o.GetBufferSize(); siz > 0 {
return bufio.NewReaderSize(o.getInput(), siz.Int())
} else {
return bufio.NewReader(o.getInput())
}
}
func (o *dlm) setReader(r *bufio.Reader) {
if r == nil {
r = o.newReader()
}
o.r.Store(r)
}
func (o *dlm) getReader() *bufio.Reader {
if i := o.r.Load(); i == nil {
r := o.newReader()
o.setReader(r)
return r
} else if v, k := i.(*bufio.Reader); !k {
r := o.newReader()
o.setReader(r)
return r
} else {
return v
}
} }

View File

@@ -40,6 +40,11 @@ const DefaultBufferSize = 32 * 1024
// EOL is the end of line, default delimiter of the socket // EOL is the end of line, default delimiter of the socket
const EOL byte = '\n' const EOL byte = '\n'
// error to be filtered
var (
errFilterClosed = "use of closed network connection"
)
// ConnState is used to process state connection // ConnState is used to process state connection
type ConnState uint8 type ConnState uint8
@@ -89,6 +94,9 @@ type FuncInfo func(local, remote net.Addr, state ConnState)
// Handler is used to process request // Handler is used to process request
type Handler func(request Reader, response Writer) type Handler func(request Reader, response Writer)
// UpdateConn is used to update new connection before used it
type UpdateConn func(co net.Conn)
// Response is used to process response // Response is used to process response
type Response func(r io.Reader) type Response func(r io.Reader)
@@ -167,3 +175,15 @@ type Client interface {
// error. // error.
Once(ctx context.Context, request io.Reader, fct Response) error Once(ctx context.Context, request io.Reader, fct Response) error
} }
func ErrorFilter(err error) error {
if err == nil {
return nil
}
if err.Error() == errFilterClosed {
return nil
}
return err
}

View File

@@ -46,6 +46,7 @@ import (
// New creates a new server based on the provided network protocol. // New creates a new server based on the provided network protocol.
// //
// Parameters: // Parameters:
// - upd: a Update Connection function or nil
// - handler: the handler for the server // - handler: the handler for the server
// - delim: the delimiter to use to separate messages // - delim: the delimiter to use to separate messages
// - proto: the network protocol to use // - proto: the network protocol to use
@@ -56,26 +57,26 @@ import (
// Return type(s): // Return type(s):
// - libsck.Server: the created server // - libsck.Server: the created server
// - error: an error if any occurred during server creation // - error: an error if any occurred during server creation
func New(handler libsck.Handler, proto libptc.NetworkProtocol, address string, perm os.FileMode, gid int32) (libsck.Server, error) { func New(upd libsck.UpdateConn, handler libsck.Handler, proto libptc.NetworkProtocol, address string, perm os.FileMode, gid int32) (libsck.Server, error) {
switch proto { switch proto {
case libptc.NetworkUnix: case libptc.NetworkUnix:
if strings.EqualFold(runtime.GOOS, "linux") { if strings.EqualFold(runtime.GOOS, "linux") {
s := scksrx.New(handler) s := scksrx.New(upd, handler)
e := s.RegisterSocket(address, perm, gid) e := s.RegisterSocket(address, perm, gid)
return s, e return s, e
} }
case libptc.NetworkUnixGram: case libptc.NetworkUnixGram:
if strings.EqualFold(runtime.GOOS, "linux") { if strings.EqualFold(runtime.GOOS, "linux") {
s := sckgrm.New(handler) s := sckgrm.New(upd, handler)
e := s.RegisterSocket(address, perm, gid) e := s.RegisterSocket(address, perm, gid)
return s, e return s, e
} }
case libptc.NetworkTCP, libptc.NetworkTCP4, libptc.NetworkTCP6: case libptc.NetworkTCP, libptc.NetworkTCP4, libptc.NetworkTCP6:
s := scksrt.New(handler) s := scksrt.New(upd, handler)
e := s.RegisterServer(address) e := s.RegisterServer(address)
return s, e return s, e
case libptc.NetworkUDP, libptc.NetworkUDP4, libptc.NetworkUDP6: case libptc.NetworkUDP, libptc.NetworkUDP4, libptc.NetworkUDP6:
s := scksru.New(handler) s := scksru.New(upd, handler)
e := s.RegisterServer(address) e := s.RegisterServer(address)
return s, e return s, e
} }

View File

@@ -42,6 +42,7 @@ import (
// New creates a new server based on the network protocol specified. // New creates a new server based on the network protocol specified.
// //
// Parameters: // Parameters:
// - upd: a Update Connection function or nil
// - handler: the handler for the server // - handler: the handler for the server
// - delim: the delimiter to use to separate messages // - delim: the delimiter to use to separate messages
// - proto: the network protocol to use // - proto: the network protocol to use
@@ -50,14 +51,14 @@ import (
// - perm: the file mode permissions for the socket, not applicable for non unix // - perm: the file mode permissions for the socket, not applicable for non unix
// - gid: the group ID for the socket permissions, not applicable for non unix // - gid: the group ID for the socket permissions, not applicable for non unix
// Return type(s): libsck.Server, error // Return type(s): libsck.Server, error
func New(handler libsck.Handler, proto libptc.NetworkProtocol, address string, perm os.FileMode, gid int32) (libsck.Server, error) { func New(upd libsck.UpdateConn, handler libsck.Handler, proto libptc.NetworkProtocol, address string, perm os.FileMode, gid int32) (libsck.Server, error) {
switch proto { switch proto {
case libptc.NetworkTCP, libptc.NetworkTCP4, libptc.NetworkTCP6: case libptc.NetworkTCP, libptc.NetworkTCP4, libptc.NetworkTCP6:
s := scksrt.New(handler) s := scksrt.New(upd, handler)
e := s.RegisterServer(address) e := s.RegisterServer(address)
return s, e return s, e
case libptc.NetworkUDP, libptc.NetworkUDP4, libptc.NetworkUDP6: case libptc.NetworkUDP, libptc.NetworkUDP4, libptc.NetworkUDP6:
s := scksru.New(handler) s := scksru.New(upd, handler)
e := s.RegisterServer(address) e := s.RegisterServer(address)
return s, e return s, e
} }

View File

@@ -37,7 +37,7 @@ type ServerTcp interface {
RegisterServer(address string) error RegisterServer(address string) error
} }
func New(h libsck.Handler) ServerTcp { func New(u libsck.UpdateConn, h libsck.Handler) ServerTcp {
c := new(atomic.Value) c := new(atomic.Value)
c.Store(make(chan []byte)) c.Store(make(chan []byte))
@@ -47,12 +47,10 @@ func New(h libsck.Handler) ServerTcp {
r := new(atomic.Value) r := new(atomic.Value)
r.Store(make(chan struct{})) r.Store(make(chan struct{}))
f := new(atomic.Value)
f.Store(h)
return &srv{ return &srv{
ssl: new(atomic.Value), ssl: new(atomic.Value),
hdl: f, upd: u,
hdl: h,
msg: c, msg: c,
stp: s, stp: s,
rst: r, rst: r,

View File

@@ -76,7 +76,7 @@ func (o *srv) Listen(ctx context.Context) error {
if len(a) == 0 { if len(a) == 0 {
o.fctError(ErrInvalidHandler) o.fctError(ErrInvalidHandler)
return ErrInvalidAddress return ErrInvalidAddress
} else if hdl := o.handler(); hdl == nil { } else if o.hdl == nil {
o.fctError(ErrInvalidHandler) o.fctError(ErrInvalidHandler)
return ErrInvalidHandler return ErrInvalidHandler
} else if l, e = o.getListen(a); e != nil { } else if l, e = o.getListen(a); e != nil {
@@ -141,13 +141,17 @@ func (o *srv) Listen(ctx context.Context) error {
func (o *srv) Conn(ctx context.Context, con net.Conn) { func (o *srv) Conn(ctx context.Context, con net.Conn) {
var ( var (
hdl libsck.Handler
cnl context.CancelFunc cnl context.CancelFunc
cor libsck.Reader cor libsck.Reader
cow libsck.Writer cow libsck.Writer
) )
o.nc.Add(1) // inc nb connection o.nc.Add(1) // inc nb connection
if o.upd != nil {
o.upd(con)
}
ctx, cnl = context.WithCancel(ctx) ctx, cnl = context.WithCancel(ctx)
cor, cow = o.getReadWriter(ctx, cnl, con) cor, cow = o.getReadWriter(ctx, cnl, con)
@@ -181,10 +185,10 @@ func (o *srv) Conn(ctx context.Context, con net.Conn) {
}() }()
// get handler or exit if nil // get handler or exit if nil
if hdl = o.handler(); hdl == nil { if o.hdl == nil {
return return
} else { } else {
go hdl(cor, cow) go o.hdl(cor, cow)
} }
for { for {
@@ -213,12 +217,12 @@ func (o *srv) getReadWriter(ctx context.Context, cnl context.CancelFunc, con net
if cr, ok := con.(*net.TCPConn); ok { if cr, ok := con.(*net.TCPConn); ok {
rc.Store(true) rc.Store(true)
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionCloseRead) o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionCloseRead)
return cr.CloseRead() return libsck.ErrorFilter(cr.CloseRead())
} else { } else {
rc.Store(true) rc.Store(true)
rw.Store(true) rw.Store(true)
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionClose) o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionClose)
return con.Close() return libsck.ErrorFilter(con.Close())
} }
} }
@@ -232,12 +236,12 @@ func (o *srv) getReadWriter(ctx context.Context, cnl context.CancelFunc, con net
if cr, ok := con.(*net.TCPConn); ok { if cr, ok := con.(*net.TCPConn); ok {
rw.Store(true) rw.Store(true)
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionCloseWrite) o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionCloseWrite)
return cr.CloseRead() return libsck.ErrorFilter(cr.CloseRead())
} else { } else {
rc.Store(true) rc.Store(true)
rw.Store(true) rw.Store(true)
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionClose) o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionClose)
return con.Close() return libsck.ErrorFilter(con.Close())
} }
} }

View File

@@ -49,13 +49,14 @@ func init() {
} }
type srv struct { type srv struct {
ssl *atomic.Value // tls config ssl *atomic.Value // tls config
hdl *atomic.Value // handler upd libsck.UpdateConn // updateConn
msg *atomic.Value // chan []byte hdl libsck.Handler // handler
stp *atomic.Value // chan struct{} msg *atomic.Value // chan []byte
rst *atomic.Value // chan struct{} stp *atomic.Value // chan struct{}
run *atomic.Bool // is Running rst *atomic.Value // chan struct{}
gon *atomic.Bool // is Running run *atomic.Bool // is Running
gon *atomic.Bool // is Running
fe *atomic.Value // function error fe *atomic.Value // function error
fi *atomic.Value // function info fi *atomic.Value // function info
@@ -294,19 +295,6 @@ func (o *srv) fctInfoSrv(msg string, args ...interface{}) {
} }
} }
func (o *srv) handler() libsck.Handler {
if o == nil {
return nil
}
v := o.hdl.Load()
if v != nil {
return v.(libsck.Handler)
}
return nil
}
func (o *srv) getTLS() *tls.Config { func (o *srv) getTLS() *tls.Config {
i := o.ssl.Load() i := o.ssl.Load()

View File

@@ -130,7 +130,7 @@ var _ = Describe("socket/server/tcp", func() {
}) })
It("Create new server based on config must succeed", func() { It("Create new server based on config must succeed", func() {
sck, err = srv.New(Handler) sck, err = srv.New(nil, Handler)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(sck).ToNot(BeNil()) Expect(sck).ToNot(BeNil())
}) })
@@ -226,7 +226,7 @@ var _ = Describe("socket/server/tcp", func() {
}) })
It("Create new server based on config must succeed", func() { It("Create new server based on config must succeed", func() {
sck, err = srv.New(Handler) sck, err = srv.New(nil, Handler)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(sck).ToNot(BeNil()) Expect(sck).ToNot(BeNil())
}) })

View File

@@ -37,18 +37,16 @@ type ServerTcp interface {
RegisterServer(address string) error RegisterServer(address string) error
} }
func New(h libsck.Handler) ServerTcp { func New(u libsck.UpdateConn, h libsck.Handler) ServerTcp {
c := new(atomic.Value) c := new(atomic.Value)
c.Store(make(chan []byte)) c.Store(make(chan []byte))
s := new(atomic.Value) s := new(atomic.Value)
s.Store(make(chan struct{})) s.Store(make(chan struct{}))
f := new(atomic.Value)
f.Store(h)
return &srv{ return &srv{
hdl: f, upd: u,
hdl: h,
msg: c, msg: c,
stp: s, stp: s,
run: new(atomic.Bool), run: new(atomic.Bool),

View File

@@ -74,7 +74,6 @@ func (o *srv) Listen(ctx context.Context) error {
loc *net.UDPAddr loc *net.UDPAddr
con *net.UDPConn con *net.UDPConn
hdl libsck.Handler
cnl context.CancelFunc cnl context.CancelFunc
cor libsck.Reader cor libsck.Reader
cow libsck.Writer cow libsck.Writer
@@ -85,7 +84,7 @@ func (o *srv) Listen(ctx context.Context) error {
if len(a) == 0 { if len(a) == 0 {
o.fctError(ErrInvalidInstance) o.fctError(ErrInvalidInstance)
return ErrInvalidAddress return ErrInvalidAddress
} else if hdl = o.handler(); hdl == nil { } else if o.hdl == nil {
o.fctError(ErrInvalidInstance) o.fctError(ErrInvalidInstance)
return ErrInvalidHandler return ErrInvalidHandler
} else if loc, con, e = o.getListen(a); e != nil { } else if loc, con, e = o.getListen(a); e != nil {
@@ -93,6 +92,10 @@ func (o *srv) Listen(ctx context.Context) error {
return e return e
} }
if o.upd != nil {
o.upd(con)
}
ctx, cnl = context.WithCancel(ctx) ctx, cnl = context.WithCancel(ctx)
cor, cow = o.getReadWriter(ctx, con, loc) cor, cow = o.getReadWriter(ctx, con, loc)
@@ -114,7 +117,7 @@ func (o *srv) Listen(ctx context.Context) error {
}() }()
// get handler or exit if nil // get handler or exit if nil
go hdl(cor, cow) go o.hdl(cor, cow)
for { for {
select { select {
@@ -143,7 +146,7 @@ func (o *srv) getReadWriter(ctx context.Context, con *net.UDPConn, loc net.Addr)
fctClose := func() error { fctClose := func() error {
o.fctInfo(loc, fg(), libsck.ConnectionClose) o.fctInfo(loc, fg(), libsck.ConnectionClose)
return con.Close() return libsck.ErrorFilter(con.Close())
} }
rdr := libsck.NewReader( rdr := libsck.NewReader(

View File

@@ -48,10 +48,11 @@ func init() {
} }
type srv struct { type srv struct {
hdl *atomic.Value // handler upd libsck.UpdateConn // updateConn
msg *atomic.Value // chan []byte hdl libsck.Handler // handler
stp *atomic.Value // chan struct{} msg *atomic.Value // chan []byte
run *atomic.Bool // is Running stp *atomic.Value // chan struct{}
run *atomic.Bool // is Running
fe *atomic.Value // function error fe *atomic.Value // function error
fi *atomic.Value // function info fi *atomic.Value // function info
@@ -218,16 +219,3 @@ func (o *srv) fctInfoSrv(msg string, args ...interface{}) {
v.(libsck.FuncInfoSrv)(fmt.Sprintf(msg, args...)) v.(libsck.FuncInfoSrv)(fmt.Sprintf(msg, args...))
} }
} }
func (o *srv) handler() libsck.Handler {
if o == nil {
return nil
}
v := o.hdl.Load()
if v != nil {
return v.(libsck.Handler)
}
return nil
}

View File

@@ -129,7 +129,7 @@ var _ = Describe("socket/server/udp", func() {
}) })
It("Create new server based on config must succeed", func() { It("Create new server based on config must succeed", func() {
sck, err = srv.New(Handler) sck, err = srv.New(nil, Handler)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(sck).ToNot(BeNil()) Expect(sck).ToNot(BeNil())
}) })

View File

@@ -43,7 +43,7 @@ type ServerUnix interface {
RegisterSocket(unixFile string, perm os.FileMode, gid int32) error RegisterSocket(unixFile string, perm os.FileMode, gid int32) error
} }
func New(h libsck.Handler) ServerUnix { func New(u libsck.UpdateConn, h libsck.Handler) ServerUnix {
c := new(atomic.Value) c := new(atomic.Value)
c.Store(make(chan []byte)) c.Store(make(chan []byte))
@@ -53,9 +53,6 @@ func New(h libsck.Handler) ServerUnix {
r := new(atomic.Value) r := new(atomic.Value)
r.Store(make(chan struct{})) r.Store(make(chan struct{}))
f := new(atomic.Value)
f.Store(h)
// socket file // socket file
sf := new(atomic.Value) sf := new(atomic.Value)
sf.Store("") sf.Store("")
@@ -69,7 +66,8 @@ func New(h libsck.Handler) ServerUnix {
sg.Store(0) sg.Store(0)
return &srv{ return &srv{
hdl: f, upd: u,
hdl: h,
msg: c, msg: c,
stp: s, stp: s,
rst: r, rst: r,

View File

@@ -146,7 +146,7 @@ func (o *srv) Listen(ctx context.Context) error {
if f, e = o.getSocketFile(); e != nil { if f, e = o.getSocketFile(); e != nil {
o.fctError(e) o.fctError(e)
return e return e
} else if hdl := o.handler(); hdl == nil { } else if o.hdl == nil {
o.fctError(ErrInvalidHandler) o.fctError(ErrInvalidHandler)
return ErrInvalidHandler return ErrInvalidHandler
} else if l, e = o.getListen(f); e != nil { } else if l, e = o.getListen(f); e != nil {
@@ -211,13 +211,17 @@ func (o *srv) Listen(ctx context.Context) error {
func (o *srv) Conn(ctx context.Context, con net.Conn) { func (o *srv) Conn(ctx context.Context, con net.Conn) {
var ( var (
hdl libsck.Handler
cnl context.CancelFunc cnl context.CancelFunc
cor libsck.Reader cor libsck.Reader
cow libsck.Writer cow libsck.Writer
) )
o.nc.Add(1) // inc nb connection o.nc.Add(1) // inc nb connection
if o.upd != nil {
o.upd(con)
}
ctx, cnl = context.WithCancel(ctx) ctx, cnl = context.WithCancel(ctx)
cor, cow = o.getReadWriter(ctx, cnl, con) cor, cow = o.getReadWriter(ctx, cnl, con)
@@ -251,10 +255,10 @@ func (o *srv) Conn(ctx context.Context, con net.Conn) {
}() }()
// get handler or exit if nil // get handler or exit if nil
if hdl = o.handler(); hdl == nil { if o.hdl == nil {
return return
} else { } else {
go hdl(cor, cow) go o.hdl(cor, cow)
} }
for { for {
@@ -283,12 +287,12 @@ func (o *srv) getReadWriter(ctx context.Context, cnl context.CancelFunc, con net
if cr, ok := con.(*net.UnixConn); ok { if cr, ok := con.(*net.UnixConn); ok {
rc.Store(true) rc.Store(true)
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionCloseRead) o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionCloseRead)
return cr.CloseRead() return libsck.ErrorFilter(cr.CloseRead())
} else { } else {
rc.Store(true) rc.Store(true)
rw.Store(true) rw.Store(true)
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionClose) o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionClose)
return con.Close() return libsck.ErrorFilter(con.Close())
} }
} }
@@ -302,12 +306,12 @@ func (o *srv) getReadWriter(ctx context.Context, cnl context.CancelFunc, con net
if cr, ok := con.(*net.UnixConn); ok { if cr, ok := con.(*net.UnixConn); ok {
rw.Store(true) rw.Store(true)
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionCloseWrite) o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionCloseWrite)
return cr.CloseRead() return libsck.ErrorFilter(cr.CloseRead())
} else { } else {
rc.Store(true) rc.Store(true)
rw.Store(true) rw.Store(true)
o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionClose) o.fctInfo(con.LocalAddr(), con.RemoteAddr(), libsck.ConnectionClose)
return con.Close() return libsck.ErrorFilter(con.Close())
} }
} }

View File

@@ -52,12 +52,13 @@ func init() {
} }
type srv struct { type srv struct {
hdl *atomic.Value // handler upd libsck.UpdateConn // updateConn
msg *atomic.Value // chan []byte hdl libsck.Handler // handler
stp *atomic.Value // chan struct{} msg *atomic.Value // chan []byte
rst *atomic.Value // chan struct{} stp *atomic.Value // chan struct{}
run *atomic.Bool // is Running rst *atomic.Value // chan struct{}
gon *atomic.Bool // is Running run *atomic.Bool // is Running
gon *atomic.Bool // is Running
fe *atomic.Value // function error fe *atomic.Value // function error
fi *atomic.Value // function info fi *atomic.Value // function info
@@ -284,16 +285,3 @@ func (o *srv) fctInfoSrv(msg string, args ...interface{}) {
v.(libsck.FuncInfoSrv)(fmt.Sprintf(msg, args...)) v.(libsck.FuncInfoSrv)(fmt.Sprintf(msg, args...))
} }
} }
func (o *srv) handler() libsck.Handler {
if o == nil {
return nil
}
v := o.hdl.Load()
if v != nil {
return v.(libsck.Handler)
}
return nil
}

View File

@@ -124,7 +124,7 @@ var _ = Describe("socket/server/unix", func() {
}) })
It("Create new server based on config must succeed", func() { It("Create new server based on config must succeed", func() {
sck, err = srv.New(Handler) sck, err = srv.New(nil, Handler)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(sck).ToNot(BeNil()) Expect(sck).ToNot(BeNil())
}) })
@@ -226,7 +226,7 @@ var _ = Describe("socket/server/unix", func() {
}) })
It("Create new server based on config must succeed", func() { It("Create new server based on config must succeed", func() {
sck, err = srv.New(Handler) sck, err = srv.New(nil, Handler)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(sck).ToNot(BeNil()) Expect(sck).ToNot(BeNil())
}) })

View File

@@ -43,16 +43,13 @@ type ServerUnixGram interface {
RegisterSocket(unixFile string, perm os.FileMode, gid int32) error RegisterSocket(unixFile string, perm os.FileMode, gid int32) error
} }
func New(h libsck.Handler) ServerUnixGram { func New(u libsck.UpdateConn, h libsck.Handler) ServerUnixGram {
c := new(atomic.Value) c := new(atomic.Value)
c.Store(make(chan []byte)) c.Store(make(chan []byte))
s := new(atomic.Value) s := new(atomic.Value)
s.Store(make(chan struct{})) s.Store(make(chan struct{}))
f := new(atomic.Value)
f.Store(h)
// socket file // socket file
sf := new(atomic.Value) sf := new(atomic.Value)
sf.Store("") sf.Store("")
@@ -66,7 +63,8 @@ func New(h libsck.Handler) ServerUnixGram {
sg.Store(0) sg.Store(0)
return &srv{ return &srv{
hdl: f, upd: u,
hdl: h,
msg: c, msg: c,
stp: s, stp: s,
run: new(atomic.Bool), run: new(atomic.Bool),

View File

@@ -142,7 +142,6 @@ func (o *srv) Listen(ctx context.Context) error {
loc *net.UnixAddr loc *net.UnixAddr
con *net.UnixConn con *net.UnixConn
hdl libsck.Handler
cnl context.CancelFunc cnl context.CancelFunc
cor libsck.Reader cor libsck.Reader
cow libsck.Writer cow libsck.Writer
@@ -153,7 +152,7 @@ func (o *srv) Listen(ctx context.Context) error {
if u, e = o.getSocketFile(); e != nil { if u, e = o.getSocketFile(); e != nil {
o.fctError(e) o.fctError(e)
return e return e
} else if hdl = o.handler(); hdl == nil { } else if o.hdl == nil {
o.fctError(ErrInvalidHandler) o.fctError(ErrInvalidHandler)
return ErrInvalidHandler return ErrInvalidHandler
} else if loc, e = net.ResolveUnixAddr(libptc.NetworkUnixGram.Code(), u); e != nil { } else if loc, e = net.ResolveUnixAddr(libptc.NetworkUnixGram.Code(), u); e != nil {
@@ -164,6 +163,10 @@ func (o *srv) Listen(ctx context.Context) error {
return e return e
} }
if o.upd != nil {
o.upd(con)
}
ctx, cnl = context.WithCancel(ctx) ctx, cnl = context.WithCancel(ctx)
cor, cow = o.getReadWriter(ctx, con, loc) cor, cow = o.getReadWriter(ctx, con, loc)
@@ -189,7 +192,7 @@ func (o *srv) Listen(ctx context.Context) error {
}() }()
// get handler or exit if nil // get handler or exit if nil
go hdl(cor, cow) go o.hdl(cor, cow)
for { for {
select { select {
@@ -218,7 +221,7 @@ func (o *srv) getReadWriter(ctx context.Context, con *net.UnixConn, loc net.Addr
fctClose := func() error { fctClose := func() error {
o.fctInfo(loc, fg(), libsck.ConnectionClose) o.fctInfo(loc, fg(), libsck.ConnectionClose)
return con.Close() return libsck.ErrorFilter(con.Close())
} }
rdr := libsck.NewReader( rdr := libsck.NewReader(

View File

@@ -52,10 +52,11 @@ func init() {
} }
type srv struct { type srv struct {
hdl *atomic.Value // handler upd libsck.UpdateConn // updateConn
msg *atomic.Value // chan []byte hdl libsck.Handler // handler
stp *atomic.Value // chan struct{} msg *atomic.Value // chan []byte
run *atomic.Bool // is Running stp *atomic.Value // chan struct{}
run *atomic.Bool // is Running
fe *atomic.Value // function error fe *atomic.Value // function error
fi *atomic.Value // function info fi *atomic.Value // function info
@@ -228,16 +229,3 @@ func (o *srv) fctInfoSrv(msg string, args ...interface{}) {
v.(libsck.FuncInfoSrv)(fmt.Sprintf(msg, args...)) v.(libsck.FuncInfoSrv)(fmt.Sprintf(msg, args...))
} }
} }
func (o *srv) handler() libsck.Handler {
if o == nil {
return nil
}
v := o.hdl.Load()
if v != nil {
return v.(libsck.Handler)
}
return nil
}

View File

@@ -117,7 +117,7 @@ var _ = Describe("socket/server/unixgram", func() {
}) })
It("Create new server based on config must succeed", func() { It("Create new server based on config must succeed", func() {
sck, err = srv.New(Handler) sck, err = srv.New(nil, Handler)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(sck).ToNot(BeNil()) Expect(sck).ToNot(BeNil())
}) })

View File

@@ -78,7 +78,7 @@ func checkPanic(err ...error) {
} }
func main() { func main() {
srv, err := config().New(Handler) srv, err := config().New(nil, Handler)
checkPanic(err) checkPanic(err)
srv.RegisterFuncError(func(e ...error) { srv.RegisterFuncError(func(e ...error) {

View File

@@ -78,7 +78,7 @@ func checkPanic(err ...error) {
} }
func main() { func main() {
srv, err := config().New(Handler) srv, err := config().New(nil, Handler)
checkPanic(err) checkPanic(err)
srv.RegisterFuncError(func(e ...error) { srv.RegisterFuncError(func(e ...error) {

View File

@@ -79,7 +79,7 @@ func checkPanic(err ...error) {
} }
func main() { func main() {
srv, err := config().New(Handler) srv, err := config().New(nil, Handler)
checkPanic(err) checkPanic(err)
srv.RegisterFuncError(func(e ...error) { srv.RegisterFuncError(func(e ...error) {