mirror of
https://github.com/nabbar/golib.git
synced 2025-09-26 20:01:15 +08:00
Package Status:
- Rework for the management of mandatory components to qualify the global status. - Added qualification to components: "should", "must", "one of". - These qualifications will influence the overall state but not the unitary state of each component. Package Socket: - Creation package to open and listen local unix file socket - Allow to specify a handler who's needing a conn instance as entry - Create a client sub package to allow negociate with the local unix file socket Package Shell: - adding sub package for command and command collection Package Monitor: - add function to expose monitor command for shell Package Config: - add function to expose monitor command for shell Package Network: - Add "IP" protocol Pakcage Httpcli: - Rework the construction of the client - Add capability to specify proxy url Package Cobra: - add function to add flag to global command like verbose or config Package Log: - fix seg fault when calling a nil instance - remove println in hookfile / hooksyslog
This commit is contained in:
@@ -43,19 +43,19 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/nabbar/golib/aws"
|
||||
"github.com/nabbar/golib/aws/configCustom"
|
||||
"github.com/nabbar/golib/httpcli"
|
||||
"github.com/nabbar/golib/password"
|
||||
lbuuid "github.com/hashicorp/go-uuid"
|
||||
libaws "github.com/nabbar/golib/aws"
|
||||
awscfg "github.com/nabbar/golib/aws/configCustom"
|
||||
libhtc "github.com/nabbar/golib/httpcli"
|
||||
libpwd "github.com/nabbar/golib/password"
|
||||
libsiz "github.com/nabbar/golib/size"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var (
|
||||
cli aws.AWS
|
||||
cfg aws.Config
|
||||
cli libaws.AWS
|
||||
cfg libaws.Config
|
||||
ctx context.Context
|
||||
cnl context.CancelFunc
|
||||
filename = "./config.json"
|
||||
@@ -88,14 +88,15 @@ var _ = BeforeSuite(func() {
|
||||
Host: "localhost:" + strconv.Itoa(GetFreePort()),
|
||||
}
|
||||
|
||||
accessKey = password.Generate(20)
|
||||
secretKey = password.Generate(64)
|
||||
accessKey = libpwd.Generate(20)
|
||||
secretKey = libpwd.Generate(64)
|
||||
)
|
||||
|
||||
htp = httpcli.GetClient(uri.Hostname())
|
||||
htp, err = libhtc.GetClient(libhtc.GetTransport(false, false, false), true, libhtc.ClientTimeout30Sec)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(htp).NotTo(BeNil())
|
||||
|
||||
cfg = configCustom.NewConfig("", accessKey, secretKey, uri, "us-east-1")
|
||||
cfg = awscfg.NewConfig("", accessKey, secretKey, uri, "us-east-1")
|
||||
Expect(cfg).NotTo(BeNil())
|
||||
|
||||
cfg.SetRegion("us-east-1")
|
||||
@@ -114,13 +115,13 @@ var _ = BeforeSuite(func() {
|
||||
println("Minio is waiting on : " + uri.Host)
|
||||
}
|
||||
|
||||
cli, err = aws.New(ctx, cfg, htp)
|
||||
cli, err = libaws.New(ctx, cfg, htp)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(cli).NotTo(BeNil())
|
||||
|
||||
cli.ForcePathStyle(ctx, true)
|
||||
|
||||
name, err = uuid.GenerateUUID()
|
||||
name, err = lbuuid.GenerateUUID()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(name).ToNot(BeEmpty())
|
||||
cli.Config().SetBucketName(name)
|
||||
@@ -144,7 +145,7 @@ func loadConfig() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if cfg, err = configCustom.NewConfigJsonUnmashal(cnfByt); err != nil {
|
||||
if cfg, err = awscfg.NewConfigJsonUnmashal(cnfByt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@@ -28,6 +28,7 @@ package cobra
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
libver "github.com/nabbar/golib/version"
|
||||
@@ -53,6 +54,30 @@ type Cobra interface {
|
||||
SetFlagConfig(persistent bool, flagVar *string) error
|
||||
SetFlagVerbose(persistent bool, flagVar *int)
|
||||
|
||||
AddFlagString(persistent bool, p *string, name, shorthand string, value string, usage string)
|
||||
AddFlagCount(persistent bool, p *int, name, shorthand string, usage string)
|
||||
AddFlagBool(persistent bool, p *bool, name, shorthand string, value bool, usage string)
|
||||
AddFlagDuration(persistent bool, p *time.Duration, name, shorthand string, value time.Duration, usage string)
|
||||
AddFlagFloat32(persistent bool, p *float32, name, shorthand string, value float32, usage string)
|
||||
AddFlagFloat64(persistent bool, p *float64, name, shorthand string, value float64, usage string)
|
||||
AddFlagInt(persistent bool, p *int, name, shorthand string, value int, usage string)
|
||||
AddFlagInt8(persistent bool, p *int8, name, shorthand string, value int8, usage string)
|
||||
AddFlagInt16(persistent bool, p *int16, name, shorthand string, value int16, usage string)
|
||||
AddFlagInt32(persistent bool, p *int32, name, shorthand string, value int32, usage string)
|
||||
AddFlagInt32Slice(persistent bool, p *[]int32, name, shorthand string, value []int32, usage string)
|
||||
AddFlagInt64(persistent bool, p *int64, name, shorthand string, value int64, usage string)
|
||||
AddFlagInt64Slice(persistent bool, p *[]int64, name, shorthand string, value []int64, usage string)
|
||||
AddFlagUint(persistent bool, p *uint, name, shorthand string, value uint, usage string)
|
||||
AddFlagUintSlice(persistent bool, p *[]uint, name, shorthand string, value []uint, usage string)
|
||||
AddFlagUint8(persistent bool, p *uint8, name, shorthand string, value uint8, usage string)
|
||||
AddFlagUint16(persistent bool, p *uint16, name, shorthand string, value uint16, usage string)
|
||||
AddFlagUint32(persistent bool, p *uint32, name, shorthand string, value uint32, usage string)
|
||||
AddFlagUint64(persistent bool, p *uint64, name, shorthand string, value uint64, usage string)
|
||||
AddFlagStringArray(persistent bool, p *[]string, name, shorthand string, value []string, usage string)
|
||||
AddFlagStringToInt(persistent bool, p *map[string]int, name, shorthand string, value map[string]int, usage string)
|
||||
AddFlagStringToInt64(persistent bool, p *map[string]int64, name, shorthand string, value map[string]int64, usage string)
|
||||
AddFlagStringToString(persistent bool, p *map[string]string, name, shorthand string, value map[string]string, usage string)
|
||||
|
||||
NewCommand(cmd, short, long, useWithoutCmd, exampleWithoutCmd string) *spfcbr.Command
|
||||
AddCommand(subCmd ...*spfcbr.Command)
|
||||
|
||||
|
185
cobra/model.go
185
cobra/model.go
@@ -32,6 +32,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
libver "github.com/nabbar/golib/version"
|
||||
@@ -175,3 +176,187 @@ func (c *cobra) getPackageDescShort() string {
|
||||
func (c *cobra) getPackageDescLong() string {
|
||||
return c.s.GetDescription()
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagString(persistent bool, p *string, name, shorthand string, value string, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().StringVarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().StringVarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagCount(persistent bool, p *int, name, shorthand string, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().CountVarP(p, name, shorthand, usage)
|
||||
} else {
|
||||
c.c.Flags().CountVarP(p, name, shorthand, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagBool(persistent bool, p *bool, name, shorthand string, value bool, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().BoolVarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().BoolVarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagDuration(persistent bool, p *time.Duration, name, shorthand string, value time.Duration, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().DurationVarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().DurationVarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagFloat32(persistent bool, p *float32, name, shorthand string, value float32, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().Float32VarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().Float32VarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagFloat64(persistent bool, p *float64, name, shorthand string, value float64, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().Float64VarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().Float64VarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagInt(persistent bool, p *int, name, shorthand string, value int, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().IntVarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().IntVarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagInt8(persistent bool, p *int8, name, shorthand string, value int8, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().Int8VarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().Int8VarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagInt16(persistent bool, p *int16, name, shorthand string, value int16, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().Int16VarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().Int16VarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagInt32(persistent bool, p *int32, name, shorthand string, value int32, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().Int32VarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().Int32VarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagInt32Slice(persistent bool, p *[]int32, name, shorthand string, value []int32, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().Int32SliceVarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().Int32SliceVarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagInt64(persistent bool, p *int64, name, shorthand string, value int64, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().Int64VarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().Int64VarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagInt64Slice(persistent bool, p *[]int64, name, shorthand string, value []int64, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().Int64SliceVarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().Int64SliceVarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagUint(persistent bool, p *uint, name, shorthand string, value uint, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().UintVarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().UintVarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagUintSlice(persistent bool, p *[]uint, name, shorthand string, value []uint, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().UintSliceVarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().UintSliceVarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagUint8(persistent bool, p *uint8, name, shorthand string, value uint8, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().Uint8VarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().Uint8VarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagUint16(persistent bool, p *uint16, name, shorthand string, value uint16, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().Uint16VarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().Uint16VarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagUint32(persistent bool, p *uint32, name, shorthand string, value uint32, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().Uint32VarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().Uint32VarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagUint64(persistent bool, p *uint64, name, shorthand string, value uint64, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().Uint64VarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().Uint64VarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagStringArray(persistent bool, p *[]string, name, shorthand string, value []string, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().StringArrayVarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().StringArrayVarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagStringToInt(persistent bool, p *map[string]int, name, shorthand string, value map[string]int, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().StringToIntVarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().StringToIntVarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagStringToInt64(persistent bool, p *map[string]int64, name, shorthand string, value map[string]int64, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().StringToInt64VarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().StringToInt64VarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddFlagStringToString(persistent bool, p *map[string]string, name, shorthand string, value map[string]string, usage string) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().StringToStringVarP(p, name, shorthand, value, usage)
|
||||
} else {
|
||||
c.c.Flags().StringToStringVarP(p, name, shorthand, value, usage)
|
||||
}
|
||||
}
|
||||
|
@@ -32,13 +32,11 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
_const "github.com/nabbar/golib/config/const"
|
||||
|
||||
cfgcst "github.com/nabbar/golib/config/const"
|
||||
cfgtps "github.com/nabbar/golib/config/types"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
spfcbr "github.com/spf13/cobra"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
func (c *configModel) ComponentHas(key string) bool {
|
||||
@@ -184,17 +182,19 @@ func (c *configModel) ComponentReload() liberr.Error {
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentStop() {
|
||||
c.cpt.Walk(func(key string, val interface{}) bool {
|
||||
if v, k := val.(cfgtps.Component); !k {
|
||||
c.cpt.Delete(key)
|
||||
} else if v == nil {
|
||||
c.cpt.Delete(key)
|
||||
} else if v.IsStarted() {
|
||||
v.Stop()
|
||||
}
|
||||
lst := c.ComponentDependencies()
|
||||
|
||||
return true
|
||||
})
|
||||
for i := len(lst) - 1; i >= 0; i-- {
|
||||
key := lst[i]
|
||||
|
||||
if len(key) < 1 {
|
||||
continue
|
||||
} else if cpt := c.ComponentGet(key); cpt == nil {
|
||||
continue
|
||||
} else {
|
||||
cpt.Stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentIsRunning(atLeast bool) bool {
|
||||
@@ -300,12 +300,12 @@ func (c *configModel) DefaultConfig() io.Reader {
|
||||
return true
|
||||
}
|
||||
|
||||
if p := v.DefaultConfig(_const.JSONIndent); len(p) > 0 {
|
||||
if p := v.DefaultConfig(cfgcst.JSONIndent); len(p) > 0 {
|
||||
if buffer.Len() > n {
|
||||
buffer.WriteString(",")
|
||||
buffer.WriteString("\n")
|
||||
}
|
||||
buffer.WriteString(fmt.Sprintf("%s\"%s\": ", _const.JSONIndent, key))
|
||||
buffer.WriteString(fmt.Sprintf("%s\"%s\": ", cfgcst.JSONIndent, key))
|
||||
buffer.Write(p)
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ func (c *configModel) DefaultConfig() io.Reader {
|
||||
|
||||
if err := json.Compact(cmp, buffer.Bytes()); err != nil {
|
||||
return buffer
|
||||
} else if err = json.Indent(ind, cmp.Bytes(), "", _const.JSONIndent); err != nil {
|
||||
} else if err = json.Indent(ind, cmp.Bytes(), "", cfgcst.JSONIndent); err != nil {
|
||||
return buffer
|
||||
}
|
||||
|
||||
|
@@ -33,11 +33,11 @@ import (
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
|
||||
cfgtps "github.com/nabbar/golib/config/types"
|
||||
libctx "github.com/nabbar/golib/context"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
shlcmd "github.com/nabbar/golib/shell/command"
|
||||
libver "github.com/nabbar/golib/version"
|
||||
libvpr "github.com/nabbar/golib/viper"
|
||||
)
|
||||
@@ -123,6 +123,11 @@ type Config interface {
|
||||
*/
|
||||
cfgtps.ComponentList
|
||||
cfgtps.ComponentMonitor
|
||||
|
||||
/*
|
||||
// Section Shell Command : github.com/nabbar/golib/shell
|
||||
*/
|
||||
GetShellCommand() []shlcmd.Command
|
||||
}
|
||||
|
||||
var (
|
||||
|
152
config/shell.go
Normal file
152
config/shell.go
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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 config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
shlcmd "github.com/nabbar/golib/shell/command"
|
||||
)
|
||||
|
||||
func ShellCommandInfo() []shlcmd.CommandInfo {
|
||||
var res = make([]shlcmd.CommandInfo, 0)
|
||||
|
||||
res = append(res, shlcmd.Info("list", "list all components"))
|
||||
res = append(res, shlcmd.Info("start", "Starting components (leave args empty to start all components)"))
|
||||
res = append(res, shlcmd.Info("stop", "Stopping components (leave args empty to start all components)"))
|
||||
res = append(res, shlcmd.Info("restart", "Restarting (stop, start) components (leave args empty to restart all components)"))
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (c *configModel) GetShellCommand() []shlcmd.Command {
|
||||
var res = make([]shlcmd.Command, 0)
|
||||
|
||||
res = append(res, shlcmd.New("list", "list all components", func(buf io.Writer, err io.Writer, args []string) {
|
||||
for _, key := range c.ComponentDependencies() {
|
||||
if len(key) < 1 {
|
||||
continue
|
||||
} else if cpt := c.ComponentGet(key); cpt == nil {
|
||||
continue
|
||||
} else {
|
||||
_, _ = fmt.Fprintln(buf, key)
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
res = append(res, shlcmd.New("start", "Starting components (leave args empty to start all components)", func(buf io.Writer, err io.Writer, args []string) {
|
||||
var list []string
|
||||
if len(args) > 0 {
|
||||
list = args
|
||||
} else {
|
||||
list = c.ComponentDependencies()
|
||||
}
|
||||
|
||||
for _, key := range list {
|
||||
if len(key) < 1 {
|
||||
continue
|
||||
} else if cpt := c.ComponentGet(key); cpt == nil {
|
||||
continue
|
||||
} else {
|
||||
_, _ = fmt.Fprintln(buf, fmt.Sprintf("Starting component '%s'", key))
|
||||
e := cpt.Start()
|
||||
c.componentUpdate(key, cpt)
|
||||
if e != nil {
|
||||
_, _ = fmt.Fprintln(err, e)
|
||||
} else if !cpt.IsStarted() {
|
||||
_, _ = fmt.Fprintln(err, fmt.Errorf("component is not started"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
res = append(res, shlcmd.New("stop", "Stopping components (leave args empty to start all components)", func(buf io.Writer, err io.Writer, args []string) {
|
||||
var list []string
|
||||
if len(args) > 0 {
|
||||
list = args
|
||||
} else {
|
||||
list = c.ComponentDependencies()
|
||||
}
|
||||
|
||||
for i := len(list) - 1; i >= 0; i-- {
|
||||
key := list[i]
|
||||
|
||||
if len(key) < 1 {
|
||||
continue
|
||||
} else if cpt := c.ComponentGet(key); cpt == nil {
|
||||
continue
|
||||
} else {
|
||||
_, _ = fmt.Fprintln(buf, fmt.Sprintf("Stopping component '%s'", key))
|
||||
cpt.Stop()
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
res = append(res, shlcmd.New("restart", "Restarting (stop, start) components (leave args empty to restart all components)", func(buf io.Writer, err io.Writer, args []string) {
|
||||
var list []string
|
||||
if len(args) > 0 {
|
||||
list = args
|
||||
} else {
|
||||
list = c.ComponentDependencies()
|
||||
}
|
||||
|
||||
for i := len(list) - 1; i >= 0; i-- {
|
||||
key := list[i]
|
||||
|
||||
if len(key) < 1 {
|
||||
continue
|
||||
} else if cpt := c.ComponentGet(key); cpt == nil {
|
||||
continue
|
||||
} else {
|
||||
_, _ = fmt.Fprintln(buf, fmt.Sprintf("Stopping component '%s'", key))
|
||||
cpt.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(buf, "")
|
||||
|
||||
for _, key := range list {
|
||||
if len(key) < 1 {
|
||||
continue
|
||||
} else if cpt := c.ComponentGet(key); cpt == nil {
|
||||
continue
|
||||
} else {
|
||||
_, _ = fmt.Fprintln(buf, fmt.Sprintf("Starting component '%s'", key))
|
||||
e := cpt.Start()
|
||||
c.componentUpdate(key, cpt)
|
||||
if e != nil {
|
||||
_, _ = fmt.Fprintln(err, e)
|
||||
} else if !cpt.IsStarted() {
|
||||
_, _ = fmt.Fprintln(err, fmt.Errorf("component is not started"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
return res
|
||||
}
|
@@ -60,8 +60,9 @@ const (
|
||||
MinPkgSMTPConfig = 3050
|
||||
MinPkgStatic = 3100
|
||||
MinPkgStatus = 3200
|
||||
MinPkgVersion = 3300
|
||||
MinPkgViper = 3400
|
||||
MinPkgSocket = 3300
|
||||
MinPkgVersion = 3400
|
||||
MinPkgViper = 3500
|
||||
|
||||
MinAvailable = 4000
|
||||
|
||||
|
66
go.mod
66
go.mod
@@ -3,11 +3,11 @@ module github.com/nabbar/golib
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go-v2 v1.18.1
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.27
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.26
|
||||
github.com/aws/aws-sdk-go-v2/service/iam v1.21.0
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.36.0
|
||||
github.com/aws/aws-sdk-go-v2 v1.19.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.28
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.27
|
||||
github.com/aws/aws-sdk-go-v2/service/iam v1.21.1
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.37.0
|
||||
github.com/bits-and-blooms/bitset v1.8.0
|
||||
github.com/c-bata/go-prompt v0.2.6
|
||||
github.com/fatih/color v1.15.0
|
||||
@@ -28,11 +28,11 @@ require (
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/nats-io/jwt/v2 v2.4.1
|
||||
github.com/nats-io/nats-server/v2 v2.9.19
|
||||
github.com/nats-io/nats.go v1.27.1
|
||||
github.com/nats-io/nats-server/v2 v2.9.20
|
||||
github.com/nats-io/nats.go v1.28.0
|
||||
github.com/nutsdb/nutsdb v0.12.3
|
||||
github.com/onsi/ginkgo/v2 v2.11.0
|
||||
github.com/onsi/gomega v1.27.8
|
||||
github.com/onsi/gomega v1.27.9
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/prometheus/client_golang v1.16.0
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
@@ -42,15 +42,15 @@ require (
|
||||
github.com/spf13/viper v1.16.0
|
||||
github.com/ugorji/go/codec v1.2.11
|
||||
github.com/vbauerster/mpb/v5 v5.4.0
|
||||
github.com/xanzy/go-gitlab v0.86.0
|
||||
github.com/xanzy/go-gitlab v0.88.0
|
||||
github.com/xhit/go-simple-mail v2.2.2+incompatible
|
||||
github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df
|
||||
golang.org/x/net v0.11.0
|
||||
golang.org/x/oauth2 v0.9.0
|
||||
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0
|
||||
golang.org/x/net v0.12.0
|
||||
golang.org/x/oauth2 v0.10.0
|
||||
golang.org/x/sync v0.3.0
|
||||
golang.org/x/sys v0.10.0
|
||||
golang.org/x/term v0.9.0
|
||||
golang.org/x/term v0.10.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gorm.io/driver/clickhouse v0.5.1
|
||||
gorm.io/driver/mysql v1.5.1
|
||||
@@ -62,8 +62,8 @@ require (
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/ClickHouse/ch-go v0.57.0 // indirect
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.10.1 // indirect
|
||||
github.com/ClickHouse/ch-go v0.58.0 // indirect
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.11.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||
@@ -75,18 +75,18 @@ require (
|
||||
github.com/andybalholm/cascadia v1.3.2 // indirect
|
||||
github.com/armon/go-metrics v0.4.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.26 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.27 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.19.3 // indirect
|
||||
github.com/aws/smithy-go v1.13.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bwmarrin/snowflake v0.3.0 // indirect
|
||||
@@ -118,7 +118,7 @@ require (
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect
|
||||
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
@@ -135,7 +135,7 @@ require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.4.1 // indirect
|
||||
github.com/jackc/pgx/v5 v5.4.2 // indirect
|
||||
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
@@ -153,7 +153,7 @@ require (
|
||||
github.com/mattn/go-sqlite3 v1.14.17 // indirect
|
||||
github.com/mattn/go-tty v0.0.5 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/microsoft/go-mssqldb v1.3.0 // indirect
|
||||
github.com/microsoft/go-mssqldb v1.4.0 // indirect
|
||||
github.com/miekg/dns v1.1.55 // indirect
|
||||
github.com/minio/highwayhash v1.0.2 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
@@ -163,8 +163,8 @@ require (
|
||||
github.com/nats-io/nkeys v0.4.4 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/paulmach/orb v0.9.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||
github.com/paulmach/orb v0.10.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.18 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/term v1.2.0-beta.2 // indirect
|
||||
@@ -193,11 +193,11 @@ require (
|
||||
go.opentelemetry.io/otel v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
||||
golang.org/x/arch v0.4.0 // indirect
|
||||
golang.org/x/crypto v0.10.0 // indirect
|
||||
golang.org/x/crypto v0.11.0 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.10.0 // indirect
|
||||
golang.org/x/tools v0.11.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
|
101
httpcli/cli.go
101
httpcli/cli.go
@@ -33,12 +33,10 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
libptc "github.com/nabbar/golib/network/protocol"
|
||||
|
||||
"golang.org/x/net/http2"
|
||||
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
libptc "github.com/nabbar/golib/network/protocol"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -53,78 +51,57 @@ const (
|
||||
|
||||
type FctHttpClient func() *http.Client
|
||||
|
||||
func GetClient(serverName string) *http.Client {
|
||||
c, e := GetClientTimeout(serverName, true, 0)
|
||||
|
||||
if e != nil {
|
||||
c, _ = GetClientTimeout(serverName, false, 0)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func GetClientError(serverName string) (*http.Client, liberr.Error) {
|
||||
return GetClientTimeout(serverName, true, 0)
|
||||
}
|
||||
|
||||
func GetClientTimeout(serverName string, http2Tr bool, GlobalTimeout time.Duration) (*http.Client, liberr.Error) {
|
||||
dl := &net.Dialer{}
|
||||
|
||||
tr := &http.Transport{
|
||||
func GetTransport(DisableKeepAlive, DisableCompression, ForceHTTP2 bool) *http.Transport {
|
||||
return &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: dl.DialContext,
|
||||
DisableCompression: true,
|
||||
//nolint #staticcheck
|
||||
TLSClientConfig: libtls.GetTLSConfig(serverName),
|
||||
DialContext: nil,
|
||||
DialTLSContext: nil,
|
||||
TLSClientConfig: nil,
|
||||
DisableKeepAlives: DisableKeepAlive,
|
||||
DisableCompression: DisableCompression,
|
||||
ForceAttemptHTTP2: ForceHTTP2,
|
||||
}
|
||||
|
||||
return getclient(tr, http2Tr, GlobalTimeout)
|
||||
}
|
||||
|
||||
func GetClientCustom(tr *http.Transport, http2Tr bool, GlobalTimeout time.Duration) (*http.Client, liberr.Error) {
|
||||
return getclient(tr, http2Tr, GlobalTimeout)
|
||||
func SetTransportTLS(tr *http.Transport, tls libtls.TLSConfig, servername string) {
|
||||
tr.TLSClientConfig = tls.TlsConfig(servername)
|
||||
}
|
||||
|
||||
func GetClientTls(serverName string, tls libtls.TLSConfig, http2Tr bool, GlobalTimeout time.Duration) (*http.Client, liberr.Error) {
|
||||
dl := &net.Dialer{}
|
||||
|
||||
tr := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: dl.DialContext,
|
||||
DisableCompression: true,
|
||||
//nolint #staticcheck
|
||||
TLSClientConfig: tls.TlsConfig(serverName),
|
||||
}
|
||||
|
||||
return getclient(tr, http2Tr, GlobalTimeout)
|
||||
func SetTransportProxy(tr *http.Transport, proxyUrl *url.URL) {
|
||||
tr.Proxy = http.ProxyURL(proxyUrl)
|
||||
}
|
||||
|
||||
func GetClientTlsForceIp(netw libptc.NetworkProtocol, ip string, serverName string, tls libtls.TLSConfig, http2Tr bool, GlobalTimeout time.Duration) (*http.Client, liberr.Error) {
|
||||
u := &url.URL{
|
||||
Host: ip,
|
||||
}
|
||||
func SetTransportDial(tr *http.Transport, forceIp bool, netw libptc.NetworkProtocol, ip, local string) {
|
||||
var (
|
||||
fctDial func(ctx context.Context, network, address string) (net.Conn, error)
|
||||
)
|
||||
|
||||
fctDial := func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
dl := &net.Dialer{
|
||||
LocalAddr: &net.TCPAddr{
|
||||
IP: net.ParseIP(u.Hostname()),
|
||||
},
|
||||
if forceIp && len(local) > 0 {
|
||||
u := &url.URL{
|
||||
Host: local,
|
||||
}
|
||||
return dl.DialContext(ctx, netw.Code(), ip)
|
||||
fctDial = func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
dl := &net.Dialer{
|
||||
LocalAddr: &net.TCPAddr{
|
||||
IP: net.ParseIP(u.Hostname()),
|
||||
},
|
||||
}
|
||||
return dl.DialContext(ctx, netw.Code(), ip)
|
||||
}
|
||||
} else if forceIp {
|
||||
fctDial = func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
dl := &net.Dialer{}
|
||||
return dl.DialContext(ctx, netw.Code(), ip)
|
||||
}
|
||||
} else {
|
||||
dl := &net.Dialer{}
|
||||
fctDial = dl.DialContext
|
||||
}
|
||||
|
||||
tr := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: fctDial,
|
||||
DisableCompression: true,
|
||||
//nolint #staticcheck
|
||||
TLSClientConfig: tls.TlsConfig(serverName),
|
||||
}
|
||||
|
||||
return getclient(tr, http2Tr, GlobalTimeout)
|
||||
tr.DialContext = fctDial
|
||||
}
|
||||
|
||||
func getclient(tr *http.Transport, http2Tr bool, GlobalTimeout time.Duration) (*http.Client, liberr.Error) {
|
||||
func GetClient(tr *http.Transport, http2Tr bool, GlobalTimeout time.Duration) (*http.Client, liberr.Error) {
|
||||
if http2Tr {
|
||||
if e := http2.ConfigureTransport(tr); e != nil {
|
||||
return nil, ErrorClientTransportHttp2.ErrorParent(e)
|
||||
|
@@ -29,6 +29,8 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
libptc "github.com/nabbar/golib/network/protocol"
|
||||
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
"github.com/nabbar/golib/httpcli"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
@@ -59,7 +61,7 @@ var _ = Describe("HttpCli", func() {
|
||||
},
|
||||
ForceIP: httpcli.OptionForceIP{
|
||||
Enable: true,
|
||||
Net: "tcp",
|
||||
Net: libptc.NetworkTCP,
|
||||
IP: "127.0.0.1:8080",
|
||||
},
|
||||
}
|
||||
|
@@ -31,23 +31,22 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
libptc "github.com/nabbar/golib/network/protocol"
|
||||
|
||||
libval "github.com/go-playground/validator/v10"
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
cmptls "github.com/nabbar/golib/config/components/tls"
|
||||
cfgcst "github.com/nabbar/golib/config/const"
|
||||
|
||||
libval "github.com/go-playground/validator/v10"
|
||||
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
libptc "github.com/nabbar/golib/network/protocol"
|
||||
)
|
||||
|
||||
type OptionForceIP struct {
|
||||
Enable bool `json:"enable" yaml:"enable" toml:"enable" mapstructure:"enable"`
|
||||
Net string `json:"net,omitempty" yaml:"net,omitempty" toml:"net,omitempty" mapstructure:"net,omitempty"`
|
||||
IP string `json:"ip,omitempty" yaml:"ip,omitempty" toml:"ip,omitempty" mapstructure:"ip,omitempty"`
|
||||
Enable bool `json:"enable" yaml:"enable" toml:"enable" mapstructure:"enable"`
|
||||
Net libptc.NetworkProtocol `json:"net,omitempty" yaml:"net,omitempty" toml:"net,omitempty" mapstructure:"net,omitempty"`
|
||||
IP string `json:"ip,omitempty" yaml:"ip,omitempty" toml:"ip,omitempty" mapstructure:"ip,omitempty"`
|
||||
Local string `json:"local,omitempty" yaml:"local,omitempty" toml:"local,omitempty" mapstructure:"local,omitempty"`
|
||||
}
|
||||
|
||||
type OptionTLS struct {
|
||||
@@ -55,11 +54,19 @@ type OptionTLS struct {
|
||||
Config libtls.Config `json:"tls" yaml:"tls" toml:"tls" mapstructure:"tls"`
|
||||
}
|
||||
|
||||
type OptionProxy struct {
|
||||
Enable bool `json:"enable" yaml:"enable" toml:"enable" mapstructure:"enable"`
|
||||
Endpoint *url.URL `json:"endpoint" yaml:"endpoint" toml:"endpoint" mapstructure:"endpoint"`
|
||||
Username string `json:"username" yaml:"username" toml:"username" mapstructure:"username"`
|
||||
Password string `json:"password" yaml:"password" toml:"password" mapstructure:"password"`
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
Timeout time.Duration `json:"timeout" yaml:"timeout" toml:"timeout" mapstructure:"timeout"`
|
||||
Http2 bool `json:"http2" yaml:"http2" toml:"http2" mapstructure:"http2"`
|
||||
TLS OptionTLS `json:"tls" yaml:"tls" toml:"tls" mapstructure:"tls"`
|
||||
ForceIP OptionForceIP `json:"force_ip" yaml:"force_ip" toml:"force_ip" mapstructure:"force_ip"`
|
||||
Proxy OptionProxy `json:"proxy" yaml:"proxy" toml:"proxy" mapstructure:"proxy"`
|
||||
}
|
||||
|
||||
func DefaultConfig(indent string) []byte {
|
||||
@@ -72,7 +79,14 @@ func DefaultConfig(indent string) []byte {
|
||||
"force_ip": {
|
||||
"enable": false,
|
||||
"net":"tcp",
|
||||
"ip":"127.0.0.1:8080"
|
||||
"ip":"127.0.0.1:8080",
|
||||
"local":"127.0.0.1"
|
||||
},
|
||||
"proxy": {
|
||||
"enable": false,
|
||||
"endpoint":"http://example.com",
|
||||
"username":"example",
|
||||
"password":"example"
|
||||
}
|
||||
}`)
|
||||
)
|
||||
@@ -113,11 +127,47 @@ func (o Options) GetClient(def libtls.TLSConfig, servername string) (*http.Clien
|
||||
tls = t
|
||||
}
|
||||
|
||||
if o.ForceIP.Enable {
|
||||
return GetClientTlsForceIp(libptc.Parse(o.ForceIP.Net), o.ForceIP.IP, servername, tls, o.Http2, o.Timeout)
|
||||
} else {
|
||||
return GetClientTls(servername, tls, o.Http2, o.Timeout)
|
||||
var tr *http.Transport
|
||||
|
||||
tr = GetTransport(false, false, o.Http2)
|
||||
SetTransportTLS(tr, tls, "")
|
||||
SetTransportDial(tr, o.ForceIP.Enable, o.ForceIP.Net, o.ForceIP.IP, o.ForceIP.Local)
|
||||
|
||||
if o.Proxy.Enable && o.Proxy.Endpoint != nil {
|
||||
var edp *url.URL
|
||||
|
||||
edp = &url.URL{
|
||||
Scheme: o.Proxy.Endpoint.Scheme,
|
||||
Opaque: o.Proxy.Endpoint.Opaque,
|
||||
User: nil,
|
||||
Host: o.Proxy.Endpoint.Host,
|
||||
Path: o.Proxy.Endpoint.Path,
|
||||
RawPath: o.Proxy.Endpoint.RawPath,
|
||||
OmitHost: o.Proxy.Endpoint.OmitHost,
|
||||
ForceQuery: o.Proxy.Endpoint.ForceQuery,
|
||||
RawQuery: o.Proxy.Endpoint.RawQuery,
|
||||
Fragment: o.Proxy.Endpoint.Fragment,
|
||||
RawFragment: o.Proxy.Endpoint.RawFragment,
|
||||
}
|
||||
|
||||
if len(o.Proxy.Password) > 0 {
|
||||
edp.User = url.UserPassword(o.Proxy.Username, o.Proxy.Password)
|
||||
} else if len(o.Proxy.Username) > 0 {
|
||||
edp.User = url.User(o.Proxy.Username)
|
||||
} else if o.Proxy.Endpoint.User != nil {
|
||||
if p, k := o.Proxy.Endpoint.User.Password(); k {
|
||||
edp.User = url.UserPassword(o.Proxy.Endpoint.User.Username(), p)
|
||||
} else {
|
||||
edp.User = url.User(o.Proxy.Endpoint.User.Username())
|
||||
}
|
||||
}
|
||||
|
||||
if edp != nil && len(edp.String()) > 0 {
|
||||
SetTransportProxy(tr, edp)
|
||||
}
|
||||
}
|
||||
|
||||
return GetClient(tr, o.Http2, o.Timeout)
|
||||
}
|
||||
|
||||
func (o Options) _GetTLS(def libtls.TLSConfig) (libtls.TLSConfig, liberr.Error) {
|
||||
|
@@ -47,7 +47,7 @@ func (o *hkf) Write(p []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
func (o *hkf) Close() error {
|
||||
fmt.Printf("closing hook for log file '%s'\n", o.getFilepath())
|
||||
//fmt.Printf("closing hook for log file '%s'\n", o.getFilepath())
|
||||
|
||||
o.d.Store(closeByte)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
@@ -121,7 +121,7 @@ func (o *hkf) Run(ctx context.Context) {
|
||||
}()
|
||||
|
||||
o.prepareChan()
|
||||
fmt.Printf("starting hook for log file '%s'\n", o.getFilepath())
|
||||
//fmt.Printf("starting hook for log file '%s'\n", o.getFilepath())
|
||||
|
||||
for {
|
||||
select {
|
||||
|
@@ -61,7 +61,7 @@ func (o *hks) WriteSev(s SyslogSeverity, p []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
func (o *hks) Close() error {
|
||||
fmt.Printf("closing hook for log syslog '%s'\n", o.getSyslogInfo())
|
||||
//fmt.Printf("closing hook for log syslog '%s'\n", o.getSyslogInfo())
|
||||
|
||||
o.d.Store(closeByte)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
@@ -62,7 +62,7 @@ func (o *hks) Run(ctx context.Context) {
|
||||
}
|
||||
|
||||
o.prepareChan()
|
||||
fmt.Printf("starting hook for log syslog '%s'\n", o.getSyslogInfo())
|
||||
//fmt.Printf("starting hook for log syslog '%s'\n", o.getSyslogInfo())
|
||||
|
||||
for {
|
||||
select {
|
||||
|
@@ -37,34 +37,66 @@ import (
|
||||
)
|
||||
|
||||
func (o *logger) Debug(message string, data interface{}, args ...interface{}) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.newEntry(loglvl.DebugLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
|
||||
}
|
||||
|
||||
func (o *logger) Info(message string, data interface{}, args ...interface{}) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.newEntry(loglvl.InfoLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
|
||||
}
|
||||
|
||||
func (o *logger) Warning(message string, data interface{}, args ...interface{}) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.newEntry(loglvl.WarnLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
|
||||
}
|
||||
|
||||
func (o *logger) Error(message string, data interface{}, args ...interface{}) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.newEntry(loglvl.ErrorLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
|
||||
}
|
||||
|
||||
func (o *logger) Fatal(message string, data interface{}, args ...interface{}) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.newEntry(loglvl.FatalLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
|
||||
}
|
||||
|
||||
func (o *logger) Panic(message string, data interface{}, args ...interface{}) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.newEntry(loglvl.PanicLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
|
||||
}
|
||||
|
||||
func (o *logger) LogDetails(lvl loglvl.Level, message string, data interface{}, err []error, fields logfld.Fields, args ...interface{}) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.newEntry(lvl, fmt.Sprintf(message, args...), err, fields, data).Log()
|
||||
}
|
||||
|
||||
func (o *logger) CheckError(lvlKO, lvlOK loglvl.Level, message string, err ...error) bool {
|
||||
if o == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
ent := o.newEntry(lvlKO, message, err, nil, nil)
|
||||
return ent.Check(lvlOK)
|
||||
}
|
||||
@@ -79,21 +111,37 @@ func (o *logger) Access(remoteAddr, remoteUser string, localtime time.Time, late
|
||||
}
|
||||
|
||||
func (o *logger) newEntry(lvl loglvl.Level, message string, err []error, fields logfld.Fields, data interface{}) logent.Entry {
|
||||
if o == nil {
|
||||
return logent.New(loglvl.NilLevel)
|
||||
}
|
||||
|
||||
var (
|
||||
fct = o.getLogrus
|
||||
ent = logent.New(lvl)
|
||||
frm = o.getCaller()
|
||||
stk = o.getStack()
|
||||
fld = o.GetFields()
|
||||
)
|
||||
|
||||
if o == nil {
|
||||
return logent.New(loglvl.NilLevel)
|
||||
} else if fld != nil {
|
||||
ent.FieldSet(fld.FieldsClone(nil))
|
||||
}
|
||||
|
||||
ent.ErrorSet(err)
|
||||
ent.FieldSet(o.GetFields().FieldsClone(nil))
|
||||
ent.DataSet(data)
|
||||
ent.SetLogger(o.getLogrus)
|
||||
ent.SetEntryContext(time.Now(), o.getStack(), frm.Function, frm.File, uint64(frm.Line), message)
|
||||
ent.SetLogger(fct)
|
||||
ent.SetEntryContext(time.Now(), stk, frm.Function, frm.File, uint64(frm.Line), message)
|
||||
ent.FieldMerge(fields)
|
||||
|
||||
return ent
|
||||
}
|
||||
|
||||
func (o *logger) newEntryClean(message string) logent.Entry {
|
||||
if o == nil {
|
||||
return logent.New(loglvl.NilLevel)
|
||||
}
|
||||
|
||||
return o.newEntry(loglvl.InfoLevel, message, nil, nil, nil).SetMessageOnly(true)
|
||||
}
|
||||
|
@@ -32,9 +32,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
moninf "github.com/nabbar/golib/monitor/types"
|
||||
|
||||
monsts "github.com/nabbar/golib/monitor/status"
|
||||
moninf "github.com/nabbar/golib/monitor/types"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@@ -30,11 +30,9 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
libprm "github.com/nabbar/golib/prometheus"
|
||||
|
||||
monsts "github.com/nabbar/golib/monitor/status"
|
||||
libprm "github.com/nabbar/golib/prometheus"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
func (o *mon) RegisterMetricsName(names ...string) {
|
||||
|
@@ -29,7 +29,7 @@ package monitor
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/nabbar/golib/monitor/types"
|
||||
montps "github.com/nabbar/golib/monitor/types"
|
||||
)
|
||||
|
||||
type fctMiddleWare func(m middleWare) error
|
||||
@@ -49,7 +49,7 @@ type mdl struct {
|
||||
mdl []fctMiddleWare
|
||||
}
|
||||
|
||||
func newMiddleware(cfg *runCfg, fct types.HealthCheck) middleWare {
|
||||
func newMiddleware(cfg *runCfg, fct montps.HealthCheck) middleWare {
|
||||
o := &mdl{
|
||||
ctx: nil,
|
||||
cfg: cfg,
|
||||
|
@@ -31,13 +31,11 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
|
||||
libsrv "github.com/nabbar/golib/server"
|
||||
|
||||
libctx "github.com/nabbar/golib/context"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
montps "github.com/nabbar/golib/monitor/types"
|
||||
libprm "github.com/nabbar/golib/prometheus"
|
||||
libsrv "github.com/nabbar/golib/server"
|
||||
)
|
||||
|
||||
type Pool interface {
|
||||
|
218
monitor/pool/shell.go
Normal file
218
monitor/pool/shell.go
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* 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 pool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
monsts "github.com/nabbar/golib/monitor/status"
|
||||
shlcmd "github.com/nabbar/golib/shell/command"
|
||||
)
|
||||
|
||||
func ShellCommandInfo() []shlcmd.CommandInfo {
|
||||
var res = make([]shlcmd.CommandInfo, 0)
|
||||
|
||||
res = append(res, shlcmd.Info("list", "Print the monitors' List"))
|
||||
res = append(res, shlcmd.Info("info", "Print information about monitors (leave args empty to print info for all monitors)"))
|
||||
res = append(res, shlcmd.Info("start", "Starting monitor (leave args empty to start all monitors)"))
|
||||
res = append(res, shlcmd.Info("stop", "Stopping monitor (leave args empty to stop all monitors)"))
|
||||
res = append(res, shlcmd.Info("restart", "Restarting monitor (leave args empty to restart all monitors)"))
|
||||
res = append(res, shlcmd.Info("status", "Print status & message for monitor (leave args empty to print status of all monitors)"))
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (p *pool) GetShellCommand(ctx context.Context) []shlcmd.Command {
|
||||
var res = make([]shlcmd.Command, 0)
|
||||
|
||||
res = append(res, shlcmd.New("list", "Print the monitors' List", func(buf io.Writer, err io.Writer, args []string) {
|
||||
var list = p.MonitorList()
|
||||
|
||||
for i := 0; i < len(list); i++ {
|
||||
_, _ = fmt.Fprintln(buf, list[i])
|
||||
}
|
||||
}))
|
||||
|
||||
res = append(res, shlcmd.New("info", "Print information about monitors (leave args empty to print info for all monitors)", func(buf io.Writer, err io.Writer, args []string) {
|
||||
var list []string
|
||||
if len(args) > 0 {
|
||||
list = args
|
||||
} else {
|
||||
list = p.MonitorList()
|
||||
}
|
||||
|
||||
for i := 0; i < len(list); i++ {
|
||||
if len(list[i]) < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
m := p.MonitorGet(list[i])
|
||||
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
inf := m.InfoGet()
|
||||
_, _ = fmt.Fprintln(buf, inf.Name())
|
||||
for k, v := range inf.Info() {
|
||||
_, _ = fmt.Fprintln(buf, fmt.Sprintf("\t%s: %s", k, v))
|
||||
}
|
||||
_, _ = fmt.Fprintln(buf, "")
|
||||
}
|
||||
}))
|
||||
|
||||
res = append(res, shlcmd.New("start", "Starting monitor (leave args empty to start all monitors)", func(buf io.Writer, err io.Writer, args []string) {
|
||||
var list []string
|
||||
if len(args) > 0 {
|
||||
list = args
|
||||
} else {
|
||||
list = p.MonitorList()
|
||||
}
|
||||
|
||||
for i := 0; i < len(list); i++ {
|
||||
if len(list[i]) < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
m := p.MonitorGet(list[i])
|
||||
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(buf, fmt.Sprintf("Starting monitor '%s'", list[i]))
|
||||
if e := m.Start(ctx); e != nil {
|
||||
_, _ = fmt.Fprintln(err, e)
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(buf, fmt.Sprintf("Updating monitor '%s' on pool", list[i]))
|
||||
if e := p.MonitorSet(m); e != nil {
|
||||
_, _ = fmt.Fprintln(err, e)
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
res = append(res, shlcmd.New("stop", "Stopping monitor (leave args empty to stop all monitors)", func(buf io.Writer, err io.Writer, args []string) {
|
||||
var list []string
|
||||
if len(args) > 0 {
|
||||
list = args
|
||||
} else {
|
||||
list = p.MonitorList()
|
||||
}
|
||||
|
||||
for i := 0; i < len(list); i++ {
|
||||
if len(list[i]) < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
m := p.MonitorGet(list[i])
|
||||
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(buf, fmt.Sprintf("Stopping monitor '%s'", list[i]))
|
||||
if e := m.Stop(ctx); e != nil {
|
||||
_, _ = fmt.Fprintln(err, e)
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(buf, fmt.Sprintf("Updating monitor '%s' on pool", list[i]))
|
||||
if e := p.MonitorSet(m); e != nil {
|
||||
_, _ = fmt.Fprintln(err, e)
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
res = append(res, shlcmd.New("restart", "Restarting monitor (leave args empty to restart all monitors)", func(buf io.Writer, err io.Writer, args []string) {
|
||||
var list []string
|
||||
if len(args) > 0 {
|
||||
list = args
|
||||
} else {
|
||||
list = p.MonitorList()
|
||||
}
|
||||
|
||||
for i := 0; i < len(list); i++ {
|
||||
if len(list[i]) < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
m := p.MonitorGet(list[i])
|
||||
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(buf, fmt.Sprintf("Stopping monitor '%s'", list[i]))
|
||||
if e := m.Stop(ctx); e != nil {
|
||||
_, _ = fmt.Fprintln(err, e)
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(buf, fmt.Sprintf("Starting monitor '%s'", list[i]))
|
||||
if e := m.Start(ctx); e != nil {
|
||||
_, _ = fmt.Fprintln(err, e)
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(buf, fmt.Sprintf("Updating monitor '%s' on pool", list[i]))
|
||||
if e := p.MonitorSet(m); e != nil {
|
||||
_, _ = fmt.Fprintln(err, e)
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
res = append(res, shlcmd.New("status", "Print status & message for monitor (leave args empty to print status of all monitors)", func(buf io.Writer, err io.Writer, args []string) {
|
||||
var list []string
|
||||
if len(args) > 0 {
|
||||
list = args
|
||||
} else {
|
||||
list = p.MonitorList()
|
||||
}
|
||||
|
||||
for i := 0; i < len(list); i++ {
|
||||
if len(list[i]) < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
m := p.MonitorGet(list[i])
|
||||
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
s := m.Status()
|
||||
|
||||
if s == monsts.OK {
|
||||
_, _ = fmt.Fprintln(buf, fmt.Sprintf("%s - %s", s.String(), list[i]))
|
||||
} else {
|
||||
_, _ = fmt.Fprintln(err, fmt.Sprintf("%s - %s: %s", s.String(), list[i], m.Message()))
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
return res
|
||||
}
|
@@ -32,11 +32,9 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
|
||||
libctx "github.com/nabbar/golib/context"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
monsts "github.com/nabbar/golib/monitor/status"
|
||||
libprm "github.com/nabbar/golib/prometheus"
|
||||
libsrv "github.com/nabbar/golib/server"
|
||||
|
@@ -27,20 +27,16 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
|
||||
shlcmd "github.com/nabbar/golib/shell/command"
|
||||
)
|
||||
|
||||
type FuncPool func() Pool
|
||||
|
||||
type PoolStatus interface {
|
||||
encoding.TextMarshaler
|
||||
json.Marshaler
|
||||
}
|
||||
|
||||
type Pool interface {
|
||||
PoolStatus
|
||||
|
||||
type PoolManage interface {
|
||||
MonitorAdd(mon Monitor) error
|
||||
MonitorGet(name string) Monitor
|
||||
MonitorSet(mon Monitor) error
|
||||
@@ -48,3 +44,18 @@ type Pool interface {
|
||||
MonitorList() []string
|
||||
MonitorWalk(fct func(name string, val Monitor) bool, validName ...string)
|
||||
}
|
||||
|
||||
type PoolStatus interface {
|
||||
encoding.TextMarshaler
|
||||
json.Marshaler
|
||||
PoolManage
|
||||
}
|
||||
|
||||
type PoolShell interface {
|
||||
GetShellCommand(ctx context.Context) []shlcmd.Command
|
||||
}
|
||||
|
||||
type Pool interface {
|
||||
PoolStatus
|
||||
PoolShell
|
||||
}
|
||||
|
@@ -43,6 +43,9 @@ const (
|
||||
NetworkUDP
|
||||
NetworkUDP4
|
||||
NetworkUDP6
|
||||
NetworkIP
|
||||
NetworkIP4
|
||||
NetworkIP6
|
||||
)
|
||||
|
||||
func Parse(str string) NetworkProtocol {
|
||||
@@ -66,7 +69,7 @@ func ParseBytes(p []byte) NetworkProtocol {
|
||||
return Parse(string(p))
|
||||
}
|
||||
|
||||
func SizeFromInt64(val int64) NetworkProtocol {
|
||||
func ParseInt64(val int64) NetworkProtocol {
|
||||
if val > int64(math.MaxUint8) {
|
||||
return NetworkProtocol(math.MaxUint8)
|
||||
}
|
||||
|
@@ -27,7 +27,12 @@
|
||||
|
||||
package protocol
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
libmap "github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
func (n NetworkProtocol) String() string {
|
||||
switch n {
|
||||
@@ -45,6 +50,12 @@ func (n NetworkProtocol) String() string {
|
||||
return "udp4"
|
||||
case NetworkUDP6:
|
||||
return "udp6"
|
||||
case NetworkIP:
|
||||
return "ip"
|
||||
case NetworkIP4:
|
||||
return "ip4"
|
||||
case NetworkIP6:
|
||||
return "ip6"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
@@ -53,3 +64,32 @@ func (n NetworkProtocol) String() string {
|
||||
func (n NetworkProtocol) Code() string {
|
||||
return strings.ToLower(n.String())
|
||||
}
|
||||
|
||||
func ViperDecoderHook() libmap.DecodeHookFuncType {
|
||||
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
|
||||
var (
|
||||
z = NetworkProtocol(0)
|
||||
t string
|
||||
k bool
|
||||
)
|
||||
|
||||
// Check if the data type matches the expected one
|
||||
if from.Kind() != reflect.String {
|
||||
return data, nil
|
||||
} else if t, k = data.(string); !k {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Check if the target type matches the expected one
|
||||
if to != reflect.TypeOf(z) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Format/decode/parse the data and return the new value
|
||||
if e := z.unmarshall([]byte(t)); e != nil {
|
||||
return nil, e
|
||||
} else {
|
||||
return z, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ import (
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
montps "github.com/nabbar/golib/monitor/types"
|
||||
libsh "github.com/nabbar/golib/shell"
|
||||
shlcmd "github.com/nabbar/golib/shell/command"
|
||||
libver "github.com/nabbar/golib/version"
|
||||
)
|
||||
|
||||
@@ -66,7 +66,7 @@ type NutsDB interface {
|
||||
|
||||
Cluster() libclu.Cluster
|
||||
Client(ctx context.Context, tickSync time.Duration) Client
|
||||
ShellCommand(ctx func() context.Context, tickSync time.Duration) []libsh.Command
|
||||
ShellCommand(ctx func() context.Context, tickSync time.Duration) []shlcmd.Command
|
||||
}
|
||||
|
||||
func New(c Config) NutsDB {
|
||||
|
@@ -40,7 +40,7 @@ import (
|
||||
libclu "github.com/nabbar/golib/cluster"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
libsh "github.com/nabbar/golib/shell"
|
||||
shlcmd "github.com/nabbar/golib/shell/command"
|
||||
)
|
||||
|
||||
type ndb struct {
|
||||
@@ -265,9 +265,9 @@ func (n *ndb) Client(ctx context.Context, tickSync time.Duration) Client {
|
||||
}
|
||||
}
|
||||
|
||||
func (n *ndb) ShellCommand(ctx func() context.Context, tickSync time.Duration) []libsh.Command {
|
||||
func (n *ndb) ShellCommand(ctx func() context.Context, tickSync time.Duration) []shlcmd.Command {
|
||||
var (
|
||||
res = make([]libsh.Command, 0)
|
||||
res = make([]shlcmd.Command, 0)
|
||||
cli func() Client
|
||||
)
|
||||
|
||||
|
@@ -35,7 +35,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
libsh "github.com/nabbar/golib/shell"
|
||||
shlcmd "github.com/nabbar/golib/shell/command"
|
||||
"github.com/nutsdb/nutsdb"
|
||||
"github.com/nutsdb/nutsdb/ds/zset"
|
||||
)
|
||||
@@ -45,7 +45,7 @@ type shellCommand struct {
|
||||
c func() Client
|
||||
}
|
||||
|
||||
func newShellCommand(code CmdCode, cli func() Client) libsh.Command {
|
||||
func newShellCommand(code CmdCode, cli func() Client) shlcmd.Command {
|
||||
if code == CmdUnknown {
|
||||
return nil
|
||||
}
|
||||
|
58
shell/command/interface.go
Normal file
58
shell/command/interface.go
Normal file
@@ -0,0 +1,58 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2021 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 command
|
||||
|
||||
import "io"
|
||||
|
||||
type FuncRun func(buf io.Writer, err io.Writer, args []string)
|
||||
|
||||
type CommandInfo interface {
|
||||
Name() string
|
||||
Describe() string
|
||||
}
|
||||
|
||||
type Command interface {
|
||||
CommandInfo
|
||||
Run(buf io.Writer, err io.Writer, args []string)
|
||||
}
|
||||
|
||||
func New(name, desc string, fct FuncRun) Command {
|
||||
return &model{
|
||||
n: name,
|
||||
d: desc,
|
||||
r: fct,
|
||||
}
|
||||
}
|
||||
|
||||
func Info(name, desc string) CommandInfo {
|
||||
return &model{
|
||||
n: name,
|
||||
d: desc,
|
||||
r: nil,
|
||||
}
|
||||
}
|
62
shell/command/model.go
Normal file
62
shell/command/model.go
Normal file
@@ -0,0 +1,62 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2021 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 command
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type model struct {
|
||||
n string
|
||||
d string
|
||||
r FuncRun
|
||||
}
|
||||
|
||||
func (o *model) Name() string {
|
||||
if o == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return o.n
|
||||
}
|
||||
|
||||
func (o *model) Describe() string {
|
||||
if o == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return o.d
|
||||
}
|
||||
|
||||
func (o *model) Run(buf io.Writer, err io.Writer, args []string) {
|
||||
if o == nil || o.r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.r(buf, err, args)
|
||||
}
|
@@ -33,12 +33,13 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/c-bata/go-prompt"
|
||||
libshl "github.com/c-bata/go-prompt"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
shlcmd "github.com/nabbar/golib/shell/command"
|
||||
)
|
||||
|
||||
func (s *shell) RunPrompt(out, err io.Writer, opt ...prompt.Option) {
|
||||
p := prompt.New(
|
||||
func (s *shell) RunPrompt(out, err io.Writer, opt ...libshl.Option) {
|
||||
p := libshl.New(
|
||||
func(inputLine string) {
|
||||
if out == nil {
|
||||
out = os.Stdout
|
||||
@@ -59,11 +60,11 @@ func (s *shell) RunPrompt(out, err io.Writer, opt ...prompt.Option) {
|
||||
|
||||
s.Run(out, err, strings.Fields(inputLine))
|
||||
},
|
||||
func(document prompt.Document) []prompt.Suggest {
|
||||
var res = make([]prompt.Suggest, 0)
|
||||
func(document libshl.Document) []libshl.Suggest {
|
||||
var res = make([]libshl.Suggest, 0)
|
||||
|
||||
_ = s.Walk(func(name string, item Command) (Command, liberr.Error) {
|
||||
res = append(res, prompt.Suggest{
|
||||
_ = s.Walk(func(name string, item shlcmd.Command) (shlcmd.Command, liberr.Error) {
|
||||
res = append(res, libshl.Suggest{
|
||||
Text: name,
|
||||
Description: item.Describe(),
|
||||
})
|
||||
|
@@ -30,30 +30,24 @@ package shell
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/c-bata/go-prompt"
|
||||
|
||||
libshl "github.com/c-bata/go-prompt"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
shlcmd "github.com/nabbar/golib/shell/command"
|
||||
)
|
||||
|
||||
type Command interface {
|
||||
Name() string
|
||||
Describe() string
|
||||
Run(buf io.Writer, err io.Writer, args []string)
|
||||
}
|
||||
|
||||
type Shell interface {
|
||||
Run(buf io.Writer, err io.Writer, args []string)
|
||||
Add(prefix string, cmd ...Command)
|
||||
Get(cmd string) []Command
|
||||
Add(prefix string, cmd ...shlcmd.Command)
|
||||
Get(cmd string) []shlcmd.Command
|
||||
Desc(cmd string) map[string]string
|
||||
Walk(fct func(name string, item Command) (Command, liberr.Error)) liberr.Error
|
||||
Walk(fct func(name string, item shlcmd.Command) (shlcmd.Command, liberr.Error)) liberr.Error
|
||||
|
||||
//go prompt
|
||||
RunPrompt(out, err io.Writer, opt ...prompt.Option)
|
||||
RunPrompt(out, err io.Writer, opt ...libshl.Option)
|
||||
}
|
||||
|
||||
func New() Shell {
|
||||
return &shell{
|
||||
c: make(map[string]Command),
|
||||
c: make(map[string]shlcmd.Command),
|
||||
}
|
||||
}
|
||||
|
@@ -32,10 +32,11 @@ import (
|
||||
"io"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
shlcmd "github.com/nabbar/golib/shell/command"
|
||||
)
|
||||
|
||||
type shell struct {
|
||||
c map[string]Command
|
||||
c map[string]shlcmd.Command
|
||||
}
|
||||
|
||||
func (s *shell) Run(buf io.Writer, err io.Writer, args []string) {
|
||||
@@ -55,7 +56,7 @@ func (s *shell) Run(buf io.Writer, err io.Writer, args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *shell) Walk(fct func(name string, item Command) (Command, liberr.Error)) liberr.Error {
|
||||
func (s *shell) Walk(fct func(name string, item shlcmd.Command) (shlcmd.Command, liberr.Error)) liberr.Error {
|
||||
if fct == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -77,9 +78,9 @@ func (s *shell) Walk(fct func(name string, item Command) (Command, liberr.Error)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *shell) Add(prefix string, cmd ...Command) {
|
||||
func (s *shell) Add(prefix string, cmd ...shlcmd.Command) {
|
||||
if len(s.c) == 0 {
|
||||
s.c = make(map[string]Command)
|
||||
s.c = make(map[string]shlcmd.Command)
|
||||
}
|
||||
|
||||
for i := 0; i < len(cmd); i++ {
|
||||
@@ -98,10 +99,10 @@ func (s *shell) Add(prefix string, cmd ...Command) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *shell) Get(cmd string) []Command {
|
||||
var res = make([]Command, 0)
|
||||
func (s *shell) Get(cmd string) []shlcmd.Command {
|
||||
var res = make([]shlcmd.Command, 0)
|
||||
|
||||
_ = s.Walk(func(name string, item Command) (Command, liberr.Error) {
|
||||
_ = s.Walk(func(name string, item shlcmd.Command) (shlcmd.Command, liberr.Error) {
|
||||
if len(cmd) == 0 || name == cmd {
|
||||
res = append(res, item)
|
||||
}
|
||||
@@ -115,7 +116,7 @@ func (s *shell) Get(cmd string) []Command {
|
||||
func (s *shell) Desc(cmd string) map[string]string {
|
||||
var res = make(map[string]string)
|
||||
|
||||
_ = s.Walk(func(name string, item Command) (Command, liberr.Error) {
|
||||
_ = s.Walk(func(name string, item shlcmd.Command) (shlcmd.Command, liberr.Error) {
|
||||
if len(cmd) == 0 || name == cmd {
|
||||
res[name] = item.Describe()
|
||||
}
|
||||
|
27
socket/client/ignore.go
Normal file
27
socket/client/ignore.go
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 client
|
55
socket/client/interface.go
Normal file
55
socket/client/interface.go
Normal file
@@ -0,0 +1,55 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
* 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 client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"sync/atomic"
|
||||
|
||||
libsck "github.com/nabbar/golib/socket"
|
||||
)
|
||||
|
||||
type Client interface {
|
||||
RegisterFuncError(f libsck.FuncError)
|
||||
Connection(ctx context.Context, request io.Reader) (io.Reader, error)
|
||||
}
|
||||
|
||||
func New(unixfile string) Client {
|
||||
u := new(atomic.Value)
|
||||
u.Store(unixfile)
|
||||
|
||||
return &clt{
|
||||
u: u,
|
||||
f: new(atomic.Value),
|
||||
tr: new(atomic.Value),
|
||||
tw: new(atomic.Value),
|
||||
}
|
||||
}
|
126
socket/client/model.go
Normal file
126
socket/client/model.go
Normal file
@@ -0,0 +1,126 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
* 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 client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
|
||||
libsck "github.com/nabbar/golib/socket"
|
||||
)
|
||||
|
||||
type clt struct {
|
||||
u *atomic.Value // unixfile
|
||||
f *atomic.Value // function error
|
||||
tr *atomic.Value // connection read timeout
|
||||
tw *atomic.Value // connection write timeout
|
||||
}
|
||||
|
||||
func (o *clt) RegisterFuncError(f libsck.FuncError) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.f.Store(f)
|
||||
}
|
||||
|
||||
func (o *clt) fctError(e error) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
v := o.f.Load()
|
||||
if v != nil {
|
||||
v.(libsck.FuncError)(e)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *clt) dial(ctx context.Context) (net.Conn, error) {
|
||||
if o == nil {
|
||||
return nil, fmt.Errorf("invalid instance")
|
||||
}
|
||||
|
||||
v := o.u.Load()
|
||||
if v == nil {
|
||||
return nil, fmt.Errorf("invalid unix file")
|
||||
} else if _, e := os.Stat(v.(string)); e != nil {
|
||||
return nil, e
|
||||
} else {
|
||||
d := net.Dialer{}
|
||||
return d.DialContext(ctx, "unix", v.(string))
|
||||
}
|
||||
}
|
||||
|
||||
func (o *clt) Connection(ctx context.Context, request io.Reader) (io.Reader, error) {
|
||||
if o == nil {
|
||||
return nil, fmt.Errorf("invalid instance")
|
||||
}
|
||||
|
||||
var (
|
||||
e error
|
||||
|
||||
cnn net.Conn
|
||||
)
|
||||
|
||||
if cnn, e = o.dial(ctx); e != nil {
|
||||
o.fctError(e)
|
||||
return nil, e
|
||||
}
|
||||
|
||||
defer cnn.Close()
|
||||
|
||||
if request != nil {
|
||||
if _, e = io.Copy(cnn, request); e != nil {
|
||||
o.fctError(e)
|
||||
return nil, e
|
||||
}
|
||||
}
|
||||
|
||||
if e = cnn.(*net.UnixConn).CloseWrite(); e != nil {
|
||||
o.fctError(e)
|
||||
return nil, e
|
||||
}
|
||||
|
||||
var buf = bytes.NewBuffer(make([]byte, 0, 32*1024))
|
||||
|
||||
if _, e = io.Copy(buf, cnn); e != nil {
|
||||
o.fctError(e)
|
||||
return nil, e
|
||||
}
|
||||
|
||||
_ = cnn.(*net.UnixConn).CloseRead()
|
||||
|
||||
return buf, nil
|
||||
}
|
27
socket/ignore.go
Normal file
27
socket/ignore.go
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 socket
|
80
socket/inerface.go
Normal file
80
socket/inerface.go
Normal file
@@ -0,0 +1,80 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
* 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 socket
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type FuncError func(e error)
|
||||
type Handler func(request io.Reader, response io.Writer)
|
||||
|
||||
type Server interface {
|
||||
RegisterFuncError(f FuncError)
|
||||
SetReadTimeout(d time.Duration)
|
||||
SetWriteTimeout(d time.Duration)
|
||||
|
||||
Listen(ctx context.Context, unixFile string, perm os.FileMode)
|
||||
Shutdown()
|
||||
Done() <-chan struct{}
|
||||
}
|
||||
|
||||
func New(h Handler, sizeBuffRead, sizeBuffWrite int32) Server {
|
||||
c := new(atomic.Value)
|
||||
c.Store(make(chan []byte))
|
||||
|
||||
s := new(atomic.Value)
|
||||
s.Store(make(chan struct{}))
|
||||
|
||||
f := new(atomic.Value)
|
||||
f.Store(h)
|
||||
|
||||
sr := new(atomic.Int32)
|
||||
sr.Store(sizeBuffRead)
|
||||
|
||||
sw := new(atomic.Int32)
|
||||
sw.Store(sizeBuffWrite)
|
||||
|
||||
return &srv{
|
||||
l: nil,
|
||||
h: f,
|
||||
c: c,
|
||||
s: s,
|
||||
f: new(atomic.Value),
|
||||
tr: new(atomic.Value),
|
||||
tw: new(atomic.Value),
|
||||
sr: sr,
|
||||
sw: sw,
|
||||
}
|
||||
}
|
202
socket/listener.go
Normal file
202
socket/listener.go
Normal file
@@ -0,0 +1,202 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
* 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 socket
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (o *srv) timeoutRead() time.Time {
|
||||
v := o.tr.Load()
|
||||
if v != nil {
|
||||
return time.Now().Add(v.(time.Duration))
|
||||
}
|
||||
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func (o *srv) timeoutWrite() time.Time {
|
||||
v := o.tw.Load()
|
||||
if v != nil {
|
||||
return time.Now().Add(v.(time.Duration))
|
||||
}
|
||||
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func (o *srv) buffRead() *bytes.Buffer {
|
||||
v := o.sr.Load()
|
||||
if v > 0 {
|
||||
return bytes.NewBuffer(make([]byte, 0, int(v)))
|
||||
}
|
||||
|
||||
return bytes.NewBuffer(make([]byte, 0, 32*1024))
|
||||
}
|
||||
|
||||
func (o *srv) buffWrite() *bytes.Buffer {
|
||||
v := o.sw.Load()
|
||||
if v > 0 {
|
||||
return bytes.NewBuffer(make([]byte, 0, int(v)))
|
||||
}
|
||||
|
||||
return bytes.NewBuffer(make([]byte, 0, 32*1024))
|
||||
}
|
||||
|
||||
func (o *srv) checkFile(unixFile string) (string, error) {
|
||||
if len(unixFile) < 1 {
|
||||
return unixFile, fmt.Errorf("missing socket file path")
|
||||
} else {
|
||||
unixFile = filepath.Join(filepath.Dir(unixFile), filepath.Base(unixFile))
|
||||
}
|
||||
|
||||
if _, e := os.Stat(unixFile); e != nil && !errors.Is(e, os.ErrNotExist) {
|
||||
return unixFile, e
|
||||
} else if e != nil {
|
||||
return unixFile, nil
|
||||
} else if e = os.Remove(unixFile); e != nil {
|
||||
return unixFile, e
|
||||
}
|
||||
|
||||
return unixFile, nil
|
||||
}
|
||||
|
||||
func (o *srv) Listen(ctx context.Context, unixFile string, perm os.FileMode) {
|
||||
var (
|
||||
e error
|
||||
i fs.FileInfo
|
||||
l net.Listener
|
||||
p = syscall.Umask(int(perm))
|
||||
)
|
||||
|
||||
if unixFile, e = o.checkFile(unixFile); e != nil {
|
||||
o.fctError(e)
|
||||
return
|
||||
} else if l, e = net.Listen("unix", unixFile); e != nil {
|
||||
o.fctError(e)
|
||||
return
|
||||
} else if i, e = os.Stat(unixFile); e != nil {
|
||||
o.fctError(e)
|
||||
return
|
||||
}
|
||||
|
||||
syscall.Umask(p)
|
||||
|
||||
var fctClose = func() {
|
||||
if l != nil {
|
||||
o.fctError(l.Close())
|
||||
}
|
||||
|
||||
if i, e = os.Stat(unixFile); e == nil {
|
||||
o.fctError(os.Remove(unixFile))
|
||||
}
|
||||
}
|
||||
|
||||
defer fctClose()
|
||||
|
||||
if i.Mode() != perm {
|
||||
if e = os.Chmod(unixFile, perm); e != nil {
|
||||
o.fctError(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Accept new connection or stop if context or shutdown trigger
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-o.Done():
|
||||
return
|
||||
default:
|
||||
// Accept an incoming connection.
|
||||
if l == nil {
|
||||
return
|
||||
} else if co, ce := l.Accept(); ce != nil {
|
||||
o.fctError(ce)
|
||||
} else {
|
||||
go o.Conn(co)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *srv) Conn(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
var (
|
||||
tr = o.timeoutRead()
|
||||
tw = o.timeoutWrite()
|
||||
br = o.buffRead()
|
||||
bw = o.buffWrite()
|
||||
)
|
||||
|
||||
if !tr.IsZero() {
|
||||
if e := conn.SetReadDeadline(tr); e != nil {
|
||||
o.fctError(e)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !tw.IsZero() {
|
||||
if e := conn.SetReadDeadline(tw); e != nil {
|
||||
o.fctError(e)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if _, e := io.Copy(br, conn); e != nil {
|
||||
o.fctError(e)
|
||||
return
|
||||
} else if e = conn.(*net.UnixConn).CloseRead(); e != nil {
|
||||
o.fctError(e)
|
||||
return
|
||||
}
|
||||
|
||||
if h := o.handler(); h != nil {
|
||||
h(br, bw)
|
||||
}
|
||||
|
||||
if _, e := io.Copy(conn, bw); e != nil {
|
||||
o.fctError(e)
|
||||
return
|
||||
} else if e = conn.(*net.UnixConn).CloseWrite(); e != nil {
|
||||
o.fctError(e)
|
||||
return
|
||||
}
|
||||
}
|
132
socket/model.go
Normal file
132
socket/model.go
Normal file
@@ -0,0 +1,132 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
* 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 socket
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTimeoutRead = time.Second
|
||||
defaultTimeoutWrite = 5 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
closedChanStruct chan struct{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
closedChanStruct = make(chan struct{})
|
||||
close(closedChanStruct)
|
||||
}
|
||||
|
||||
type srv struct {
|
||||
l net.Listener
|
||||
|
||||
h *atomic.Value // handler
|
||||
c *atomic.Value // chan []byte
|
||||
s *atomic.Value // chan struct{}
|
||||
f *atomic.Value // function error
|
||||
|
||||
tr *atomic.Value // connection read timeout
|
||||
tw *atomic.Value // connection write timeout
|
||||
sr *atomic.Int32 // read buffer size
|
||||
sw *atomic.Int32 // write buffer size
|
||||
}
|
||||
|
||||
func (o *srv) Done() <-chan struct{} {
|
||||
s := o.s.Load()
|
||||
if s != nil {
|
||||
return s.(chan struct{})
|
||||
}
|
||||
|
||||
return closedChanStruct
|
||||
}
|
||||
|
||||
func (o *srv) Shutdown() {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
s := o.s.Load()
|
||||
if s != nil {
|
||||
o.s.Store(nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *srv) RegisterFuncError(f FuncError) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.f.Store(f)
|
||||
}
|
||||
|
||||
func (o *srv) SetReadTimeout(d time.Duration) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.tr.Store(d)
|
||||
}
|
||||
|
||||
func (o *srv) SetWriteTimeout(d time.Duration) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.tw.Store(d)
|
||||
}
|
||||
|
||||
func (o *srv) fctError(e error) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
v := o.f.Load()
|
||||
if v != nil {
|
||||
v.(FuncError)(e)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *srv) handler() Handler {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
v := o.h.Load()
|
||||
if v != nil {
|
||||
return v.(Handler)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@@ -32,7 +32,9 @@ import (
|
||||
|
||||
libval "github.com/go-playground/validator/v10"
|
||||
monsts "github.com/nabbar/golib/monitor/status"
|
||||
"golang.org/x/exp/slices"
|
||||
stsctr "github.com/nabbar/golib/status/control"
|
||||
stslmd "github.com/nabbar/golib/status/listmandatory"
|
||||
stsmdt "github.com/nabbar/golib/status/mandatory"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -42,7 +44,12 @@ const (
|
||||
|
||||
type Config struct {
|
||||
ReturnCode map[monsts.Status]int
|
||||
MandatoryComponent []string
|
||||
MandatoryComponent stslmd.ListMandatory
|
||||
}
|
||||
|
||||
type Mandatory struct {
|
||||
Mode stsctr.Mode
|
||||
Keys []string
|
||||
}
|
||||
|
||||
func (o Config) Validate() error {
|
||||
@@ -98,22 +105,37 @@ func (o *sts) cfgGetReturnCode(s monsts.Status) int {
|
||||
}
|
||||
}
|
||||
|
||||
func (o *sts) cfgIsMandatory(name string) bool {
|
||||
if i, l := o.x.Load(keyConfigMandatory); !l {
|
||||
return false
|
||||
} else if v, k := i.([]string); !k {
|
||||
return false
|
||||
} else {
|
||||
return slices.Contains(v, name)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *sts) cfgGetMandatory() []string {
|
||||
func (o *sts) cfgGetMandatory() stslmd.ListMandatory {
|
||||
if i, l := o.x.Load(keyConfigMandatory); !l {
|
||||
return nil
|
||||
} else if v, k := i.([]string); !k {
|
||||
} else if v, k := i.(stslmd.ListMandatory); !k {
|
||||
return nil
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
func (o *sts) cfgGetMode(key string) stsctr.Mode {
|
||||
if l := o.cfgGetMandatory(); len(l) < 1 {
|
||||
return stsctr.Ignore
|
||||
} else {
|
||||
return l.GetMode(key)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *sts) cfgGetOne(key string) []string {
|
||||
if l := o.cfgGetMandatory(); len(l) < 1 {
|
||||
return make([]string, 0)
|
||||
} else {
|
||||
var r []string
|
||||
l.Walk(func(m stsmdt.Mandatory) bool {
|
||||
if m.KeyHas(key) {
|
||||
r = m.KeyList()
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
89
status/control/encode.go
Normal file
89
status/control/encode.go
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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 control
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func (c *Mode) unmarshall(val []byte) error {
|
||||
*c = ParseBytes(val)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Mode) MarshalJSON() ([]byte, error) {
|
||||
t := c.String()
|
||||
b := make([]byte, 0, len(t)+2)
|
||||
b = append(b, '"')
|
||||
b = append(b, []byte(t)...)
|
||||
b = append(b, '"')
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (c *Mode) UnmarshalJSON(bytes []byte) error {
|
||||
return c.unmarshall(bytes)
|
||||
}
|
||||
|
||||
func (c Mode) MarshalYAML() (interface{}, error) {
|
||||
return []byte(c.String()), nil
|
||||
}
|
||||
|
||||
func (c *Mode) UnmarshalYAML(value *yaml.Node) error {
|
||||
return c.unmarshall([]byte(value.Value))
|
||||
}
|
||||
|
||||
func (c Mode) MarshalTOML() ([]byte, error) {
|
||||
return []byte(c.String()), nil
|
||||
}
|
||||
|
||||
func (c *Mode) UnmarshalTOML(i interface{}) error {
|
||||
if p, k := i.([]byte); k {
|
||||
return c.unmarshall(p)
|
||||
}
|
||||
if p, k := i.(string); k {
|
||||
return c.unmarshall([]byte(p))
|
||||
}
|
||||
return fmt.Errorf("size: value not in valid format")
|
||||
}
|
||||
|
||||
func (c Mode) MarshalText() ([]byte, error) {
|
||||
return []byte(c.String()), nil
|
||||
}
|
||||
|
||||
func (c *Mode) UnmarshalText(bytes []byte) error {
|
||||
return c.unmarshall(bytes)
|
||||
}
|
||||
|
||||
func (c Mode) MarshalCBOR() ([]byte, error) {
|
||||
return []byte(c.String()), nil
|
||||
}
|
||||
|
||||
func (c *Mode) UnmarshalCBOR(bytes []byte) error {
|
||||
return c.unmarshall(bytes)
|
||||
}
|
66
status/control/interface.go
Normal file
66
status/control/interface.go
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 control
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Mode uint8
|
||||
|
||||
const (
|
||||
Ignore Mode = iota
|
||||
Should
|
||||
Must
|
||||
One
|
||||
)
|
||||
|
||||
func Parse(s string) Mode {
|
||||
switch {
|
||||
case strings.EqualFold(Must.Code(), s):
|
||||
return Must
|
||||
case strings.EqualFold(One.Code(), s):
|
||||
return One
|
||||
case strings.EqualFold(Should.Code(), s):
|
||||
return Should
|
||||
}
|
||||
|
||||
return Ignore
|
||||
}
|
||||
|
||||
func ParseBytes(p []byte) Mode {
|
||||
return Parse(string(p))
|
||||
}
|
||||
|
||||
func ParseInt64(val int64) Mode {
|
||||
if val > int64(math.MaxUint8) {
|
||||
return Mode(math.MaxUint8)
|
||||
}
|
||||
|
||||
return Mode(uint8(val))
|
||||
}
|
80
status/control/model.go
Normal file
80
status/control/model.go
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 control
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
libmap "github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
func (c Mode) String() string {
|
||||
switch c {
|
||||
case Must:
|
||||
return "Must"
|
||||
case One:
|
||||
return "One"
|
||||
case Should:
|
||||
return "Should"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c Mode) Code() string {
|
||||
return strings.ToLower(c.String())
|
||||
}
|
||||
|
||||
func ViperDecoderHook() libmap.DecodeHookFuncType {
|
||||
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
|
||||
var (
|
||||
z = Mode(0)
|
||||
t string
|
||||
k bool
|
||||
)
|
||||
|
||||
// Check if the data type matches the expected one
|
||||
if from.Kind() != reflect.String {
|
||||
return data, nil
|
||||
} else if t, k = data.(string); !k {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Check if the target type matches the expected one
|
||||
if to != reflect.TypeOf(z) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Format/decode/parse the data and return the new value
|
||||
if e := z.unmarshall([]byte(t)); e != nil {
|
||||
return nil, e
|
||||
} else {
|
||||
return z, nil
|
||||
}
|
||||
}
|
||||
}
|
@@ -35,12 +35,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
monpol "github.com/nabbar/golib/monitor/pool"
|
||||
|
||||
ginsdk "github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/render"
|
||||
ginrdr "github.com/gin-gonic/gin/render"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
|
||||
monpol "github.com/nabbar/golib/monitor/pool"
|
||||
monsts "github.com/nabbar/golib/monitor/status"
|
||||
montps "github.com/nabbar/golib/monitor/types"
|
||||
)
|
||||
@@ -88,7 +86,7 @@ func (e *encodeModel) GinRender(c *ginsdk.Context, isText bool, isShort bool) {
|
||||
}
|
||||
|
||||
if isText {
|
||||
c.Render(e.code, render.Data{
|
||||
c.Render(e.code, ginrdr.Data{
|
||||
ContentType: ginsdk.MIMEPlain,
|
||||
Data: e.Bytes(),
|
||||
})
|
||||
|
@@ -31,15 +31,11 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
|
||||
montps "github.com/nabbar/golib/monitor/types"
|
||||
|
||||
libctx "github.com/nabbar/golib/context"
|
||||
|
||||
libver "github.com/nabbar/golib/version"
|
||||
|
||||
ginsdk "github.com/gin-gonic/gin"
|
||||
libctx "github.com/nabbar/golib/context"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
montps "github.com/nabbar/golib/monitor/types"
|
||||
libver "github.com/nabbar/golib/version"
|
||||
)
|
||||
|
||||
type Route interface {
|
||||
@@ -54,7 +50,7 @@ type Info interface {
|
||||
}
|
||||
|
||||
type Pool interface {
|
||||
montps.Pool
|
||||
montps.PoolStatus
|
||||
RegisterPool(fct montps.FuncPool)
|
||||
}
|
||||
|
||||
|
37
status/listmandatory/interface.go
Normal file
37
status/listmandatory/interface.go
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 listmandatory
|
||||
|
||||
import stsmdt "github.com/nabbar/golib/status/mandatory"
|
||||
|
||||
type ListMandatory []stsmdt.Mandatory
|
||||
|
||||
func New(m ...stsmdt.Mandatory) ListMandatory {
|
||||
res := make([]stsmdt.Mandatory, 0)
|
||||
copy(res, m)
|
||||
return res
|
||||
}
|
126
status/listmandatory/model.go
Normal file
126
status/listmandatory/model.go
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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 listmandatory
|
||||
|
||||
import (
|
||||
stsctr "github.com/nabbar/golib/status/control"
|
||||
stsmdt "github.com/nabbar/golib/status/mandatory"
|
||||
)
|
||||
|
||||
func (l *ListMandatory) Walk(fct func(m stsmdt.Mandatory) bool) {
|
||||
if l == nil {
|
||||
return
|
||||
} else if len(*l) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
k bool
|
||||
m stsmdt.Mandatory
|
||||
n = *l
|
||||
)
|
||||
|
||||
for i := range n {
|
||||
m = n[i]
|
||||
k = fct(m)
|
||||
n[i] = m
|
||||
|
||||
if !k {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
*l = n
|
||||
}
|
||||
|
||||
func (l *ListMandatory) Add(m ...stsmdt.Mandatory) {
|
||||
if l == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var n = *l
|
||||
|
||||
if len(n) < 1 {
|
||||
n = make([]stsmdt.Mandatory, 0)
|
||||
}
|
||||
|
||||
*l = append(n, m...)
|
||||
}
|
||||
|
||||
func (l *ListMandatory) Del(m stsmdt.Mandatory) {
|
||||
if l == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
n = *l
|
||||
r = make([]stsmdt.Mandatory, 0)
|
||||
)
|
||||
|
||||
if len(n) < 1 {
|
||||
*l = make([]stsmdt.Mandatory, 0)
|
||||
return
|
||||
}
|
||||
|
||||
for i := range n {
|
||||
if n[i] != m {
|
||||
r = append(r, n[i])
|
||||
}
|
||||
}
|
||||
|
||||
*l = r
|
||||
}
|
||||
|
||||
func (l ListMandatory) GetMode(key string) stsctr.Mode {
|
||||
if len(l) < 1 {
|
||||
return stsctr.Ignore
|
||||
}
|
||||
|
||||
for i := range l {
|
||||
if l[i].KeyHas(key) {
|
||||
return l[i].GetMode()
|
||||
}
|
||||
}
|
||||
|
||||
return stsctr.Ignore
|
||||
}
|
||||
|
||||
func (l *ListMandatory) SetMode(key string, mod stsctr.Mode) {
|
||||
if len(*l) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
var n = *l
|
||||
|
||||
for i := range n {
|
||||
if n[i].KeyHas(key) {
|
||||
n[i].SetMode(mod)
|
||||
*l = n
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
56
status/mandatory/interface.go
Normal file
56
status/mandatory/interface.go
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 mandatory
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
|
||||
stsctr "github.com/nabbar/golib/status/control"
|
||||
)
|
||||
|
||||
type Mandatory interface {
|
||||
SetMode(m stsctr.Mode)
|
||||
GetMode() stsctr.Mode
|
||||
|
||||
KeyHas(key string) bool
|
||||
KeyAdd(keys ...string)
|
||||
KeyDel(keys ...string)
|
||||
KeyList() []string
|
||||
}
|
||||
|
||||
func New() Mandatory {
|
||||
m := new(atomic.Value)
|
||||
m.Store(stsctr.Ignore)
|
||||
|
||||
k := new(atomic.Value)
|
||||
k.Store(make([]string, 0))
|
||||
|
||||
return &model{
|
||||
Mode: m,
|
||||
Keys: k,
|
||||
}
|
||||
}
|
135
status/mandatory/model.go
Normal file
135
status/mandatory/model.go
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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 mandatory
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
|
||||
stsctr "github.com/nabbar/golib/status/control"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type model struct {
|
||||
Mode *atomic.Value
|
||||
Keys *atomic.Value
|
||||
}
|
||||
|
||||
func (o *model) SetMode(m stsctr.Mode) {
|
||||
o.Mode.Store(m)
|
||||
}
|
||||
|
||||
func (o *model) GetMode() stsctr.Mode {
|
||||
m := o.Mode.Load()
|
||||
|
||||
if m != nil {
|
||||
return m.(stsctr.Mode)
|
||||
}
|
||||
|
||||
return stsctr.Ignore
|
||||
}
|
||||
|
||||
func (o *model) KeyHas(key string) bool {
|
||||
i := o.Keys.Load()
|
||||
|
||||
if i == nil {
|
||||
return false
|
||||
} else if l, k := i.([]string); !k {
|
||||
return false
|
||||
} else {
|
||||
return slices.Contains(l, key)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *model) KeyAdd(keys ...string) {
|
||||
var (
|
||||
i any
|
||||
k bool
|
||||
l []string
|
||||
)
|
||||
|
||||
i = o.Keys.Load()
|
||||
|
||||
if i == nil {
|
||||
l = make([]string, 0)
|
||||
} else if l, k = i.([]string); !k {
|
||||
l = make([]string, 0)
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
if !slices.Contains(l, key) {
|
||||
l = append(l, key)
|
||||
}
|
||||
}
|
||||
|
||||
o.Keys.Store(l)
|
||||
}
|
||||
|
||||
func (o *model) KeyDel(keys ...string) {
|
||||
var (
|
||||
i any
|
||||
k bool
|
||||
l []string
|
||||
)
|
||||
|
||||
i = o.Keys.Load()
|
||||
|
||||
if i == nil {
|
||||
o.Keys.Store(make([]string, 0))
|
||||
return
|
||||
} else if l, k = i.([]string); !k {
|
||||
o.Keys.Store(make([]string, 0))
|
||||
return
|
||||
}
|
||||
|
||||
var res = make([]string, 0)
|
||||
|
||||
for _, key := range l {
|
||||
if !slices.Contains(keys, key) {
|
||||
res = append(res, key)
|
||||
}
|
||||
}
|
||||
|
||||
o.Keys.Store(res)
|
||||
}
|
||||
|
||||
func (o *model) KeyList() []string {
|
||||
var (
|
||||
i any
|
||||
k bool
|
||||
l []string
|
||||
)
|
||||
|
||||
i = o.Keys.Load()
|
||||
|
||||
if i == nil {
|
||||
return make([]string, 0)
|
||||
} else if l, k = i.([]string); !k {
|
||||
return make([]string, 0)
|
||||
}
|
||||
|
||||
return slices.Clone(l)
|
||||
}
|
@@ -30,12 +30,11 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
|
||||
montps "github.com/nabbar/golib/monitor/types"
|
||||
|
||||
libctx "github.com/nabbar/golib/context"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
monsts "github.com/nabbar/golib/monitor/status"
|
||||
montps "github.com/nabbar/golib/monitor/types"
|
||||
stsctr "github.com/nabbar/golib/status/control"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
@@ -74,28 +73,60 @@ func (o *sts) IsHealthy(name ...string) bool {
|
||||
}
|
||||
|
||||
func (o *sts) getStatus(keys ...string) (monsts.Status, string) {
|
||||
if len(keys) < 1 {
|
||||
keys = o.cfgGetMandatory()
|
||||
}
|
||||
|
||||
o.m.RLock()
|
||||
defer o.m.RUnlock()
|
||||
|
||||
s := monsts.OK
|
||||
m := ""
|
||||
stt := monsts.OK
|
||||
msg := ""
|
||||
ign := make([]string, 0)
|
||||
|
||||
o.MonitorWalk(func(name string, val montps.Monitor) bool {
|
||||
if !slices.Contains(keys, name) {
|
||||
if len(keys) > 0 && !slices.Contains(keys, name) {
|
||||
return true
|
||||
} else if len(ign) > 0 && slices.Contains(ign, name) {
|
||||
return true
|
||||
}
|
||||
|
||||
if v := val.Status(); s > v {
|
||||
s = v
|
||||
m = val.Message()
|
||||
v := val.Status()
|
||||
|
||||
if c := o.cfgGetMode(name); c == stsctr.Ignore {
|
||||
return true
|
||||
} else if c == stsctr.Should && v < monsts.Warn {
|
||||
if stt > monsts.Warn {
|
||||
stt = monsts.Warn
|
||||
msg = val.Message()
|
||||
}
|
||||
} else if c == stsctr.One {
|
||||
lst := o.cfgGetOne(name)
|
||||
sta := monsts.KO
|
||||
res := ""
|
||||
|
||||
o.MonitorWalk(func(nme string, val montps.Monitor) bool {
|
||||
if !slices.Contains(lst, nme) {
|
||||
return true
|
||||
}
|
||||
|
||||
ign = append(ign, nme)
|
||||
|
||||
w := val.Status()
|
||||
|
||||
if w > sta {
|
||||
sta = w
|
||||
} else if w == sta && len(res) < 1 {
|
||||
res = val.Message()
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
if stt > sta {
|
||||
stt = sta
|
||||
msg = res
|
||||
}
|
||||
} else if stt > v {
|
||||
stt = v
|
||||
msg = val.Message()
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
return s, m
|
||||
return stt, msg
|
||||
}
|
||||
|
@@ -31,9 +31,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
|
||||
ginsdk "github.com/gin-gonic/gin"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
|
Reference in New Issue
Block a user