mirror of
https://github.com/nabbar/golib.git
synced 2025-12-24 11:51:02 +08:00
Add Package Config :
- major dependancies are : - golib/context config - golib/viper - interface config extend : - golib/context config interface - component list - interface component list : this interface implement all function to manage a collection of component. All component are registred with they config key. A component must implement basic function like start, stop, reload, defaultConfig... The main config json is set by calling all component config with the config key attached Each component have some status status like isStarted, isRunning, ... Each component must also declare his dependencies with other component. As that when start or reload is called, the component is sure that dependencies are still started or reloaded. - They are 4 component for now : log, tls, headers and http server - The config package will start a new context / cancelfunc on init to be sure to stop cleanly all component and process Add Package Viper : - this package is an helper to the config package with the spf13 viper lib - this package can watch any change of a config file or can be connected to a remote config cluster like ETCD Add Package Cobra : - this package is an helper to make a CLI with flag / command - this package is based on spf13 cobra has all method to be connected to viper golib
This commit is contained in:
242
cobra/README.md
Normal file
242
cobra/README.md
Normal file
@@ -0,0 +1,242 @@
|
||||
# Cobra pakcage
|
||||
Help build integration of spf13/Cobra lib.
|
||||
This package will simplify call and use of flags / command for a CLI Tools.
|
||||
|
||||
## Exmaple of implement
|
||||
Make some folder / file like this:
|
||||
```
|
||||
/api
|
||||
|- root.go
|
||||
|- one_command.go
|
||||
/pkg
|
||||
|- common.go
|
||||
/main.go
|
||||
```
|
||||
|
||||
### Main init :
|
||||
|
||||
This `commong.go` file will make the init of version, logger, cobra, viper and config packages.
|
||||
|
||||
```go
|
||||
import (
|
||||
"strings"
|
||||
|
||||
libcbr "github.com/nabbar/golib/cobra"
|
||||
libcfg "github.com/nabbar/golib/config"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
libver "github.com/nabbar/golib/version"
|
||||
libvpr "github.com/nabbar/golib/viper"
|
||||
)
|
||||
```
|
||||
|
||||
Some variables :
|
||||
```go
|
||||
var(
|
||||
// Golib Version Package
|
||||
vrs libver.Version
|
||||
|
||||
// Main config / context Golib package
|
||||
cfg libcfg.Config
|
||||
|
||||
// Root logger before config
|
||||
log liblog.Logger
|
||||
|
||||
// Main Cobra / Viper resource
|
||||
cbr libcbr.Cobra
|
||||
vpr libvpr.Viper
|
||||
)
|
||||
```
|
||||
|
||||
This function will init the libs if not set and return the lib resource :
|
||||
```go
|
||||
func GetViper() libvpr.Viper {
|
||||
if vpr == nil {
|
||||
vpr = libvpr.New()
|
||||
vpr.SetHomeBaseName(strings.ToLower(GetVersion().GetPackage()))
|
||||
vpr.SetEnvVarsPrefix(GetVersion().GetPrefix())
|
||||
vpr.SetDefaultConfig(GetConfig().DefaultConfig)
|
||||
}
|
||||
|
||||
return vpr
|
||||
}
|
||||
|
||||
func GetCobra() libcbr.Cobra {
|
||||
if cbr == nil {
|
||||
cbr = libcbr.New()
|
||||
cbr.SetVersion(GetVersion())
|
||||
cbr.SetLogger(GetLogger)
|
||||
cbr.SetViper(GetViper)
|
||||
}
|
||||
|
||||
return cbr
|
||||
}
|
||||
|
||||
func GetConfig() libcfg.Config {
|
||||
if cfg == nil {
|
||||
cfg = libcfg.New()
|
||||
cfg.RegisterFuncViper(GetViper)
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
func GetVersion() libver.Version {
|
||||
if vrs == nil {
|
||||
//vrs = libver.NewVersion(...)
|
||||
}
|
||||
|
||||
return vrs
|
||||
}
|
||||
|
||||
func GetLogger() liblog.Logger {
|
||||
if log == nil {
|
||||
log = liblog.New(cfg.Context())
|
||||
_ = log.SetOptions(&liblog.Options{
|
||||
DisableStandard: false,
|
||||
DisableStack: false,
|
||||
DisableTimestamp: false,
|
||||
EnableTrace: true,
|
||||
TraceFilter: GetVersion().GetRootPackagePath(),
|
||||
DisableColor: false,
|
||||
LogFile: nil, // TODO
|
||||
LogSyslog: nil, // TODO
|
||||
})
|
||||
log.SetLevel(liblog.InfoLevel)
|
||||
log.SetSPF13Level(liblog.InfoLevel, nil)
|
||||
}
|
||||
|
||||
return log
|
||||
}
|
||||
```
|
||||
|
||||
### The root file in command folder
|
||||
This file will be the global file for cobra. It will config and init the cobra for yours command.
|
||||
This file will import your `pkg/common.go` file :
|
||||
```go
|
||||
import(
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
libcns "github.com/nabbar/golib/console"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
|
||||
compkg "../pkg"
|
||||
apipkg "../api"
|
||||
)
|
||||
```
|
||||
|
||||
And will define some flag vars :
|
||||
```go
|
||||
var (
|
||||
// var for config file path to be load by viper
|
||||
cfgFile string
|
||||
|
||||
// var for log verbose
|
||||
flgVerbose int
|
||||
|
||||
// flag for init cobra has error
|
||||
iniErr liberr.Error
|
||||
)
|
||||
```
|
||||
|
||||
The `InitCommand` function will initialize the cobra / viper package and will be call by the main init function into you `main/init()` function:
|
||||
```go
|
||||
func InitCommand() {
|
||||
//the initFunc is a function call on init cobra before calling command but after parsing flag / command ...
|
||||
compkg.GetCobra().SetFuncInit(initConfig)
|
||||
|
||||
// must init after the SetFuncinit function
|
||||
compkg.GetCobra().Init()
|
||||
|
||||
// add the Config file flag
|
||||
compkg.GetLogger().CheckError(liblog.FatalLevel, liblog.DebugLevel, "Add Flag Config File", compkg.GetCobra().SetFlagConfig(true, &cfgFile))
|
||||
|
||||
// add the verbose flas
|
||||
compkg.GetCobra().SetFlagVerbose(true, &flgVerbose)
|
||||
|
||||
// Add some generic command
|
||||
compkg.GetCobra().AddCommandCompletion()
|
||||
compkg.GetCobra().AddCommandConfigure("", compkg.GetConfig().DefaultConfig)
|
||||
compkg.GetCobra().AddCommandPrintErrorCode(cmdPrintError)
|
||||
|
||||
// Add one custom command. The best is to isolate each command into a specific file
|
||||
// Each command file, will having a main function to create the cobra command.
|
||||
// Here we will only call this main function to add each command into the main cobra command like this
|
||||
compkg.GetCobra().AddCommand(initCustomCommand1())
|
||||
|
||||
// Carefully with the `init` function, because you will not manage the order of running each init function.
|
||||
// To prevent it, the best is to not having init function, but custom init call in the awaiting order into the `main/init` function
|
||||
}
|
||||
|
||||
// this function will be use in the PrintError command to print first ErrorCode => Package
|
||||
func cmdPrintError(item, value string) {
|
||||
println(fmt.Sprintf("%s : %s", libcns.PadLeft(item, 15, " "), path.Dir(value)))
|
||||
}
|
||||
|
||||
// initConfig reads in config file and ENV variables if set.
|
||||
func initConfig() {
|
||||
// Redefine the root logger level with the verbose flag
|
||||
switch flgVerbose {
|
||||
case 0:
|
||||
compkg.GetLogger().SetLevel(liblog.ErrorLevel)
|
||||
case 1:
|
||||
compkg.GetLogger().SetLevel(liblog.WarnLevel)
|
||||
case 2:
|
||||
compkg.GetLogger().SetLevel(liblog.InfoLevel)
|
||||
default:
|
||||
compkg.GetLogger().SetLevel(liblog.DebugLevel)
|
||||
}
|
||||
|
||||
// Define the config file into viper to load it if is set
|
||||
iniErr = compkg.GetViper().SetConfigFile(cfgFile)
|
||||
compkg.GetLogger().CheckError(liblog.FatalLevel, liblog.DebugLevel, "define config file", iniErr)
|
||||
|
||||
// try to init viper with config (local file or remote)
|
||||
if iniErr = compkg.GetViper().Config(liblog.NilLevel, liblog.NilLevel); iniErr == nil {
|
||||
// register the reload config function with the watch FS function
|
||||
compkg.GetViper().SetRemoteReloadFunc(func() {
|
||||
_ = compkg.GetLogger().CheckError(liblog.ErrorLevel, liblog.DebugLevel, "config reload", compkg.GetConfig().Reload())
|
||||
})
|
||||
compkg.GetViper().WatchFS(liblog.InfoLevel)
|
||||
}
|
||||
|
||||
// Make the config for this app (cf config package)
|
||||
apipkg.SetConfig(compkg.GetLogger().GetLevel(), apirtr.GetHandlers())
|
||||
}
|
||||
|
||||
// This is called by main.main() to parse and run the app.
|
||||
func Execute() {
|
||||
compkg.GetLogger().CheckError(liblog.FatalLevel, liblog.DebugLevel, "RootCmd Executed", compkg.GetCobra().Execute())
|
||||
}
|
||||
```
|
||||
|
||||
### The main file of your app
|
||||
The main file of your app, wil implement the `main/init()` function and the `main/main()` function.
|
||||
|
||||
```go
|
||||
import(
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
|
||||
compkg "./pkg"
|
||||
cmdpkg "./cmd"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Configure the golib error package
|
||||
liberr.SetModeReturnError(liberr.ErrorReturnStringErrorFull)
|
||||
|
||||
// Check the go runtime use to build
|
||||
compkg.GetLogger().CheckError(liblog.FatalLevel, liblog.DebugLevel, "Checking go version", compkg.GetVersion().CheckGo("1.16", ">="))
|
||||
|
||||
// Call the `cmd/InitCommand` function
|
||||
cmdpkg.InitCommand()
|
||||
}
|
||||
|
||||
func main() {
|
||||
// run the command Execute function
|
||||
cmdpkg.Execute()
|
||||
}
|
||||
|
||||
```
|
||||
96
cobra/completion.go
Normal file
96
cobra/completion.go
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 cobra
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
spfcbr "github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func (c *cobra) AddCommandCompletion() {
|
||||
pkg := c.getPackageName()
|
||||
|
||||
desc := "This command will create a completion shel script for simplify the use of this app.\n" +
|
||||
"To do this," +
|
||||
"\n\t 1- generate a completion script for your shell, like this : " +
|
||||
"\n\t\t" + pkg + " completion bash /etc/bash_completion.d/" + pkg +
|
||||
"\n\n 2- enable completion into your shell" +
|
||||
"\n\t\t example to bash, you need to install the package `bash-completion`" +
|
||||
"\n\n 3- enable completion into your shell profile" +
|
||||
"\n\t\t example to bash, you need to uncomment the completion section into your /home/<user>/.bashrc" +
|
||||
"\n\n"
|
||||
|
||||
cmd := &spfcbr.Command{
|
||||
Use: "completion <Bash|Zsh|PowerShell|Fish> <Completion File to be write>",
|
||||
Example: "completion bash /etc/bash_completion.d/" + pkg,
|
||||
Short: "Generate a completion scripts for bash, zsh, fish or powershell",
|
||||
Long: desc,
|
||||
Run: func(cmd *spfcbr.Command, args []string) {
|
||||
var file string
|
||||
|
||||
if len(args) < 1 {
|
||||
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "missing args", cmd.Usage())
|
||||
os.Exit(1)
|
||||
} else if len(args) >= 2 {
|
||||
file = filepath.Clean(args[1])
|
||||
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "create file path", os.MkdirAll(filepath.Dir(file), 0755))
|
||||
}
|
||||
|
||||
switch strings.ToLower(args[0]) {
|
||||
case "bash":
|
||||
if file == "" {
|
||||
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenBashCompletionV2(os.Stdout, true))
|
||||
} else {
|
||||
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenBashCompletionFileV2(file, true))
|
||||
}
|
||||
case "fish":
|
||||
if file == "" {
|
||||
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenFishCompletion(os.Stdout, true))
|
||||
} else {
|
||||
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenFishCompletionFile(file, true))
|
||||
}
|
||||
case "powershell":
|
||||
if file == "" {
|
||||
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenPowerShellCompletionWithDesc(os.Stdout))
|
||||
} else {
|
||||
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenPowerShellCompletionFileWithDesc(file))
|
||||
}
|
||||
case "zsh":
|
||||
if file == "" {
|
||||
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenZshCompletion(os.Stdout))
|
||||
} else {
|
||||
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenZshCompletionFile(file))
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
c.c.AddCommand(cmd)
|
||||
}
|
||||
140
cobra/configure.go
Normal file
140
cobra/configure.go
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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 cobra
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/pelletier/go-toml"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
spfcbr "github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func (c *cobra) getDefaultPath(baseName string) (string, error) {
|
||||
path := ""
|
||||
|
||||
// Find home directory.
|
||||
home, err := homedir.Dir()
|
||||
c.getLog().CheckError(liblog.WarnLevel, liblog.InfoLevel, "Loading home dir", err)
|
||||
|
||||
// set configname based on package name
|
||||
if baseName == "" {
|
||||
return "", fmt.Errorf("arguments missing: requires the destination file path")
|
||||
}
|
||||
|
||||
path = filepath.Clean(home + string(filepath.Separator) + baseName + ".json")
|
||||
|
||||
if path == "." || path == ".json" {
|
||||
return "", fmt.Errorf("arguments missing: requires the destination file path")
|
||||
}
|
||||
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func (c *cobra) AddCommandConfigure(basename string, defaultConfig func() io.Reader) {
|
||||
pkg := c.getPackageName()
|
||||
|
||||
if basename == "" && pkg != "" {
|
||||
basename = "." + strings.ToLower(pkg)
|
||||
}
|
||||
|
||||
var cfgFile string
|
||||
|
||||
c.c.AddCommand(&spfcbr.Command{
|
||||
Use: "configure <file path with valid extension (json, yaml, toml, ...) to be generated>",
|
||||
Example: "configure ~/." + strings.ToLower(pkg) + ".yml",
|
||||
Short: "Generate config file",
|
||||
Long: `Generates a configuration file based on giving existing config flag
|
||||
override by passed flag in command line and completed with default for non existing values.`,
|
||||
|
||||
Run: func(cmd *spfcbr.Command, args []string) {
|
||||
var fs *os.File
|
||||
|
||||
defer func() {
|
||||
if fs != nil {
|
||||
_ = fs.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
buf, err := ioutil.ReadAll(defaultConfig())
|
||||
c.getLog().CheckError(liblog.FatalLevel, liblog.DebugLevel, "reading default config", err)
|
||||
|
||||
if len(path.Ext(cfgFile)) > 0 && strings.ToLower(path.Ext(cfgFile)) != ".json" {
|
||||
var mod = make(map[string]interface{}, 0)
|
||||
|
||||
err = json.Unmarshal(buf, &mod)
|
||||
c.getLog().CheckError(liblog.FatalLevel, liblog.DebugLevel, "transform json default config", err)
|
||||
|
||||
switch strings.ToLower(path.Ext(cfgFile)) {
|
||||
case ".toml":
|
||||
buf, err = toml.Marshal(mod)
|
||||
case ".yml", ".yaml":
|
||||
buf, err = yaml.Marshal(mod)
|
||||
default:
|
||||
c.getLog().CheckError(liblog.FatalLevel, liblog.DebugLevel, "get encode for extension file", fmt.Errorf("extension file '%s' not compatible", path.Ext(cfgFile)))
|
||||
}
|
||||
}
|
||||
|
||||
fs, err = os.OpenFile(cfgFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
|
||||
c.getLog().CheckError(liblog.FatalLevel, liblog.DebugLevel, "opening destination config file for exclusive write with truncate", err)
|
||||
|
||||
_, err = fs.Write(buf)
|
||||
c.getLog().CheckError(liblog.FatalLevel, liblog.DebugLevel, fmt.Sprintf("writing config to file '%s'", cfgFile), err)
|
||||
|
||||
err = os.Chmod(cfgFile, 0600)
|
||||
if !c.getLog().CheckError(liblog.ErrorLevel, liblog.InfoLevel, fmt.Sprintf("setting permission for config file '%s'", cfgFile), err) {
|
||||
println(fmt.Sprintf("\n\t>> Config File '%s' has been created and file permission have been set.", cfgFile))
|
||||
println("\t>> To explicitly specify this config file when you call this tool, use the '-c' flag like this: ")
|
||||
println(fmt.Sprintf("\t\t\t %s -c %s <cmd>...\n", pkg, cfgFile))
|
||||
}
|
||||
},
|
||||
|
||||
Args: func(cmd *spfcbr.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
var err error
|
||||
cfgFile, err = c.getDefaultPath(basename)
|
||||
return err
|
||||
} else if len(args) > 1 {
|
||||
return fmt.Errorf("arguments error: too many file path specify")
|
||||
} else {
|
||||
cfgFile = args[0]
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
74
cobra/interface.go
Normal file
74
cobra/interface.go
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 cobra
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
libver "github.com/nabbar/golib/version"
|
||||
libvpr "github.com/nabbar/golib/viper"
|
||||
spfcbr "github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type FuncInit func()
|
||||
type FuncLogger func() liblog.Logger
|
||||
type FuncViper func() libvpr.Viper
|
||||
type FuncPrintErrorCode func(item, value string)
|
||||
|
||||
type Cobra interface {
|
||||
SetVersion(v libver.Version)
|
||||
|
||||
SetFuncInit(fct FuncInit)
|
||||
SetViper(fct FuncViper)
|
||||
SetLogger(fct FuncLogger)
|
||||
SetForceNoInfo(flag bool)
|
||||
|
||||
Init()
|
||||
|
||||
SetFlagConfig(persistent bool, flagVar *string) error
|
||||
SetFlagVerbose(persistent bool, flagVar *int)
|
||||
|
||||
NewCommand(cmd, short, long, useWithoutCmd, exampleWithoutCmd string) *spfcbr.Command
|
||||
AddCommand(subCmd ...*spfcbr.Command)
|
||||
|
||||
AddCommandCompletion()
|
||||
AddCommandConfigure(basename string, defaultConfig func() io.Reader)
|
||||
AddCommandPrintErrorCode(fct FuncPrintErrorCode)
|
||||
|
||||
Execute() error
|
||||
}
|
||||
|
||||
func New() Cobra {
|
||||
return &cobra{
|
||||
c: nil,
|
||||
s: nil,
|
||||
v: nil,
|
||||
i: nil,
|
||||
l: nil,
|
||||
}
|
||||
}
|
||||
172
cobra/model.go
Normal file
172
cobra/model.go
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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 cobra
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
libver "github.com/nabbar/golib/version"
|
||||
spfcbr "github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type cobra struct {
|
||||
c *spfcbr.Command
|
||||
s libver.Version
|
||||
b bool
|
||||
d string
|
||||
|
||||
v FuncViper
|
||||
i FuncInit
|
||||
l FuncLogger
|
||||
}
|
||||
|
||||
func (c *cobra) Init() {
|
||||
|
||||
c.c = &spfcbr.Command{
|
||||
TraverseChildren: true,
|
||||
Use: c.getPackageName(),
|
||||
Version: c.getPackageVersion(),
|
||||
Short: c.getPackageDescShort(),
|
||||
Long: c.getPackageDescLong(),
|
||||
}
|
||||
|
||||
// launch cobra flag parsing
|
||||
spfcbr.OnInitialize(c.printHeader, c.i)
|
||||
}
|
||||
|
||||
func (c *cobra) printHeader() {
|
||||
if !c.b {
|
||||
println(c.s.GetHeader())
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) SetForceNoInfo(flag bool) {
|
||||
c.b = flag
|
||||
}
|
||||
|
||||
func (c *cobra) Execute() error {
|
||||
return c.c.Execute()
|
||||
}
|
||||
|
||||
func (c *cobra) SetVersion(vers libver.Version) {
|
||||
c.s = vers
|
||||
}
|
||||
|
||||
func (c *cobra) SetFuncInit(fct FuncInit) {
|
||||
c.i = fct
|
||||
}
|
||||
|
||||
func (c *cobra) SetViper(fct FuncViper) {
|
||||
c.v = fct
|
||||
}
|
||||
|
||||
func (c *cobra) SetLogger(fct FuncLogger) {
|
||||
c.l = fct
|
||||
}
|
||||
|
||||
func (c *cobra) SetFlagConfig(persistent bool, flagVar *string) error {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().StringVarP(flagVar, "config", "c", "", "specify the config file to load (default is $HOME/."+strings.ToLower(c.getPackageName())+".[yaml|json|toml])")
|
||||
return c.c.MarkPersistentFlagFilename("config", "json", "toml", "yaml", "yml")
|
||||
} else {
|
||||
c.c.Flags().StringVarP(flagVar, "config", "c", "", "specify the config file to load (default is $HOME/."+strings.ToLower(c.getPackageName())+".[yaml|json|toml])")
|
||||
return c.c.MarkFlagFilename("config", "json", "toml", "yaml", "yml")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) SetFlagVerbose(persistent bool, flagVar *int) {
|
||||
if persistent {
|
||||
c.c.PersistentFlags().CountVarP(flagVar, "verbose", "v", "enable verbose mode (multi allowed v, vv, vvv)")
|
||||
} else {
|
||||
c.c.Flags().CountVarP(flagVar, "verbose", "v", "enable verbose mode (multi allowed v, vv, vvv)")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) NewCommand(cmd, short, long, useWithoutCmd, exampleWithoutCmd string) *spfcbr.Command {
|
||||
return &spfcbr.Command{
|
||||
Use: fmt.Sprintf("%s %s", cmd, useWithoutCmd),
|
||||
Short: short,
|
||||
Long: long,
|
||||
Example: fmt.Sprintf("%s %s", cmd, exampleWithoutCmd),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cobra) AddCommand(subCmd ...*spfcbr.Command) {
|
||||
c.c.AddCommand(subCmd...)
|
||||
}
|
||||
|
||||
func (c *cobra) getLog() liblog.Logger {
|
||||
var l liblog.Logger
|
||||
|
||||
if c.l != nil {
|
||||
l = c.l()
|
||||
}
|
||||
|
||||
if l != nil {
|
||||
return l
|
||||
}
|
||||
|
||||
return liblog.GetDefault()
|
||||
}
|
||||
|
||||
func (c *cobra) getPackageName() string {
|
||||
pkg := path.Base(os.Args[0])
|
||||
|
||||
if pkg == "" {
|
||||
if f, e := os.Executable(); e == nil {
|
||||
pkg = path.Base(f)
|
||||
} else {
|
||||
pkg = c.s.GetPackage()
|
||||
}
|
||||
}
|
||||
|
||||
return pkg
|
||||
}
|
||||
|
||||
func (c *cobra) getPackageVersion() string {
|
||||
if c.s == nil {
|
||||
return "missing version"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Version details: \n\tHash: %s\n\tVersion: %s\n\tRuntime: %s\n\tAuthor: %s\n\tDate: %s\n\tLicence: %s\n", c.s.GetBuild(), c.s.GetRelease(), c.s.GetAppId(), c.s.GetAuthor(), c.s.GetDate(), c.s.GetLicenseName())
|
||||
}
|
||||
|
||||
func (c *cobra) getPackageGRootPath() string {
|
||||
return c.s.GetRootPackagePath()
|
||||
}
|
||||
|
||||
func (c *cobra) getPackageDescShort() string {
|
||||
return c.d
|
||||
}
|
||||
|
||||
func (c *cobra) getPackageDescLong() string {
|
||||
return c.s.GetDescription()
|
||||
}
|
||||
60
cobra/printError.go
Normal file
60
cobra/printError.go
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 cobra
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
spfcbr "github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func (c *cobra) AddCommandPrintErrorCode(fct FuncPrintErrorCode) {
|
||||
c.c.AddCommand(&spfcbr.Command{
|
||||
Use: "error",
|
||||
Example: "error",
|
||||
Short: "Print error code with package path related",
|
||||
Long: "",
|
||||
Run: func(cmd *spfcbr.Command, args []string) {
|
||||
var (
|
||||
lst = liberr.GetCodePackages(c.getPackageGRootPath())
|
||||
key = make([]int, 0)
|
||||
)
|
||||
|
||||
for c := range lst {
|
||||
key = append(key, int(c.GetUint16()))
|
||||
}
|
||||
|
||||
sort.Ints(key)
|
||||
|
||||
for _, c := range key {
|
||||
fct(fmt.Sprintf("%d", c), lst[liberr.CodeError(uint16(c))])
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
119
config/README.md
Normal file
119
config/README.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# Config pakcage
|
||||
This package will make a global config management package for an app.
|
||||
This package work wil component who's will make the real intelligence of the config.
|
||||
For example, the main config file is not existing into this config, because is generated by the sum of all component config part.
|
||||
|
||||
## Exmaple of implement
|
||||
You can follow the initialization define into the [`cobra` package](../cobra/README.md)
|
||||
Here we will define the intialization of the config package.
|
||||
|
||||
### Main init of config :
|
||||
|
||||
Make a package's file to be called by yours application command or routers
|
||||
Into this file we will use some import
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
libsts "github.com/nabbar/golib/status"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
librtr "github.com/nabbar/golib/router"
|
||||
|
||||
cmphea "github.com/nabbar/golib/config/components/head"
|
||||
cmphtp "github.com/nabbar/golib/config/components/http"
|
||||
cmplog "github.com/nabbar/golib/config/components/log"
|
||||
cmptls "github.com/nabbar/golib/config/components/tls"
|
||||
|
||||
compkg "../pkg"
|
||||
)
|
||||
```
|
||||
|
||||
Some constant to prevents error on copy/paste :
|
||||
```go
|
||||
const (
|
||||
ConfigKeyHead = "headers"
|
||||
ConfigKeyHttp = "servers"
|
||||
ConfigKeyLog = "log"
|
||||
ConfigKeyTls = "tls"
|
||||
)
|
||||
```
|
||||
|
||||
This function will init the libs and return the lib resource.
|
||||
This is an example, but you can create your own component to add it into you config.
|
||||
The config can have multi instance of same component type but with different config key.
|
||||
As That, you can for example define a TLS config for HTTP server, a TLS config for a client, ...
|
||||
|
||||
```go
|
||||
func SetConfig(lvl liblog.Level, handler map[string]http.Handler) {
|
||||
compkg.GetConfig().ComponentSet(ConfigKeyHead, cmphea.New())
|
||||
compkg.GetConfig().ComponentSet(ConfigKeyLog, cmplog.New(lvl, compkg.GetLogger))
|
||||
compkg.GetConfig().ComponentSet(ConfigKeyTls, cmptls.New())
|
||||
compkg.GetConfig().ComponentSet(ConfigKeyHttp, cmphtp.New(_ConfigKeyTls, _ConfigKeyLog, handler))
|
||||
}
|
||||
|
||||
// This function will return the router header based of the component header stored into the config
|
||||
func GetHeader() librtr.Headers {
|
||||
if cmp := cmphea.Load(compkg.GetConfig().ComponentGet, _ConfigKeyHead); cmp != nil {
|
||||
return cmp.GetHeaders()
|
||||
} else {
|
||||
GetLog().Fatal("component '%s' is not initialized", _ConfigKeyHead)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// This function will return the logger for the application.
|
||||
// If the component is not started, this function will return the root logger
|
||||
func GetLog() liblog.Logger {
|
||||
if !compkg.GetConfig().ComponentIsStarted() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cmp := cmplog.Load(compkg.GetConfig().ComponentGet, _ConfigKeyLog); cmp != nil {
|
||||
return cmp.Log()
|
||||
} else {
|
||||
compkg.GetLogger().Error("component '%s' is not initialized", _ConfigKeyLog)
|
||||
return compkg.GetLogger()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This function will connect the `status` package of golib with the `httpserver` package stored into the config :
|
||||
|
||||
```go
|
||||
// This function can be call by the implementation of Status Package to expose the status of the pool web server
|
||||
// This function will update the status after each reload the pool web server.
|
||||
func SetRouteStatus(sts libsts.RouteStatus) {
|
||||
compkg.GetConfig().RegisterFuncReloadAfter(func() liberr.Error {
|
||||
var cmp cmphtp.ComponentHttp
|
||||
|
||||
// If component has not been started, skill the function
|
||||
if !compkg.GetConfig().ComponentIsStarted() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if cannot access to the Http component, generate an error
|
||||
if cmp = cmphtp.Load(compkg.GetConfig().ComponentGet, ConfigKeyHttp); cmp == nil {
|
||||
return ErrorComponentNotInitialized.ErrorParent(fmt.Errorf("component '%s'", ConfigKeyHttp))
|
||||
}
|
||||
|
||||
// Get the Pool Server
|
||||
pool := cmp.GetPool()
|
||||
pool.StatusRoute(_ConfigKeyHttp, GetRouteStatusMessage, sts)
|
||||
|
||||
// Don't forget to update the component pool
|
||||
cmp.SetPool(pool)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
To generate the config example, just call this function :
|
||||
```go
|
||||
compkg.GetConfig().DefaultConfig()
|
||||
```
|
||||
This function will associate the config Key with the component default config into a main buffer to return it.
|
||||
As that, config can be extended easily with many component and the config is automatically managed.
|
||||
89
config/component.go
Normal file
89
config/component.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 config
|
||||
|
||||
import (
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
type Component interface {
|
||||
// Type return the component type.
|
||||
Type() string
|
||||
|
||||
// RegisterContext is called by Config to register a function to get the main context.
|
||||
// This function can be used into start / reload function to use context interface.
|
||||
RegisterContext(fct FuncContext)
|
||||
|
||||
// RegisterGet is called by Config to register a function to get a component by his key.
|
||||
// This function can be used for dependencies into start / reload function.
|
||||
RegisterGet(fct FuncComponentGet)
|
||||
|
||||
// RegisterFuncStartBefore is called to register a function to be called before the start function.
|
||||
RegisterFuncStartBefore(fct func() liberr.Error)
|
||||
|
||||
// RegisterFuncStartAfter is called to register a function to be called after the start function.
|
||||
RegisterFuncStartAfter(fct func() liberr.Error)
|
||||
|
||||
// RegisterFuncReloadBefore is called to register a function to be called before the reload function.
|
||||
RegisterFuncReloadBefore(fct func() liberr.Error)
|
||||
|
||||
// RegisterFuncReloadAfter is called to register a function to be called after the reload function.
|
||||
RegisterFuncReloadAfter(fct func() liberr.Error)
|
||||
|
||||
// Start is called by the Config interface when the global configuration as been started
|
||||
// This function can be usefull to start server in go routine with a configuration stored
|
||||
// itself.
|
||||
Start(getCpt FuncComponentGet, getCfg FuncComponentConfigGet) liberr.Error
|
||||
|
||||
// IsStarted is trigger by the Config interface with function ComponentIsStarted.
|
||||
// This function can be usefull to know if the start server function is still call.
|
||||
IsStarted() bool
|
||||
|
||||
// Reload is called by the Config interface when the global configuration as been updated
|
||||
// It receives a func as param to grab a config model by sending a model structure.
|
||||
// It must configure itself, and stop / start his server if possible or return an error.
|
||||
Reload(getCpt FuncComponentGet, getCfg FuncComponentConfigGet) liberr.Error
|
||||
|
||||
// Stop is called by the Config interface when global context is done.
|
||||
// The context done can arrive by stopping the application or by received a signal KILL/TERM.
|
||||
// This function must stop cleanly the component.
|
||||
Stop()
|
||||
|
||||
// IsRunning is trigger by the Config interface with function ComponentIsRunning.
|
||||
// This function can be usefully to know if the component server function is still call.
|
||||
// The atLeast param is used to know if the function must return true on first server is running
|
||||
// or if all server must be running to return true.
|
||||
IsRunning(atLeast bool) bool
|
||||
|
||||
// DefaultConfig is called by Config.GetDefault.
|
||||
// It must return a slice of byte containing the default json config for this component.
|
||||
DefaultConfig() []byte
|
||||
|
||||
// Dependencies is called by Config to define if this component need other component.
|
||||
// Each other component can be call by calling Config.Get
|
||||
Dependencies() []string
|
||||
}
|
||||
45
config/components/head/default.go
Normal file
45
config/components/head/default.go
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 head
|
||||
|
||||
var _defaultConfig = []byte(`{
|
||||
"Content-Security-Policy":"default-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data: image/svg+xml*; font-src 'self'; connect-src 'self'; media-src 'self'; object-src 'self'; child-src 'none'; frame-src 'none'; worker-src 'none'; frame-ancestors 'none'; form-action 'none'; upgrade-insecure-requests 1; block-all-mixed-content; disown-opener; require-sri-for script style; sandbox allow-same-origin allow-scripts; reflected-xss block; referrer no-referrer",
|
||||
"Feature-Policy":"geolocation 'self'; midi 'self'; notifications 'self'; push 'self'; sync-xhr 'self'; microphone 'self'; camera 'self'; magnetometer 'self'; gyroscope 'self'; speaker 'self'; vibrate 'self'; fullscreen 'self'; payment 'self';",
|
||||
"Strict-Transport-Security":"max-age=1; preload; includeSubDomains",
|
||||
"X-Frame-Options":"DENY",
|
||||
"X-Xss-Protection":"1; mode=block",
|
||||
"X-Content-Type-Options":"nosniff",
|
||||
"Referrer-Policy":"no-referrer"
|
||||
}`)
|
||||
|
||||
func (c *componentHead) DefaultConfig() []byte {
|
||||
return _defaultConfig
|
||||
}
|
||||
|
||||
func SetDefaultConfig(cfg []byte) {
|
||||
_defaultConfig = cfg
|
||||
}
|
||||
71
config/components/head/errors.go
Normal file
71
config/components/head/errors.go
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 head
|
||||
|
||||
import (
|
||||
libcfg "github.com/nabbar/golib/config"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorParamsEmpty liberr.CodeError = iota + libcfg.MinErrorComponentHttp
|
||||
ErrorParamsInvalid
|
||||
ErrorComponentNotInitialized
|
||||
ErrorConfigInvalid
|
||||
ErrorReloadPoolServer
|
||||
ErrorReloadTLSDefault
|
||||
)
|
||||
|
||||
func init() {
|
||||
isCodeError = liberr.ExistInMapMessage(ErrorParamsEmpty)
|
||||
liberr.RegisterIdFctMessage(ErrorParamsEmpty, getMessage)
|
||||
}
|
||||
|
||||
var isCodeError = false
|
||||
|
||||
func IsCodeError() bool {
|
||||
return isCodeError
|
||||
}
|
||||
|
||||
func getMessage(code liberr.CodeError) (message string) {
|
||||
switch code {
|
||||
case ErrorParamsEmpty:
|
||||
return "at least one given parameters is empty"
|
||||
case ErrorParamsInvalid:
|
||||
return "at least one given parameters is invalid"
|
||||
case ErrorComponentNotInitialized:
|
||||
return "this component seems to not be correctly initialized"
|
||||
case ErrorConfigInvalid:
|
||||
return "server invalid config"
|
||||
case ErrorReloadPoolServer:
|
||||
return "cannot update pool servers with new config"
|
||||
case ErrorReloadTLSDefault:
|
||||
return "cannot update default TLS with new config"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
67
config/components/head/interface.go
Normal file
67
config/components/head/interface.go
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 head
|
||||
|
||||
import (
|
||||
libcfg "github.com/nabbar/golib/config"
|
||||
librtr "github.com/nabbar/golib/router"
|
||||
)
|
||||
|
||||
const (
|
||||
ComponentType = "head"
|
||||
)
|
||||
|
||||
type ComponentHead interface {
|
||||
libcfg.Component
|
||||
|
||||
GetHeaders() librtr.Headers
|
||||
SetHeaders(head librtr.Headers)
|
||||
}
|
||||
|
||||
func New() ComponentHead {
|
||||
return &componentHead{
|
||||
head: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func Register(cfg libcfg.Config, key string, cpt ComponentHead) {
|
||||
cfg.ComponentSet(key, cpt)
|
||||
}
|
||||
|
||||
func RegisterNew(cfg libcfg.Config, key string) {
|
||||
cfg.ComponentSet(key, New())
|
||||
}
|
||||
|
||||
func Load(getCpt libcfg.FuncComponentGet, key string) ComponentHead {
|
||||
if c := getCpt(key); c == nil {
|
||||
return nil
|
||||
} else if h, ok := c.(ComponentHead); !ok {
|
||||
return nil
|
||||
} else {
|
||||
return h
|
||||
}
|
||||
}
|
||||
171
config/components/head/model.go
Normal file
171
config/components/head/model.go
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package head
|
||||
|
||||
import (
|
||||
libcfg "github.com/nabbar/golib/config"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
libhts "github.com/nabbar/golib/httpserver"
|
||||
librtr "github.com/nabbar/golib/router"
|
||||
)
|
||||
|
||||
type DefaultModel struct {
|
||||
Head librtr.HeadersConfig
|
||||
Http libhts.PoolServerConfig
|
||||
}
|
||||
|
||||
type componentHead struct {
|
||||
ctx libcfg.FuncContext
|
||||
get libcfg.FuncComponentGet
|
||||
fsa func() liberr.Error
|
||||
fsb func() liberr.Error
|
||||
fra func() liberr.Error
|
||||
frb func() liberr.Error
|
||||
|
||||
head librtr.Headers
|
||||
}
|
||||
|
||||
func (c *componentHead) Type() string {
|
||||
return ComponentType
|
||||
}
|
||||
|
||||
func (c *componentHead) RegisterContext(fct libcfg.FuncContext) {
|
||||
c.ctx = fct
|
||||
}
|
||||
|
||||
func (c *componentHead) RegisterGet(fct libcfg.FuncComponentGet) {
|
||||
c.get = fct
|
||||
}
|
||||
|
||||
func (c *componentHead) RegisterFuncStartBefore(fct func() liberr.Error) {
|
||||
c.fsb = fct
|
||||
}
|
||||
|
||||
func (c *componentHead) RegisterFuncStartAfter(fct func() liberr.Error) {
|
||||
c.fsa = fct
|
||||
}
|
||||
|
||||
func (c *componentHead) RegisterFuncReloadBefore(fct func() liberr.Error) {
|
||||
c.frb = fct
|
||||
}
|
||||
|
||||
func (c *componentHead) RegisterFuncReloadAfter(fct func() liberr.Error) {
|
||||
c.fra = fct
|
||||
}
|
||||
|
||||
func (c *componentHead) _run(getCfg libcfg.FuncComponentConfigGet) liberr.Error {
|
||||
if c == nil {
|
||||
return ErrorComponentNotInitialized.Error(nil)
|
||||
}
|
||||
|
||||
cnf := DefaultModel{}
|
||||
if err := getCfg(&cnf); err != nil {
|
||||
return ErrorParamsInvalid.Error(err)
|
||||
}
|
||||
|
||||
c.head = cnf.Head.New()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *componentHead) Start(getCpt libcfg.FuncComponentGet, getCfg libcfg.FuncComponentConfigGet) liberr.Error {
|
||||
var err liberr.Error
|
||||
|
||||
if c.fsb != nil {
|
||||
if err = c.fsb(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = c._run(getCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.fsa != nil {
|
||||
if err = c.fsa(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *componentHead) Reload(getCpt libcfg.FuncComponentGet, getCfg libcfg.FuncComponentConfigGet) liberr.Error {
|
||||
var (
|
||||
err liberr.Error
|
||||
)
|
||||
|
||||
if c.frb != nil {
|
||||
if err = c.frb(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = c._run(getCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.fra != nil {
|
||||
if err = c.fra(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *componentHead) Stop() {
|
||||
|
||||
}
|
||||
|
||||
func (c *componentHead) IsStarted() bool {
|
||||
return c.head == nil
|
||||
}
|
||||
|
||||
func (c *componentHead) IsRunning(atLeast bool) bool {
|
||||
return c.head == nil
|
||||
}
|
||||
|
||||
func (c *componentHead) Dependencies() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (c *componentHead) GetHeaders() librtr.Headers {
|
||||
if c == nil || c.head == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return c.head
|
||||
}
|
||||
|
||||
func (c *componentHead) SetHeaders(head librtr.Headers) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.head = head
|
||||
}
|
||||
113
config/components/http/default.go
Normal file
113
config/components/http/default.go
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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 http
|
||||
|
||||
var _defaultConfig = []byte(`[
|
||||
{
|
||||
"disabled":false,
|
||||
"mandatory":true,
|
||||
"timeout_cache_info":"30s",
|
||||
"timeout_cache_health":"30s",
|
||||
"read_timeout":"0s",
|
||||
"read_header_timeout":"0s",
|
||||
"write_timeout":"0s",
|
||||
"idle_timeout":"0s",
|
||||
"max_header_bytes":0,
|
||||
"max_handlers":0,
|
||||
"max_concurrent_streams":0,
|
||||
"max_read_frame_size":0,
|
||||
"permit_prohibited_cipher_suites":false,
|
||||
"max_upload_buffer_per_connection":0,
|
||||
"max_upload_buffer_per_stream":0,
|
||||
"name":"status_http",
|
||||
"handler_keys":"status",
|
||||
"tls_mandatory":false,
|
||||
"listen":"0.0.0.0:6080",
|
||||
"expose":"http://0.0.0.0",
|
||||
"tls":{
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
"disabled":false,
|
||||
"mandatory":true,
|
||||
"timeout_cache_info":"30s",
|
||||
"timeout_cache_health":"30s",
|
||||
"read_timeout":"0s",
|
||||
"read_header_timeout":"0s",
|
||||
"write_timeout":"0s",
|
||||
"idle_timeout":"0s",
|
||||
"max_header_bytes":0,
|
||||
"max_handlers":0,
|
||||
"max_concurrent_streams":0,
|
||||
"max_read_frame_size":0,
|
||||
"permit_prohibited_cipher_suites":false,
|
||||
"max_upload_buffer_per_connection":0,
|
||||
"max_upload_buffer_per_stream":0,
|
||||
"handler_keys":"api",
|
||||
"tls_mandatory":false,
|
||||
"name":"api_http",
|
||||
"listen":"0.0.0.0:7080",
|
||||
"expose":"http://0.0.0.0",
|
||||
"tls":{
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
"disabled":false,
|
||||
"mandatory":true,
|
||||
"timeout_cache_info":"30s",
|
||||
"timeout_cache_health":"30s",
|
||||
"read_timeout":"0s",
|
||||
"read_header_timeout":"0s",
|
||||
"write_timeout":"0s",
|
||||
"idle_timeout":"0s",
|
||||
"max_header_bytes":0,
|
||||
"max_handlers":0,
|
||||
"max_concurrent_streams":0,
|
||||
"max_read_frame_size":0,
|
||||
"permit_prohibited_cipher_suites":false,
|
||||
"max_upload_buffer_per_connection":0,
|
||||
"max_upload_buffer_per_stream":0,
|
||||
"handler_keys":"metrics",
|
||||
"tls_mandatory":false,
|
||||
"name":"metrics_http",
|
||||
"listen":"0.0.0.0:8080",
|
||||
"expose":"http://0.0.0.0",
|
||||
"tls":{
|
||||
|
||||
}
|
||||
}
|
||||
]`)
|
||||
|
||||
func (c *componentHttp) DefaultConfig() []byte {
|
||||
return _defaultConfig
|
||||
}
|
||||
|
||||
func SetDefaultConfig(cfg []byte) {
|
||||
_defaultConfig = cfg
|
||||
}
|
||||
77
config/components/http/errors.go
Normal file
77
config/components/http/errors.go
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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 http
|
||||
|
||||
import (
|
||||
libcfg "github.com/nabbar/golib/config"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorParamsEmpty liberr.CodeError = iota + libcfg.MinErrorComponentHttp
|
||||
ErrorParamsInvalid
|
||||
ErrorComponentNotInitialized
|
||||
ErrorConfigInvalid
|
||||
ErrorStartPoolServer
|
||||
ErrorReloadPoolServer
|
||||
ErrorDependencyTLSDefault
|
||||
ErrorDependencyLogDefault
|
||||
)
|
||||
|
||||
func init() {
|
||||
isCodeError = liberr.ExistInMapMessage(ErrorParamsEmpty)
|
||||
liberr.RegisterIdFctMessage(ErrorParamsEmpty, getMessage)
|
||||
}
|
||||
|
||||
var isCodeError = false
|
||||
|
||||
func IsCodeError() bool {
|
||||
return isCodeError
|
||||
}
|
||||
|
||||
func getMessage(code liberr.CodeError) (message string) {
|
||||
switch code {
|
||||
case ErrorParamsEmpty:
|
||||
return "at least one given parameters is empty"
|
||||
case ErrorParamsInvalid:
|
||||
return "at least one given parameters is invalid"
|
||||
case ErrorComponentNotInitialized:
|
||||
return "this component seems to not be correctly initialized"
|
||||
case ErrorConfigInvalid:
|
||||
return "server invalid config"
|
||||
case ErrorStartPoolServer:
|
||||
return "cannot start new pool servers with config"
|
||||
case ErrorReloadPoolServer:
|
||||
return "cannot update pool servers with new config"
|
||||
case ErrorDependencyTLSDefault:
|
||||
return "cannot retrieve default TLS"
|
||||
case ErrorDependencyLogDefault:
|
||||
return "cannot retrieve default Logger"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
87
config/components/http/interface.go
Normal file
87
config/components/http/interface.go
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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 http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
libcfg "github.com/nabbar/golib/config"
|
||||
libhts "github.com/nabbar/golib/httpserver"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultTlsKey = "tls"
|
||||
DefaultLogKey = "log"
|
||||
ComponentType = "http"
|
||||
)
|
||||
|
||||
type ComponentHttp interface {
|
||||
libcfg.Component
|
||||
|
||||
SetTLSKey(tlsKey string)
|
||||
SetLOGKey(logKey string)
|
||||
SetHandler(handler map[string]http.Handler)
|
||||
|
||||
GetPool() libhts.PoolServer
|
||||
SetPool(pool libhts.PoolServer)
|
||||
}
|
||||
|
||||
func New(tlsKey, logKey string, handler map[string]http.Handler) ComponentHttp {
|
||||
if tlsKey == "" {
|
||||
tlsKey = DefaultTlsKey
|
||||
}
|
||||
|
||||
if logKey == "" {
|
||||
logKey = DefaultLogKey
|
||||
}
|
||||
|
||||
return &componentHttp{
|
||||
tls: tlsKey,
|
||||
log: logKey,
|
||||
run: false,
|
||||
hand: handler,
|
||||
pool: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func Register(cfg libcfg.Config, key string, cpt ComponentHttp) {
|
||||
cfg.ComponentSet(key, cpt)
|
||||
}
|
||||
|
||||
func RegisterNew(cfg libcfg.Config, key string, tlsKey, logKey string, handler map[string]http.Handler) {
|
||||
cfg.ComponentSet(key, New(tlsKey, logKey, handler))
|
||||
}
|
||||
|
||||
func Load(getCpt libcfg.FuncComponentGet, key string) ComponentHttp {
|
||||
if c := getCpt(key); c == nil {
|
||||
return nil
|
||||
} else if h, ok := c.(ComponentHttp); !ok {
|
||||
return nil
|
||||
} else {
|
||||
return h
|
||||
}
|
||||
}
|
||||
306
config/components/http/model.go
Normal file
306
config/components/http/model.go
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* 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 http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
libcfg "github.com/nabbar/golib/config"
|
||||
cptlog "github.com/nabbar/golib/config/components/log"
|
||||
cpttls "github.com/nabbar/golib/config/components/tls"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
libhts "github.com/nabbar/golib/httpserver"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
)
|
||||
|
||||
type componentHttp struct {
|
||||
ctx libcfg.FuncContext
|
||||
get libcfg.FuncComponentGet
|
||||
fsa func() liberr.Error
|
||||
fsb func() liberr.Error
|
||||
fra func() liberr.Error
|
||||
frb func() liberr.Error
|
||||
|
||||
tls string
|
||||
log string
|
||||
|
||||
run bool
|
||||
hand map[string]http.Handler
|
||||
|
||||
pool libhts.PoolServer
|
||||
}
|
||||
|
||||
func (c *componentHttp) _CheckDep() bool {
|
||||
return c != nil && len(c.hand) > 0 && c.tls != "" && c.log != ""
|
||||
}
|
||||
|
||||
func (c *componentHttp) _CheckInit() bool {
|
||||
return c != nil && c._CheckDep() && c.pool != nil
|
||||
}
|
||||
|
||||
func (c *componentHttp) Type() string {
|
||||
return ComponentType
|
||||
}
|
||||
|
||||
func (c *componentHttp) RegisterContext(fct libcfg.FuncContext) {
|
||||
c.ctx = fct
|
||||
}
|
||||
|
||||
func (c *componentHttp) RegisterGet(fct libcfg.FuncComponentGet) {
|
||||
c.get = fct
|
||||
}
|
||||
|
||||
func (c *componentHttp) RegisterFuncStartBefore(fct func() liberr.Error) {
|
||||
c.fsb = fct
|
||||
}
|
||||
|
||||
func (c *componentHttp) RegisterFuncStartAfter(fct func() liberr.Error) {
|
||||
c.fsa = fct
|
||||
}
|
||||
|
||||
func (c *componentHttp) RegisterFuncReloadBefore(fct func() liberr.Error) {
|
||||
c.frb = fct
|
||||
}
|
||||
|
||||
func (c *componentHttp) RegisterFuncReloadAfter(fct func() liberr.Error) {
|
||||
c.fra = fct
|
||||
}
|
||||
|
||||
func (c *componentHttp) getTLS(getCpt libcfg.FuncComponentGet) (libtls.TLSConfig, liberr.Error) {
|
||||
if !c._CheckDep() {
|
||||
return nil, ErrorComponentNotInitialized.Error(nil)
|
||||
}
|
||||
|
||||
if i := cpttls.Load(getCpt, c.tls); i == nil {
|
||||
return nil, ErrorDependencyTLSDefault.Error(nil)
|
||||
} else if tls := i.GetTLS(); tls == nil {
|
||||
return nil, ErrorDependencyTLSDefault.Error(nil)
|
||||
} else {
|
||||
return tls, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *componentHttp) getLogger(getCpt libcfg.FuncComponentGet) (liblog.Logger, liberr.Error) {
|
||||
if !c._CheckDep() {
|
||||
return nil, ErrorComponentNotInitialized.Error(nil)
|
||||
}
|
||||
|
||||
if i := cptlog.Load(getCpt, c.log); i == nil {
|
||||
return nil, ErrorDependencyLogDefault.Error(nil)
|
||||
} else if log := i.Log(); log == nil {
|
||||
return nil, ErrorDependencyLogDefault.Error(nil)
|
||||
} else {
|
||||
return log, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *componentHttp) _getPoolServerConfig(getCpt libcfg.FuncComponentGet, getCfg libcfg.FuncComponentConfigGet) (libhts.PoolServerConfig, liberr.Error) {
|
||||
cnf := make(libhts.PoolServerConfig, 0)
|
||||
|
||||
if !c._CheckDep() {
|
||||
return cnf, ErrorComponentNotInitialized.Error(nil)
|
||||
}
|
||||
|
||||
if err := getCfg(&cnf); err != nil {
|
||||
return cnf, ErrorParamsInvalid.Error(err)
|
||||
}
|
||||
|
||||
if tls, err := c.getTLS(getCpt); err != nil {
|
||||
return cnf, err
|
||||
} else {
|
||||
cnf.MapUpdate(func(sCFG libhts.ServerConfig) libhts.ServerConfig {
|
||||
sCFG.SetDefaultTLS(func() libtls.TLSConfig {
|
||||
return tls
|
||||
})
|
||||
|
||||
sCFG.SetParentContext(c.ctx)
|
||||
return sCFG
|
||||
})
|
||||
}
|
||||
|
||||
if err := cnf.Validate(); err != nil {
|
||||
return cnf, ErrorConfigInvalid.Error(err)
|
||||
} else if len(c.hand) < 1 {
|
||||
return cnf, ErrorComponentNotInitialized.ErrorParent(fmt.Errorf("missing handler"))
|
||||
}
|
||||
|
||||
return cnf, nil
|
||||
}
|
||||
|
||||
func (c *componentHttp) Start(getCpt libcfg.FuncComponentGet, getCfg libcfg.FuncComponentConfigGet) liberr.Error {
|
||||
var (
|
||||
err liberr.Error
|
||||
cnf libhts.PoolServerConfig
|
||||
)
|
||||
|
||||
if c.fsb != nil {
|
||||
if err = c.fsb(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if cnf, err = c._getPoolServerConfig(getCpt, getCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p, e := cnf.PoolServer(); e != nil {
|
||||
return ErrorStartPoolServer.Error(e)
|
||||
} else {
|
||||
c.pool = p
|
||||
}
|
||||
|
||||
c.pool.SetLogger(func() liblog.Logger {
|
||||
if log, err := c.getLogger(getCpt); err != nil {
|
||||
return liblog.GetDefault()
|
||||
} else {
|
||||
return log
|
||||
}
|
||||
})
|
||||
|
||||
if err = c.pool.ListenMultiHandler(c.hand); err != nil {
|
||||
return ErrorStartPoolServer.Error(err)
|
||||
}
|
||||
|
||||
if c.fsa != nil {
|
||||
if err = c.fsa(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *componentHttp) Reload(getCpt libcfg.FuncComponentGet, getCfg libcfg.FuncComponentConfigGet) liberr.Error {
|
||||
var (
|
||||
err liberr.Error
|
||||
cnf libhts.PoolServerConfig
|
||||
)
|
||||
|
||||
if c.frb != nil {
|
||||
if err = c.frb(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if cnf, err = c._getPoolServerConfig(getCpt, getCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.pool != nil {
|
||||
if p, e := cnf.UpdatePoolServer(c.pool); e != nil {
|
||||
return ErrorReloadPoolServer.Error(e)
|
||||
} else {
|
||||
c.pool = p
|
||||
}
|
||||
} else if p, e := cnf.PoolServer(); e != nil {
|
||||
return ErrorReloadPoolServer.Error(e)
|
||||
} else {
|
||||
c.pool = p
|
||||
}
|
||||
|
||||
c.pool.SetLogger(func() liblog.Logger {
|
||||
if log, err := c.getLogger(getCpt); err != nil {
|
||||
return liblog.GetDefault()
|
||||
} else {
|
||||
return log
|
||||
}
|
||||
})
|
||||
|
||||
c.pool.Restart()
|
||||
|
||||
if c.fra != nil {
|
||||
if err = c.fra(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *componentHttp) Stop() {
|
||||
c.run = false
|
||||
|
||||
if !c._CheckInit() {
|
||||
return
|
||||
}
|
||||
|
||||
c.pool.Shutdown()
|
||||
}
|
||||
|
||||
func (c *componentHttp) IsStarted() bool {
|
||||
return c._CheckInit() && c.pool.IsRunning(true)
|
||||
}
|
||||
|
||||
func (c *componentHttp) IsRunning(atLeast bool) bool {
|
||||
return c._CheckInit() && c.pool.IsRunning(atLeast)
|
||||
}
|
||||
|
||||
func (c *componentHttp) Dependencies() []string {
|
||||
return []string{cpttls.ComponentType, cptlog.ComponentType}
|
||||
}
|
||||
|
||||
func (c *componentHttp) SetTLSKey(tlsKey string) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.tls = tlsKey
|
||||
}
|
||||
|
||||
func (c *componentHttp) SetLOGKey(logKey string) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.log = logKey
|
||||
}
|
||||
|
||||
func (c *componentHttp) SetHandler(handler map[string]http.Handler) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.hand = handler
|
||||
}
|
||||
|
||||
func (c *componentHttp) GetPool() libhts.PoolServer {
|
||||
if c == nil || c.pool == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return c.pool
|
||||
}
|
||||
|
||||
func (c *componentHttp) SetPool(pool libhts.PoolServer) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.pool = pool
|
||||
}
|
||||
85
config/components/log/default.go
Normal file
85
config/components/log/default.go
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package log
|
||||
|
||||
var _defaultConfig = []byte(`
|
||||
{
|
||||
"disableStandard":false,
|
||||
"disableStack":false,
|
||||
"disableTimestamp":false,
|
||||
"enableTrace":true,
|
||||
"traceFilter":"",
|
||||
"disableColor":false,
|
||||
"logFile":[
|
||||
{
|
||||
"logLevel":[
|
||||
"Debug",
|
||||
"Info",
|
||||
"Warning",
|
||||
"Error",
|
||||
"Fatal",
|
||||
"Critical"
|
||||
],
|
||||
"filepath":"",
|
||||
"create":false,
|
||||
"createPath":false,
|
||||
"fileMode":"0644",
|
||||
"pathMode":"0755",
|
||||
"disableStack":false,
|
||||
"disableTimestamp":false,
|
||||
"enableTrace":true
|
||||
}
|
||||
],
|
||||
"logSyslog":[
|
||||
{
|
||||
"logLevel":[
|
||||
"Debug",
|
||||
"Info",
|
||||
"Warning",
|
||||
"Error",
|
||||
"Fatal",
|
||||
"Critical"
|
||||
],
|
||||
"network":"tcp",
|
||||
"host":"",
|
||||
"severity":"Error",
|
||||
"facility":"local0",
|
||||
"tag":"",
|
||||
"disableStack":false,
|
||||
"disableTimestamp":false,
|
||||
"enableTrace":true
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
func (c *componentLog) DefaultConfig() []byte {
|
||||
return _defaultConfig
|
||||
}
|
||||
|
||||
func SetDefaultConfig(cfg []byte) {
|
||||
_defaultConfig = cfg
|
||||
}
|
||||
71
config/components/log/errors.go
Normal file
71
config/components/log/errors.go
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 log
|
||||
|
||||
import (
|
||||
libcfg "github.com/nabbar/golib/config"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorParamsEmpty liberr.CodeError = iota + libcfg.MinErrorComponentLog
|
||||
ErrorParamsInvalid
|
||||
ErrorConfigInvalid
|
||||
ErrorComponentNotInitialized
|
||||
ErrorStartLog
|
||||
ErrorReloadLog
|
||||
)
|
||||
|
||||
func init() {
|
||||
isCodeError = liberr.ExistInMapMessage(ErrorParamsEmpty)
|
||||
liberr.RegisterIdFctMessage(ErrorParamsEmpty, getMessage)
|
||||
}
|
||||
|
||||
var isCodeError = false
|
||||
|
||||
func IsCodeError() bool {
|
||||
return isCodeError
|
||||
}
|
||||
|
||||
func getMessage(code liberr.CodeError) (message string) {
|
||||
switch code {
|
||||
case ErrorParamsEmpty:
|
||||
return "at least one given parameters is empty"
|
||||
case ErrorParamsInvalid:
|
||||
return "at least one given parameters is invalid"
|
||||
case ErrorConfigInvalid:
|
||||
return "server invalid config"
|
||||
case ErrorComponentNotInitialized:
|
||||
return "this component seems to not be correctly initialized"
|
||||
case ErrorStartLog:
|
||||
return "cannot start Logger"
|
||||
case ErrorReloadLog:
|
||||
return "cannot update Logger with new config"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
74
config/components/log/interface.go
Normal file
74
config/components/log/interface.go
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 log
|
||||
|
||||
import (
|
||||
libcfg "github.com/nabbar/golib/config"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultLevel = liblog.InfoLevel
|
||||
ComponentType = "log"
|
||||
)
|
||||
|
||||
type ComponentLog interface {
|
||||
libcfg.Component
|
||||
|
||||
Log() liblog.Logger
|
||||
|
||||
SetLevel(lvl liblog.Level)
|
||||
SetField(fields liblog.Fields)
|
||||
SetOptions(opt *liblog.Options) liberr.Error
|
||||
}
|
||||
|
||||
func New(lvl liblog.Level, defLogger func() liblog.Logger) ComponentLog {
|
||||
return &componentLog{
|
||||
d: defLogger,
|
||||
l: nil,
|
||||
v: lvl,
|
||||
}
|
||||
}
|
||||
|
||||
func Register(cfg libcfg.Config, key string, cpt ComponentLog) {
|
||||
cfg.ComponentSet(key, cpt)
|
||||
}
|
||||
|
||||
func RegisterNew(cfg libcfg.Config, key string, lvl liblog.Level, defLogger func() liblog.Logger) {
|
||||
cfg.ComponentSet(key, New(lvl, defLogger))
|
||||
}
|
||||
|
||||
func Load(getCpt libcfg.FuncComponentGet, key string) ComponentLog {
|
||||
if c := getCpt(key); c == nil {
|
||||
return nil
|
||||
} else if h, ok := c.(ComponentLog); !ok {
|
||||
return nil
|
||||
} else {
|
||||
return h
|
||||
}
|
||||
}
|
||||
196
config/components/log/model.go
Normal file
196
config/components/log/model.go
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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 log
|
||||
|
||||
import (
|
||||
libcfg "github.com/nabbar/golib/config"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
)
|
||||
|
||||
type DefaultModel struct {
|
||||
liblog.Options
|
||||
}
|
||||
|
||||
type componentLog struct {
|
||||
ctx libcfg.FuncContext
|
||||
get libcfg.FuncComponentGet
|
||||
fsa func() liberr.Error
|
||||
fsb func() liberr.Error
|
||||
fra func() liberr.Error
|
||||
frb func() liberr.Error
|
||||
|
||||
d func() liblog.Logger
|
||||
l liblog.Logger
|
||||
v liblog.Level
|
||||
}
|
||||
|
||||
func (c *componentLog) Type() string {
|
||||
return ComponentType
|
||||
}
|
||||
|
||||
func (c *componentLog) RegisterContext(fct libcfg.FuncContext) {
|
||||
c.ctx = fct
|
||||
}
|
||||
|
||||
func (c *componentLog) RegisterGet(fct libcfg.FuncComponentGet) {
|
||||
c.get = fct
|
||||
}
|
||||
|
||||
func (c *componentLog) RegisterFuncStartBefore(fct func() liberr.Error) {
|
||||
c.fsb = fct
|
||||
}
|
||||
|
||||
func (c *componentLog) RegisterFuncStartAfter(fct func() liberr.Error) {
|
||||
c.fsa = fct
|
||||
}
|
||||
|
||||
func (c *componentLog) RegisterFuncReloadBefore(fct func() liberr.Error) {
|
||||
c.frb = fct
|
||||
}
|
||||
|
||||
func (c *componentLog) RegisterFuncReloadAfter(fct func() liberr.Error) {
|
||||
c.fra = fct
|
||||
}
|
||||
|
||||
func (c *componentLog) _run(errCode liberr.CodeError, getCfg libcfg.FuncComponentConfigGet) liberr.Error {
|
||||
if c.ctx == nil {
|
||||
return ErrorComponentNotInitialized.Error(nil)
|
||||
}
|
||||
|
||||
if c.l == nil {
|
||||
c.l = liblog.New(c.ctx())
|
||||
}
|
||||
|
||||
cnf := DefaultModel{}
|
||||
if err := getCfg(&cnf); err != nil {
|
||||
return ErrorParamsInvalid.Error(err)
|
||||
} else if err = cnf.Validate(); err != nil {
|
||||
return ErrorConfigInvalid.Error(err)
|
||||
} else if e := c.l.SetOptions(&cnf.Options); e != nil {
|
||||
return errCode.ErrorParent(e)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *componentLog) Start(getCpt libcfg.FuncComponentGet, getCfg libcfg.FuncComponentConfigGet) liberr.Error {
|
||||
var err liberr.Error
|
||||
|
||||
if c.fsb != nil {
|
||||
if err = c.fsb(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = c._run(ErrorStartLog, getCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.fsa != nil {
|
||||
if err = c.fsa(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *componentLog) Reload(getCpt libcfg.FuncComponentGet, getCfg libcfg.FuncComponentConfigGet) liberr.Error {
|
||||
var err liberr.Error
|
||||
|
||||
if c.frb != nil {
|
||||
if err = c.frb(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = c._run(ErrorStartLog, getCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.fra != nil {
|
||||
if err = c.fra(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *componentLog) Stop() {
|
||||
|
||||
}
|
||||
|
||||
func (c *componentLog) IsStarted() bool {
|
||||
return c.l != nil
|
||||
}
|
||||
|
||||
func (c *componentLog) IsRunning(atLeast bool) bool {
|
||||
return c.l != nil
|
||||
}
|
||||
|
||||
func (c *componentLog) Dependencies() []string {
|
||||
return make([]string, 0)
|
||||
}
|
||||
|
||||
func (c *componentLog) Log() liblog.Logger {
|
||||
if c.l != nil {
|
||||
_l, _ := c.l.Clone()
|
||||
return _l
|
||||
}
|
||||
|
||||
return c.d()
|
||||
}
|
||||
|
||||
func (c *componentLog) SetLevel(lvl liblog.Level) {
|
||||
if c.l != nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.l.SetLevel(lvl)
|
||||
}
|
||||
|
||||
func (c *componentLog) SetField(fields liblog.Fields) {
|
||||
if c.l != nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.l.SetFields(fields)
|
||||
}
|
||||
|
||||
func (c *componentLog) SetOptions(opt *liblog.Options) liberr.Error {
|
||||
if c.l != nil {
|
||||
return ErrorComponentNotInitialized.Error(nil)
|
||||
}
|
||||
|
||||
if e := c.l.SetOptions(opt); e != nil {
|
||||
return ErrorConfigInvalid.ErrorParent(e)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
83
config/components/tls/default.go
Normal file
83
config/components/tls/default.go
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 tls
|
||||
|
||||
var _defaultConfig = []byte(`{
|
||||
"versionMin":"1.2",
|
||||
"versionMax":"1.2",
|
||||
"dynamicSizingDisable":false,
|
||||
"sessionTicketDisable":false,
|
||||
"authClient":"none",
|
||||
"curveList":[
|
||||
"X25519",
|
||||
"P256",
|
||||
"P384",
|
||||
"P521"
|
||||
],
|
||||
"cipherList":[
|
||||
"RSA-AES128-GCM",
|
||||
"RSA-AES128-CBC",
|
||||
"RSA-AES256-GCM",
|
||||
"RSA-CHACHA",
|
||||
"ECDSA-AES128-GCM",
|
||||
"ECDSA-AES128-CBC",
|
||||
"ECDSA-AES256-GCM",
|
||||
"ECDSA-CHACHA"
|
||||
],
|
||||
"rootCA":[
|
||||
""
|
||||
],
|
||||
"rootCAFiles":[
|
||||
""
|
||||
],
|
||||
"clientCA":[
|
||||
""
|
||||
],
|
||||
"clientCAFiles":[
|
||||
""
|
||||
],
|
||||
"certPair":[
|
||||
{
|
||||
"key":"",
|
||||
"pem":""
|
||||
}
|
||||
],
|
||||
"certPairFiles":[
|
||||
{
|
||||
"key":"",
|
||||
"pem":""
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
func (c *componentTls) DefaultConfig() []byte {
|
||||
return _defaultConfig
|
||||
}
|
||||
|
||||
func SetDefaultConfig(cfg []byte) {
|
||||
_defaultConfig = cfg
|
||||
}
|
||||
71
config/components/tls/errors.go
Normal file
71
config/components/tls/errors.go
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 tls
|
||||
|
||||
import (
|
||||
libcfg "github.com/nabbar/golib/config"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorParamsEmpty liberr.CodeError = iota + libcfg.MinErrorComponentTls
|
||||
ErrorParamsInvalid
|
||||
ErrorConfigInvalid
|
||||
ErrorComponentNotInitialized
|
||||
ErrorStartTLS
|
||||
ErrorReloadTLS
|
||||
)
|
||||
|
||||
func init() {
|
||||
isCodeError = liberr.ExistInMapMessage(ErrorParamsEmpty)
|
||||
liberr.RegisterIdFctMessage(ErrorParamsEmpty, getMessage)
|
||||
}
|
||||
|
||||
var isCodeError = false
|
||||
|
||||
func IsCodeError() bool {
|
||||
return isCodeError
|
||||
}
|
||||
|
||||
func getMessage(code liberr.CodeError) (message string) {
|
||||
switch code {
|
||||
case ErrorParamsEmpty:
|
||||
return "at least one given parameters is empty"
|
||||
case ErrorParamsInvalid:
|
||||
return "at least one given parameters is invalid"
|
||||
case ErrorConfigInvalid:
|
||||
return "server invalid config"
|
||||
case ErrorComponentNotInitialized:
|
||||
return "this component seems to not be correctly initialized"
|
||||
case ErrorStartTLS:
|
||||
return "cannot create new TLS Config"
|
||||
case ErrorReloadTLS:
|
||||
return "cannot update TLS Config"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
66
config/components/tls/interface.go
Normal file
66
config/components/tls/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 tls
|
||||
|
||||
import (
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
libcfg "github.com/nabbar/golib/config"
|
||||
)
|
||||
|
||||
const (
|
||||
ComponentType = "tls"
|
||||
)
|
||||
|
||||
type ComponentTlS interface {
|
||||
libcfg.Component
|
||||
GetTLS() libtls.TLSConfig
|
||||
SetTLS(tls libtls.TLSConfig)
|
||||
}
|
||||
|
||||
func New() ComponentTlS {
|
||||
return &componentTls{
|
||||
tls: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func Register(cfg libcfg.Config, key string, cpt ComponentTlS) {
|
||||
cfg.ComponentSet(key, cpt)
|
||||
}
|
||||
|
||||
func RegisterNew(cfg libcfg.Config, key string) {
|
||||
cfg.ComponentSet(key, New())
|
||||
}
|
||||
|
||||
func Load(getCpt libcfg.FuncComponentGet, key string) ComponentTlS {
|
||||
if c := getCpt(key); c == nil {
|
||||
return nil
|
||||
} else if h, ok := c.(ComponentTlS); !ok {
|
||||
return nil
|
||||
} else {
|
||||
return h
|
||||
}
|
||||
}
|
||||
182
config/components/tls/model.go
Normal file
182
config/components/tls/model.go
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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 tls
|
||||
|
||||
import (
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
libcfg "github.com/nabbar/golib/config"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
type DefaultModel struct {
|
||||
libtls.Config
|
||||
}
|
||||
|
||||
type componentTls struct {
|
||||
ctx libcfg.FuncContext
|
||||
get libcfg.FuncComponentGet
|
||||
fsa func() liberr.Error
|
||||
fsb func() liberr.Error
|
||||
fra func() liberr.Error
|
||||
frb func() liberr.Error
|
||||
|
||||
tls libtls.TLSConfig
|
||||
}
|
||||
|
||||
func (c *componentTls) Type() string {
|
||||
return ComponentType
|
||||
}
|
||||
|
||||
func (c *componentTls) RegisterContext(fct libcfg.FuncContext) {
|
||||
c.ctx = fct
|
||||
}
|
||||
|
||||
func (c *componentTls) RegisterGet(fct libcfg.FuncComponentGet) {
|
||||
c.get = fct
|
||||
}
|
||||
|
||||
func (c *componentTls) RegisterFuncStartBefore(fct func() liberr.Error) {
|
||||
c.fsb = fct
|
||||
}
|
||||
|
||||
func (c *componentTls) RegisterFuncStartAfter(fct func() liberr.Error) {
|
||||
c.fsa = fct
|
||||
}
|
||||
|
||||
func (c *componentTls) RegisterFuncReloadBefore(fct func() liberr.Error) {
|
||||
c.frb = fct
|
||||
}
|
||||
|
||||
func (c *componentTls) RegisterFuncReloadAfter(fct func() liberr.Error) {
|
||||
c.fra = fct
|
||||
}
|
||||
|
||||
func (c *componentTls) _run(errCode liberr.CodeError, getCfg libcfg.FuncComponentConfigGet) (libtls.TLSConfig, liberr.Error) {
|
||||
cnf := DefaultModel{}
|
||||
|
||||
if c == nil {
|
||||
return nil, ErrorComponentNotInitialized.Error(nil)
|
||||
}
|
||||
|
||||
if err := getCfg(&cnf); err != nil {
|
||||
return nil, ErrorParamsInvalid.Error(err)
|
||||
}
|
||||
|
||||
if err := cnf.Validate(); err != nil {
|
||||
return nil, ErrorConfigInvalid.Error(err)
|
||||
}
|
||||
|
||||
if tls, err := cnf.New(); err != nil {
|
||||
return nil, errCode.Error(err)
|
||||
} else {
|
||||
return tls, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *componentTls) Start(getCpt libcfg.FuncComponentGet, getCfg libcfg.FuncComponentConfigGet) liberr.Error {
|
||||
var (
|
||||
err liberr.Error
|
||||
tls libtls.TLSConfig
|
||||
)
|
||||
|
||||
if c.fsb != nil {
|
||||
if err = c.fsb(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if tls, err = c._run(ErrorStartTLS, getCfg); err != nil {
|
||||
return err
|
||||
} else {
|
||||
c.tls = tls
|
||||
}
|
||||
|
||||
if c.fsa != nil {
|
||||
if err = c.fsa(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *componentTls) Reload(getCpt libcfg.FuncComponentGet, getCfg libcfg.FuncComponentConfigGet) liberr.Error {
|
||||
var (
|
||||
err liberr.Error
|
||||
tls libtls.TLSConfig
|
||||
)
|
||||
|
||||
if c.frb != nil {
|
||||
if err = c.frb(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if tls, err = c._run(ErrorReloadTLS, getCfg); err != nil {
|
||||
return err
|
||||
} else {
|
||||
c.tls = tls
|
||||
}
|
||||
|
||||
if c.fra != nil {
|
||||
if err = c.fra(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *componentTls) Stop() {}
|
||||
|
||||
func (c *componentTls) Dependencies() []string {
|
||||
return make([]string, 0)
|
||||
}
|
||||
|
||||
func (c *componentTls) IsStarted() bool {
|
||||
return c.tls != nil
|
||||
}
|
||||
|
||||
func (c *componentTls) IsRunning(atLeast bool) bool {
|
||||
return c.tls != nil
|
||||
}
|
||||
|
||||
func (c *componentTls) GetTLS() libtls.TLSConfig {
|
||||
if c == nil || c.tls == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return c.tls
|
||||
}
|
||||
|
||||
func (c *componentTls) SetTLS(tls libtls.TLSConfig) {
|
||||
if c == nil || tls == nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.tls = tls
|
||||
}
|
||||
355
config/cptList.go
Normal file
355
config/cptList.go
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* 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 (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
type ComponentList interface {
|
||||
// ComponentHas return true if the key is a registered Component
|
||||
ComponentHas(key string) bool
|
||||
|
||||
// ComponentType return the Component Type of the registered key.
|
||||
ComponentType(key string) string
|
||||
|
||||
// ComponentGet return the given component associated with the config Key.
|
||||
// The component can be transTyped to other interface to be exploited
|
||||
ComponentGet(key string) Component
|
||||
|
||||
// ComponentDel remove the given Component key from the config.
|
||||
ComponentDel(key string)
|
||||
|
||||
// ComponentSet stores the given Component with a key.
|
||||
ComponentSet(key string, cpt Component)
|
||||
|
||||
// ComponentList returns a map of stored couple keyType and Component
|
||||
ComponentList() map[string]Component
|
||||
|
||||
// ComponentKeys returns a slice of stored Component keys
|
||||
ComponentKeys() []string
|
||||
|
||||
// ComponentStart trigger the Start function of each Component.
|
||||
// This function will keep the dependencies of each Component.
|
||||
// This function will stop the Start sequence on any error triggered.
|
||||
ComponentStart(getCpt FuncComponentGet, getCfg FuncComponentConfigGet) liberr.Error
|
||||
|
||||
// ComponentIsStarted will trigger the IsStarted function of all registered component.
|
||||
// If any component return false, this func return false.
|
||||
ComponentIsStarted() bool
|
||||
|
||||
// ComponentReload trigger the Reload function of each Component.
|
||||
// This function will keep the dependencies of each Component.
|
||||
// This function will stop the Reload sequence on any error triggered.
|
||||
ComponentReload(getCpt FuncComponentGet, getCfg FuncComponentConfigGet) liberr.Error
|
||||
|
||||
// ComponentStop trigger the Stop function of each Component.
|
||||
// This function will not keep the dependencies of each Component.
|
||||
ComponentStop()
|
||||
|
||||
// ComponentIsRunning will trigger the IsRunning function of all registered component.
|
||||
// If any component return false, this func return false.
|
||||
ComponentIsRunning(atLeast bool) bool
|
||||
|
||||
// DefaultConfig aggregates all registered components' default config
|
||||
// Returns a filled buffer with a complete config json model
|
||||
DefaultConfig() io.Reader
|
||||
}
|
||||
|
||||
func newComponentList() ComponentList {
|
||||
return &componentList{
|
||||
m: sync.Mutex{},
|
||||
l: make(map[string]*atomic.Value, 0),
|
||||
}
|
||||
}
|
||||
|
||||
type componentList struct {
|
||||
m sync.Mutex
|
||||
l map[string]*atomic.Value
|
||||
}
|
||||
|
||||
func (c *componentList) ComponentHas(key string) bool {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
_, ok := c.l[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (c *componentList) ComponentType(key string) string {
|
||||
if !c.ComponentHas(key) {
|
||||
return ""
|
||||
} else if o := c.ComponentGet(key); o == nil {
|
||||
return ""
|
||||
} else {
|
||||
return o.Type()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *componentList) ComponentGet(key string) Component {
|
||||
if !c.ComponentHas(key) {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
if len(c.l) < 1 {
|
||||
c.l = make(map[string]*atomic.Value, 0)
|
||||
}
|
||||
|
||||
if v := c.l[key]; v == nil {
|
||||
return nil
|
||||
} else if i := v.Load(); i == nil {
|
||||
return nil
|
||||
} else if o, ok := i.(Component); !ok {
|
||||
return nil
|
||||
} else {
|
||||
return o
|
||||
}
|
||||
}
|
||||
|
||||
func (c *componentList) ComponentDel(key string) {
|
||||
if !c.ComponentHas(key) {
|
||||
return
|
||||
}
|
||||
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
if len(c.l) < 1 {
|
||||
c.l = make(map[string]*atomic.Value, 0)
|
||||
}
|
||||
|
||||
if v := c.l[key]; v == nil {
|
||||
return
|
||||
} else {
|
||||
c.l[key] = new(atomic.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *componentList) ComponentSet(key string, cpt Component) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
if len(c.l) < 1 {
|
||||
c.l = make(map[string]*atomic.Value, 0)
|
||||
}
|
||||
|
||||
if v, ok := c.l[key]; !ok || v == nil {
|
||||
c.l[key] = new(atomic.Value)
|
||||
}
|
||||
|
||||
c.l[key].Store(cpt)
|
||||
}
|
||||
|
||||
func (c *componentList) ComponentList() map[string]Component {
|
||||
var res = make(map[string]Component, 0)
|
||||
|
||||
for _, k := range c.ComponentKeys() {
|
||||
res[k] = c.ComponentGet(k)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (c *componentList) ComponentKeys() []string {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
var res = make([]string, 0)
|
||||
|
||||
for k := range c.l {
|
||||
res = append(res, k)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (c *componentList) startOne(key string, getCpt FuncComponentGet, getCfg FuncComponentConfigGet) liberr.Error {
|
||||
var cpt Component
|
||||
|
||||
if !c.ComponentHas(key) {
|
||||
return ErrorComponentNotFound.ErrorParent(fmt.Errorf("component: %s", key))
|
||||
} else if cpt = c.ComponentGet(key); cpt == nil {
|
||||
return ErrorComponentNotFound.ErrorParent(fmt.Errorf("component: %s", key))
|
||||
} else if cpt.IsStarted() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if dep := cpt.Dependencies(); len(dep) > 0 {
|
||||
for _, k := range dep {
|
||||
if err := c.startOne(k, getCpt, getCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := cpt.Start(getCpt, getCfg); err != nil {
|
||||
return err
|
||||
} else {
|
||||
c.ComponentSet(key, cpt)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *componentList) ComponentStart(getCpt FuncComponentGet, getCfg FuncComponentConfigGet) liberr.Error {
|
||||
for _, key := range c.ComponentKeys() {
|
||||
if err := c.startOne(key, getCpt, getCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *componentList) ComponentIsStarted() bool {
|
||||
for _, k := range c.ComponentKeys() {
|
||||
if cpt := c.ComponentGet(k); cpt == nil {
|
||||
continue
|
||||
} else if ok := cpt.IsStarted(); !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *componentList) reloadOne(isReload []string, key string, getCpt FuncComponentGet, getCfg FuncComponentConfigGet) ([]string, liberr.Error) {
|
||||
var (
|
||||
err liberr.Error
|
||||
cpt Component
|
||||
)
|
||||
|
||||
if !c.ComponentHas(key) {
|
||||
return isReload, ErrorComponentNotFound.ErrorParent(fmt.Errorf("component: %s", key))
|
||||
} else if cpt = c.ComponentGet(key); cpt == nil {
|
||||
return isReload, ErrorComponentNotFound.ErrorParent(fmt.Errorf("component: %s", key))
|
||||
} else if stringIsInSlice(isReload, key) {
|
||||
return isReload, nil
|
||||
}
|
||||
|
||||
if dep := cpt.Dependencies(); len(dep) > 0 {
|
||||
for _, k := range dep {
|
||||
if isReload, err = c.reloadOne(isReload, k, getCpt, getCfg); err != nil {
|
||||
return isReload, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = cpt.Reload(getCpt, getCfg); err != nil {
|
||||
return isReload, err
|
||||
} else {
|
||||
c.ComponentSet(key, cpt)
|
||||
isReload = append(isReload, key)
|
||||
}
|
||||
|
||||
return isReload, nil
|
||||
}
|
||||
|
||||
func (c *componentList) ComponentReload(getCpt FuncComponentGet, getCfg FuncComponentConfigGet) liberr.Error {
|
||||
var (
|
||||
err liberr.Error
|
||||
key string
|
||||
|
||||
isReload = make([]string, 0)
|
||||
)
|
||||
|
||||
for _, key = range c.ComponentKeys() {
|
||||
if isReload, err = c.reloadOne(isReload, key, getCpt, getCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *componentList) ComponentStop() {
|
||||
for _, key := range c.ComponentKeys() {
|
||||
if !c.ComponentHas(key) {
|
||||
continue
|
||||
}
|
||||
|
||||
cpt := c.ComponentGet(key)
|
||||
if cpt == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
cpt.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *componentList) ComponentIsRunning(atLeast bool) bool {
|
||||
for _, k := range c.ComponentKeys() {
|
||||
if cpt := c.ComponentGet(k); cpt == nil {
|
||||
continue
|
||||
} else if ok := cpt.IsRunning(atLeast); !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *componentList) DefaultConfig() io.Reader {
|
||||
var buffer = bytes.NewBuffer(make([]byte, 0))
|
||||
|
||||
buffer.WriteString("{")
|
||||
buffer.WriteString("\n")
|
||||
|
||||
n := buffer.Len()
|
||||
|
||||
for _, k := range c.ComponentKeys() {
|
||||
if cpt := c.ComponentGet(k); cpt == nil {
|
||||
continue
|
||||
} else if p := cpt.DefaultConfig(); len(p) > 0 {
|
||||
if buffer.Len() > n {
|
||||
buffer.WriteString(",")
|
||||
}
|
||||
buffer.WriteString(fmt.Sprintf(" \"%s\": ", k))
|
||||
buffer.Write(p)
|
||||
}
|
||||
}
|
||||
|
||||
buffer.WriteString("\n")
|
||||
buffer.WriteString("}")
|
||||
|
||||
var res = bytes.NewBuffer(make([]byte, 0))
|
||||
if err := json.Indent(res, buffer.Bytes(), "", " "); err != nil {
|
||||
return buffer
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
73
config/errors.go
Normal file
73
config/errors.go
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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 "github.com/nabbar/golib/errors"
|
||||
|
||||
const (
|
||||
ErrorParamsEmpty errors.CodeError = iota + errors.MinPkgConfig
|
||||
ErrorConfigMissingViper
|
||||
ErrorComponentNotFound
|
||||
ErrorComponentConfigNotFound
|
||||
ErrorComponentConfigError
|
||||
)
|
||||
|
||||
const (
|
||||
MinErrorComponentHttp = ErrorParamsEmpty + 10
|
||||
MinErrorComponentLog = MinErrorComponentHttp + 10
|
||||
MinErrorComponentTls = MinErrorComponentLog + 10
|
||||
)
|
||||
|
||||
var isCodeError = false
|
||||
|
||||
func IsCodeError() bool {
|
||||
return isCodeError
|
||||
}
|
||||
|
||||
func init() {
|
||||
isCodeError = errors.ExistInMapMessage(ErrorParamsEmpty)
|
||||
errors.RegisterIdFctMessage(ErrorParamsEmpty, getMessage)
|
||||
}
|
||||
|
||||
func getMessage(code errors.CodeError) (message string) {
|
||||
switch code {
|
||||
case errors.UNK_ERROR:
|
||||
return ""
|
||||
case ErrorParamsEmpty:
|
||||
return "given parameters is empty"
|
||||
case ErrorConfigMissingViper:
|
||||
return "missing valid viper function"
|
||||
case ErrorComponentNotFound:
|
||||
return "component is not found"
|
||||
case ErrorComponentConfigNotFound:
|
||||
return "config keys for component is not found"
|
||||
case ErrorComponentConfigError:
|
||||
return "config for component is trigger an error"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
158
config/interface.go
Normal file
158
config/interface.go
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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 (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
libctx "github.com/nabbar/golib/context"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
libvpr "github.com/nabbar/golib/viper"
|
||||
)
|
||||
|
||||
type FuncContext func() context.Context
|
||||
type FuncComponentGet func(key string) Component
|
||||
type FuncComponentConfigGet func(model interface{}) liberr.Error
|
||||
|
||||
type Config interface {
|
||||
/*
|
||||
// Section Context : github.com/nabbar/golib/context
|
||||
*/
|
||||
|
||||
// Context return the current context pointer
|
||||
Context() context.Context
|
||||
|
||||
// ContextMerge trigger the golib/context/config interface
|
||||
// and will merge the stored context value into current context
|
||||
ContextMerge(ctx libctx.Config) bool
|
||||
|
||||
// ContextStore trigger the golib/context/config interface
|
||||
// and will store a context value into current context
|
||||
ContextStore(key string, cfg interface{})
|
||||
|
||||
// ContextLoad trigger the golib/context/config interface
|
||||
// and will restore a context value or nil
|
||||
ContextLoad(key string) interface{}
|
||||
|
||||
// ContextSetCancel allow to register a custom function called on cancel context.
|
||||
// On context cancel event or signal kill, term... this function will be called
|
||||
// before config stop and main context cancel function
|
||||
ContextSetCancel(fct func())
|
||||
|
||||
/*
|
||||
// Section Event : github.com/nabbar/golib/config
|
||||
*/
|
||||
|
||||
RegisterFuncViper(fct func() libvpr.Viper)
|
||||
|
||||
// Start will trigger the start function of all registered component.
|
||||
// If any component return an error, this func will stop the start
|
||||
// process and return the error.
|
||||
Start() liberr.Error
|
||||
|
||||
// RegisterFuncStartBefore allow to register a func to be call when the config Start
|
||||
// is trigger. This func is call before the start sequence.
|
||||
RegisterFuncStartBefore(fct func() liberr.Error)
|
||||
|
||||
// RegisterFuncStartAfter allow to register a func to be call when the config Start
|
||||
// is trigger. This func is call after the start sequence.
|
||||
RegisterFuncStartAfter(fct func() liberr.Error)
|
||||
|
||||
// Reload triggers the Reload function of each registered Component.
|
||||
Reload() liberr.Error
|
||||
|
||||
// RegisterFuncReloadBefore allow to register a func to be call when the config Reload
|
||||
// is trigger. This func is call before the reload sequence.
|
||||
RegisterFuncReloadBefore(fct func() liberr.Error)
|
||||
|
||||
// RegisterFuncReloadAfter allow to register a func to be call when the config Reload
|
||||
// is trigger. This func is call after the reload sequence.
|
||||
RegisterFuncReloadAfter(fct func() liberr.Error)
|
||||
|
||||
// Stop will trigger the stop function of all registered component.
|
||||
// All component must stop cleanly.
|
||||
Stop()
|
||||
|
||||
// RegisterFuncStopBefore allow to register a func to be call when the config Stop
|
||||
// is trigger. This func is call before the stop sequence.
|
||||
RegisterFuncStopBefore(fct func())
|
||||
|
||||
// RegisterFuncStopAfter allow to register a func to be call when the config Stop
|
||||
// is trigger. This func is call after the stop sequence.
|
||||
RegisterFuncStopAfter(fct func())
|
||||
|
||||
/*
|
||||
// Section Component : github.com/nabbar/golib/config
|
||||
*/
|
||||
ComponentList
|
||||
}
|
||||
|
||||
var (
|
||||
ctx context.Context
|
||||
cnl context.CancelFunc
|
||||
)
|
||||
|
||||
func init() {
|
||||
ctx, cnl = context.WithCancel(context.Background())
|
||||
|
||||
go func() {
|
||||
// Wait for interrupt signal to gracefully shutdown the server with
|
||||
// a timeout of 5 seconds.
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT)
|
||||
signal.Notify(quit, syscall.SIGTERM)
|
||||
signal.Notify(quit, syscall.SIGQUIT)
|
||||
|
||||
select {
|
||||
case <-quit:
|
||||
cnl()
|
||||
case <-ctx.Done():
|
||||
cnl()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func New() Config {
|
||||
c := &configModel{
|
||||
m: sync.Mutex{},
|
||||
ctx: libctx.NewConfig(ctx),
|
||||
cpt: newComponentList(),
|
||||
}
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-c.ctx.Done():
|
||||
c.cancel()
|
||||
}
|
||||
}()
|
||||
|
||||
return c
|
||||
}
|
||||
318
config/model.go
Normal file
318
config/model.go
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* 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 (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
libctx "github.com/nabbar/golib/context"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
libsts "github.com/nabbar/golib/status"
|
||||
libvpr "github.com/nabbar/golib/viper"
|
||||
spfvpr "github.com/spf13/viper"
|
||||
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type configModel struct {
|
||||
m sync.Mutex
|
||||
|
||||
ctx libctx.Config
|
||||
fcnl func()
|
||||
|
||||
cpt ComponentList
|
||||
|
||||
fctGolibViper func() libvpr.Viper
|
||||
fctRouteStatus func() libsts.RouteStatus
|
||||
fctStartBefore func() liberr.Error
|
||||
fctStartAfter func() liberr.Error
|
||||
fctReloadBefore func() liberr.Error
|
||||
fctReloadAfter func() liberr.Error
|
||||
fctStopBefore func()
|
||||
fctStopAfter func()
|
||||
}
|
||||
|
||||
func (c *configModel) _ComponentGetConfig(key string, model interface{}) liberr.Error {
|
||||
var (
|
||||
err error
|
||||
vpr libvpr.Viper
|
||||
vip *spfvpr.Viper
|
||||
)
|
||||
|
||||
if c.cpt.ComponentHas(key) {
|
||||
if c.fctGolibViper == nil {
|
||||
return ErrorConfigMissingViper.Error(nil)
|
||||
} else if vpr = c.fctGolibViper(); vpr == nil {
|
||||
return ErrorConfigMissingViper.Error(nil)
|
||||
} else if vip = vpr.Viper(); vip == nil {
|
||||
return ErrorConfigMissingViper.Error(nil)
|
||||
}
|
||||
|
||||
err = vip.UnmarshalKey(key, model)
|
||||
} else {
|
||||
return ErrorComponentNotFound.ErrorParent(fmt.Errorf("component '%s'", key))
|
||||
}
|
||||
|
||||
return ErrorComponentConfigError.Iferror(err)
|
||||
}
|
||||
|
||||
func (c *configModel) _FuncComponentGetConfig(key string) FuncComponentConfigGet {
|
||||
return func(model interface{}) liberr.Error {
|
||||
return c._ComponentGetConfig(key, model)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *configModel) Context() context.Context {
|
||||
return c.ctx
|
||||
}
|
||||
|
||||
func (c *configModel) ContextMerge(ctx libctx.Config) bool {
|
||||
return c.ctx.Merge(ctx)
|
||||
}
|
||||
|
||||
func (c *configModel) ContextStore(key string, cfg interface{}) {
|
||||
c.ctx.Store(key, cfg)
|
||||
}
|
||||
|
||||
func (c *configModel) ContextLoad(key string) interface{} {
|
||||
return c.ctx.Load(key)
|
||||
}
|
||||
|
||||
func (c *configModel) ContextSetCancel(fct func()) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
c.fcnl = fct
|
||||
}
|
||||
|
||||
func (c *configModel) cancel() {
|
||||
c.cancelCustom()
|
||||
c.Stop()
|
||||
}
|
||||
|
||||
func (c *configModel) cancelCustom() {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
if c.fcnl != nil {
|
||||
c.fcnl()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *configModel) RegisterFuncViper(fct func() libvpr.Viper) {
|
||||
c.fctGolibViper = fct
|
||||
}
|
||||
|
||||
func (c *configModel) Start() liberr.Error {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
var err liberr.Error
|
||||
|
||||
if c.fctStartBefore != nil {
|
||||
if err = c.fctStartBefore(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
getCpt := func(key string) Component {
|
||||
return c.ComponentGet(key)
|
||||
}
|
||||
|
||||
for _, k := range c.ComponentKeys() {
|
||||
cpt := c.ComponentGet(k)
|
||||
|
||||
if cpt == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = cpt.Start(getCpt, c._FuncComponentGetConfig(k)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if c.fctStartAfter != nil {
|
||||
if err = c.fctStartAfter(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *configModel) RegisterFuncStartBefore(fct func() liberr.Error) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
c.fctStartBefore = fct
|
||||
}
|
||||
|
||||
func (c *configModel) RegisterFuncStartAfter(fct func() liberr.Error) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
c.fctStartAfter = fct
|
||||
}
|
||||
|
||||
func (c *configModel) Reload() liberr.Error {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
var err liberr.Error
|
||||
|
||||
if c.fctReloadBefore != nil {
|
||||
if err = c.fctReloadBefore(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
getCpt := func(key string) Component {
|
||||
return c.ComponentGet(key)
|
||||
}
|
||||
|
||||
for _, k := range c.ComponentKeys() {
|
||||
cpt := c.ComponentGet(k)
|
||||
|
||||
if cpt == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = cpt.Reload(getCpt, c._FuncComponentGetConfig(k)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if c.fctReloadAfter != nil {
|
||||
if err = c.fctReloadAfter(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *configModel) RegisterFuncReloadBefore(fct func() liberr.Error) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
c.fctReloadBefore = fct
|
||||
}
|
||||
|
||||
func (c *configModel) RegisterFuncReloadAfter(fct func() liberr.Error) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
c.fctReloadAfter = fct
|
||||
}
|
||||
|
||||
func (c *configModel) Stop() {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
if c.fctStopBefore != nil {
|
||||
c.fctStopBefore()
|
||||
}
|
||||
|
||||
for _, k := range c.ComponentKeys() {
|
||||
cpt := c.ComponentGet(k)
|
||||
|
||||
if cpt == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
cpt.Stop()
|
||||
}
|
||||
|
||||
if c.fctStopAfter != nil {
|
||||
c.fctStopAfter()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *configModel) RegisterFuncStopBefore(fct func()) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
c.fctStopBefore = fct
|
||||
}
|
||||
|
||||
func (c *configModel) RegisterFuncStopAfter(fct func()) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
c.fctStopAfter = fct
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentHas(key string) bool {
|
||||
return c.cpt.ComponentHas(key)
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentType(key string) string {
|
||||
return c.cpt.ComponentType(key)
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentGet(key string) Component {
|
||||
return c.cpt.ComponentGet(key)
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentDel(key string) {
|
||||
c.cpt.ComponentDel(key)
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentSet(key string, cpt Component) {
|
||||
cpt.RegisterContext(c.Context)
|
||||
cpt.RegisterGet(c.ComponentGet)
|
||||
|
||||
c.cpt.ComponentSet(key, cpt)
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentList() map[string]Component {
|
||||
return c.cpt.ComponentList()
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentKeys() []string {
|
||||
return c.cpt.ComponentKeys()
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentStart(getCpt FuncComponentGet, getCfg FuncComponentConfigGet) liberr.Error {
|
||||
return c.cpt.ComponentStart(getCpt, getCfg)
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentIsStarted() bool {
|
||||
return c.cpt.ComponentIsStarted()
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentReload(getCpt FuncComponentGet, getCfg FuncComponentConfigGet) liberr.Error {
|
||||
return c.cpt.ComponentReload(getCpt, getCfg)
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentStop() {
|
||||
c.cpt.ComponentStop()
|
||||
}
|
||||
|
||||
func (c *configModel) ComponentIsRunning(atLeast bool) bool {
|
||||
return c.cpt.ComponentIsRunning(atLeast)
|
||||
}
|
||||
|
||||
func (c *configModel) DefaultConfig() io.Reader {
|
||||
return c.cpt.DefaultConfig()
|
||||
}
|
||||
41
config/tools.go
Normal file
41
config/tools.go
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
func stringIsInSlice(list []string, key string) bool {
|
||||
if len(list) < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, k := range list {
|
||||
if k == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -26,6 +26,7 @@ package context
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@@ -41,53 +42,49 @@ type Config interface {
|
||||
func NewConfig(ctx context.Context) Config {
|
||||
return &configContext{
|
||||
Context: ctx,
|
||||
cfg: new(atomic.Value),
|
||||
cfg: make(map[string]*atomic.Value, 0),
|
||||
}
|
||||
}
|
||||
|
||||
type configContext struct {
|
||||
context.Context
|
||||
cfg *atomic.Value
|
||||
m sync.Mutex
|
||||
cfg map[string]*atomic.Value
|
||||
}
|
||||
|
||||
func (c configContext) getMap() map[string]*atomic.Value {
|
||||
func (c configContext) Load(key string) interface{} {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
var (
|
||||
v interface{}
|
||||
s map[string]*atomic.Value
|
||||
i interface{}
|
||||
ok bool
|
||||
)
|
||||
|
||||
if c.cfg == nil {
|
||||
c.cfg = new(atomic.Value)
|
||||
} else if v = c.cfg.Load(); v == nil {
|
||||
s = make(map[string]*atomic.Value)
|
||||
|
||||
} else if s, ok = v.(map[string]*atomic.Value); !ok {
|
||||
s = make(map[string]*atomic.Value)
|
||||
c.cfg = make(map[string]*atomic.Value, 0)
|
||||
} else if i, ok = c.cfg[key]; ok && i != nil {
|
||||
return i
|
||||
}
|
||||
|
||||
return s
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *configContext) Store(key string, cfg interface{}) {
|
||||
s := c.getMap()
|
||||
func (c configContext) Store(key string, cfg interface{}) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
if _, ok := s[key]; !ok {
|
||||
s[key] = &atomic.Value{}
|
||||
var ok bool
|
||||
|
||||
if c.cfg == nil {
|
||||
c.cfg = make(map[string]*atomic.Value, 0)
|
||||
}
|
||||
|
||||
s[key].Store(cfg)
|
||||
c.cfg.Store(s)
|
||||
}
|
||||
|
||||
func (c *configContext) Load(key string) interface{} {
|
||||
s := c.getMap()
|
||||
|
||||
if _, ok := s[key]; !ok {
|
||||
return nil
|
||||
} else {
|
||||
return s[key].Load()
|
||||
if _, ok = c.cfg[key]; !ok {
|
||||
c.cfg[key] = new(atomic.Value)
|
||||
}
|
||||
|
||||
c.cfg[key].Store(cfg)
|
||||
}
|
||||
|
||||
func (c *configContext) Merge(cfg Config) bool {
|
||||
@@ -100,9 +97,10 @@ func (c *configContext) Merge(cfg Config) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
s := c.getMap()
|
||||
x.m.Lock()
|
||||
defer x.m.Unlock()
|
||||
|
||||
for k, v := range x.getMap() {
|
||||
for k, v := range x.cfg {
|
||||
if k == "" || v == nil {
|
||||
continue
|
||||
}
|
||||
@@ -110,22 +108,9 @@ func (c *configContext) Merge(cfg Config) bool {
|
||||
if i := v.Load(); i == nil {
|
||||
continue
|
||||
} else {
|
||||
s[k] = &atomic.Value{}
|
||||
s[k].Store(i)
|
||||
c.Store(k, i)
|
||||
}
|
||||
}
|
||||
|
||||
c.cfg.Store(s)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
//Deprecated: use Store.
|
||||
func (c *configContext) ObjectStore(key string, obj interface{}) {
|
||||
c.Store(key, obj)
|
||||
}
|
||||
|
||||
//Deprecated: use Load.
|
||||
func (c *configContext) ObjectLoad(key string) interface{} {
|
||||
return c.Load(key)
|
||||
}
|
||||
|
||||
@@ -31,26 +31,28 @@ const (
|
||||
MinPkgArtifact = 200
|
||||
MinPkgCertificate = 300
|
||||
MinPkgCluster = 400
|
||||
MinPkgConsole = 500
|
||||
MinPkgCrypt = 600
|
||||
MinPkgHttpCli = 700
|
||||
MinPkgHttpServer = 800
|
||||
MinPkgIOUtils = 900
|
||||
MinPkgLDAP = 1000
|
||||
MinPkgLogger = 1100
|
||||
MinPkgMail = 1200
|
||||
MinPkgMailer = 1300
|
||||
MinPkgMailPooler = 1400
|
||||
MinPkgNetwork = 1500
|
||||
MinPkgNats = 1600
|
||||
MinPkgNutsDB = 1700
|
||||
MinPkgOAuth = 1800
|
||||
MinPkgAws = 1900
|
||||
MinPkgRouter = 2000
|
||||
MinPkgSemaphore = 2100
|
||||
MinPkgSMTP = 2200
|
||||
MinPkgStatic = 2300
|
||||
MinPkgVersion = 2400
|
||||
MinPkgConfig = 500
|
||||
MinPkgConsole = 600
|
||||
MinPkgCrypt = 700
|
||||
MinPkgHttpCli = 800
|
||||
MinPkgHttpServer = 900
|
||||
MinPkgIOUtils = 1000
|
||||
MinPkgLDAP = 1100
|
||||
MinPkgLogger = 1200
|
||||
MinPkgMail = 1300
|
||||
MinPkgMailer = 1400
|
||||
MinPkgMailPooler = 1500
|
||||
MinPkgNetwork = 1600
|
||||
MinPkgNats = 1700
|
||||
MinPkgNutsDB = 1800
|
||||
MinPkgOAuth = 1900
|
||||
MinPkgAws = 2000
|
||||
MinPkgRouter = 2100
|
||||
MinPkgSemaphore = 2200
|
||||
MinPkgSMTP = 2300
|
||||
MinPkgStatic = 2400
|
||||
MinPkgVersion = 2500
|
||||
MinPkgViper = 2600
|
||||
|
||||
MinAvailable = 4000
|
||||
|
||||
|
||||
43
go.mod
43
go.mod
@@ -10,9 +10,10 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.24.1
|
||||
github.com/c-bata/go-prompt v0.2.6
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/fsnotify/fsnotify v1.5.1
|
||||
github.com/fxamacker/cbor/v2 v2.4.0
|
||||
github.com/gin-gonic/gin v1.7.7
|
||||
github.com/go-ldap/ldap/v3 v3.4.1
|
||||
github.com/go-ldap/ldap/v3 v3.4.2
|
||||
github.com/go-playground/validator/v10 v10.10.0
|
||||
github.com/google/go-github/v33 v33.0.0
|
||||
github.com/hashicorp/go-hclog v1.1.0
|
||||
@@ -22,16 +23,20 @@ require (
|
||||
github.com/lni/dragonboat/v3 v3.3.5
|
||||
github.com/matcornic/hermes/v2 v2.1.0
|
||||
github.com/mattn/go-colorable v0.1.12
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296
|
||||
github.com/nats-io/nats-server/v2 v2.7.2
|
||||
github.com/nats-io/nats.go v1.13.1-0.20220121202836-972a071d373d
|
||||
github.com/onsi/ginkgo/v2 v2.1.1
|
||||
github.com/onsi/ginkgo/v2 v2.1.3
|
||||
github.com/onsi/gomega v1.18.1
|
||||
github.com/pelletier/go-toml v1.9.4
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spf13/cobra v1.3.0
|
||||
github.com/spf13/jwalterweatherman v1.1.0
|
||||
github.com/spf13/viper v1.10.1
|
||||
github.com/vbauerster/mpb/v5 v5.4.0
|
||||
github.com/xanzy/go-gitlab v0.55.0
|
||||
github.com/xanzy/go-gitlab v0.55.1
|
||||
github.com/xhit/go-simple-mail v2.2.2+incompatible
|
||||
github.com/xujiajun/nutsdb v0.6.0
|
||||
github.com/xujiajun/utils v0.0.0-20190123093513-8bf096c4f53b
|
||||
@@ -40,6 +45,7 @@ require (
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -53,7 +59,7 @@ require (
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
||||
github.com/andybalholm/cascadia v1.3.1 // indirect
|
||||
github.com/aokoli/goutils v1.1.1 // indirect
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
|
||||
github.com/armon/go-metrics v0.3.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.2.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4 // indirect
|
||||
@@ -76,7 +82,7 @@ require (
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.3 // indirect
|
||||
github.com/google/btree v1.0.0 // indirect
|
||||
@@ -85,28 +91,32 @@ require (
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||
github.com/hashicorp/go-msgpack v0.5.3 // indirect
|
||||
github.com/hashicorp/go-multierror v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.0 // indirect
|
||||
github.com/hashicorp/go-sockaddr v1.0.0 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.1 // indirect
|
||||
github.com/hashicorp/memberlist v0.2.2 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/hashicorp/memberlist v0.3.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jaytaylor/html2text v0.0.0-20211105163654-bc68cce691ba // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/juju/ratelimit v1.0.2-0.20191002062651-f60b32039441 // indirect
|
||||
github.com/klauspost/compress v1.14.2 // indirect
|
||||
github.com/klauspost/compress v1.14.3 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/lni/goutils v1.3.0 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mattn/go-tty v0.0.4 // indirect
|
||||
github.com/miekg/dns v1.1.26 // indirect
|
||||
github.com/miekg/dns v1.1.41 // indirect
|
||||
github.com/minio/highwayhash v1.0.2 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
@@ -119,8 +129,11 @@ require (
|
||||
github.com/rogpeppe/go-internal v1.8.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/spf13/afero v1.8.1 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/ugorji/go/codec v1.2.6 // indirect
|
||||
github.com/valyala/fastrand v1.0.0 // indirect
|
||||
github.com/valyala/histogram v1.0.1 // indirect
|
||||
@@ -129,11 +142,11 @@ require (
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xujiajun/mmap-go v1.0.1 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220209195652-db638375bc3a // indirect
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
|
||||
golang.org/x/exp v0.0.0-20200513190911-00229845015e // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
||||
)
|
||||
|
||||
@@ -283,7 +283,7 @@ func (c *ServerConfig) SetParentContext(f func() context.Context) {
|
||||
c.getParentContext = f
|
||||
}
|
||||
|
||||
func (c ServerConfig) GetTLS() (libtls.TLSConfig, liberr.Error) {
|
||||
func (c *ServerConfig) GetTLS() (libtls.TLSConfig, liberr.Error) {
|
||||
var def libtls.TLSConfig
|
||||
|
||||
if c.TLS.InheritDefault && c.getTLSDefault != nil {
|
||||
@@ -293,7 +293,7 @@ func (c ServerConfig) GetTLS() (libtls.TLSConfig, liberr.Error) {
|
||||
return c.TLS.NewFrom(def)
|
||||
}
|
||||
|
||||
func (c ServerConfig) IsTLS() bool {
|
||||
func (c *ServerConfig) IsTLS() bool {
|
||||
if ssl, err := c.GetTLS(); err == nil && ssl != nil && ssl.LenCertificatePair() > 0 {
|
||||
return true
|
||||
}
|
||||
@@ -301,7 +301,7 @@ func (c ServerConfig) IsTLS() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c ServerConfig) getContext() context.Context {
|
||||
func (c *ServerConfig) getContext() context.Context {
|
||||
var ctx context.Context
|
||||
|
||||
if c.getParentContext != nil {
|
||||
@@ -315,7 +315,7 @@ func (c ServerConfig) getContext() context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (c ServerConfig) GetListen() *url.URL {
|
||||
func (c *ServerConfig) GetListen() *url.URL {
|
||||
var (
|
||||
err error
|
||||
add *url.URL
|
||||
@@ -342,7 +342,7 @@ func (c ServerConfig) GetListen() *url.URL {
|
||||
return add
|
||||
}
|
||||
|
||||
func (c ServerConfig) GetExpose() *url.URL {
|
||||
func (c *ServerConfig) GetExpose() *url.URL {
|
||||
var (
|
||||
err error
|
||||
add *url.URL
|
||||
@@ -367,14 +367,18 @@ func (c ServerConfig) GetExpose() *url.URL {
|
||||
return add
|
||||
}
|
||||
|
||||
func (c ServerConfig) GetHandlerKey() string {
|
||||
func (c *ServerConfig) GetHandlerKey() string {
|
||||
return c.HandlerKeys
|
||||
}
|
||||
|
||||
func (c ServerConfig) Validate() liberr.Error {
|
||||
func (c *ServerConfig) Validate() liberr.Error {
|
||||
val := validator.New()
|
||||
err := val.Struct(c)
|
||||
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if e, ok := err.(*validator.InvalidValidationError); ok {
|
||||
return ErrorServerValidate.ErrorParent(e)
|
||||
}
|
||||
@@ -394,6 +398,6 @@ func (c ServerConfig) Validate() liberr.Error {
|
||||
|
||||
}
|
||||
|
||||
func (c ServerConfig) Server() Server {
|
||||
return NewServer(&c)
|
||||
func (c *ServerConfig) Server() Server {
|
||||
return NewServer(c)
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -48,6 +49,8 @@ import (
|
||||
const _TimeoutWaitingPortFreeing = 500 * time.Microsecond
|
||||
|
||||
type srvRun struct {
|
||||
m sync.Mutex
|
||||
|
||||
log liblog.FuncLog // return golib logger interface
|
||||
err *atomic.Value // last err occured
|
||||
run *atomic.Value // is running
|
||||
@@ -70,6 +73,7 @@ type run interface {
|
||||
|
||||
func newRun(log liblog.FuncLog) run {
|
||||
return &srvRun{
|
||||
m: sync.Mutex{},
|
||||
log: log,
|
||||
err: new(atomic.Value),
|
||||
run: new(atomic.Value),
|
||||
@@ -270,7 +274,10 @@ func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error {
|
||||
}
|
||||
|
||||
s.ctx, s.cnl = context.WithCancel(cfg.getContext())
|
||||
|
||||
s.m.Lock()
|
||||
s.srv = srv
|
||||
s.m.Unlock()
|
||||
|
||||
go func(ctx context.Context, cnl context.CancelFunc, name, host string, tlsMandatory bool) {
|
||||
var _log = s.getLogger()
|
||||
@@ -284,9 +291,14 @@ func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error {
|
||||
s.setRunning(false)
|
||||
}()
|
||||
|
||||
s.m.Lock()
|
||||
if s.srv == nil {
|
||||
return
|
||||
}
|
||||
s.srv.BaseContext = func(listener net.Listener) context.Context {
|
||||
return s.ctx
|
||||
}
|
||||
s.m.Unlock()
|
||||
|
||||
var er error
|
||||
_log.Entry(liblog.InfoLevel, "Server is starting").Log()
|
||||
@@ -337,7 +349,11 @@ func (s *srvRun) srvShutdown() {
|
||||
cancel()
|
||||
if s.srv != nil {
|
||||
err := s.srv.Close()
|
||||
|
||||
s.m.Lock()
|
||||
s.srv = nil
|
||||
s.m.Unlock()
|
||||
|
||||
_log.Entry(liblog.ErrorLevel, "closing server").ErrorAdd(true, err).Check(liblog.InfoLevel)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -101,6 +101,35 @@ func (lic license) GetLicense() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (lic license) GetLicenseName() string {
|
||||
switch lic {
|
||||
case License_Apache_v2:
|
||||
return "Apache License - Version 2.0, January 2004"
|
||||
case License_GNU_Affero_GPL_v3:
|
||||
return "GNU AFFERO GENERAL PUBLIC LICENSE - Version 3, 19 November 2007"
|
||||
case License_GNU_GPL_v3:
|
||||
return "GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007"
|
||||
case License_GNU_Lesser_GPL_v3:
|
||||
return "GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007"
|
||||
case License_MIT:
|
||||
return "MIT License"
|
||||
case License_Mozilla_PL_v2:
|
||||
return "Mozilla Public License Version 2.0"
|
||||
case License_Unlicense:
|
||||
return "Free and unencumbered software"
|
||||
case License_Creative_Common_Zero_v1:
|
||||
return "Creative Commons - CC0 1.0 Universal"
|
||||
case License_Creative_Common_Attribution_v4_int:
|
||||
return "Creative Commons - Attribution 4.0 International"
|
||||
case License_Creative_Common_Attribution_Share_Alike_v4_int:
|
||||
return "Creative Commons - Attribution-ShareAlike 4.0 International"
|
||||
case License_SIL_Open_Font_1_1:
|
||||
return "SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func boiler_MIT(Year, Author string) string {
|
||||
return fmt.Sprintf(`
|
||||
MIT License
|
||||
|
||||
@@ -55,6 +55,7 @@ type Version interface {
|
||||
GetAppId() string
|
||||
GetAuthor() string
|
||||
GetBuild() string
|
||||
GetDate() string
|
||||
GetDescription() string
|
||||
GetHeader() string
|
||||
GetInfo() string
|
||||
@@ -63,6 +64,7 @@ type Version interface {
|
||||
GetPrefix() string
|
||||
GetRelease() string
|
||||
|
||||
GetLicenseName() string
|
||||
GetLicenseLegal(addMoreLicence ...license) string
|
||||
GetLicenseFull(addMoreLicence ...license) string
|
||||
GetLicenseBoiler(addMoreLicence ...license) string
|
||||
@@ -156,6 +158,19 @@ func (vers versionModel) GetHeader() string {
|
||||
return fmt.Sprintf("%s (%s)", vers.versionPackage, vers.GetInfo())
|
||||
}
|
||||
|
||||
func (vers versionModel) GetDate() string {
|
||||
var (
|
||||
err error
|
||||
ts time.Time
|
||||
)
|
||||
|
||||
if ts, err = time.Parse(time.RFC3339, vers.versionDate); err != nil {
|
||||
ts = time.Time{}
|
||||
}
|
||||
|
||||
return ts.Format(time.RFC1123)
|
||||
}
|
||||
|
||||
func (vers versionModel) GetBuild() string {
|
||||
return vers.versionBuild
|
||||
}
|
||||
@@ -176,6 +191,10 @@ func (vers versionModel) GetRelease() string {
|
||||
return vers.versionRelease
|
||||
}
|
||||
|
||||
func (vers versionModel) GetLicenseName() string {
|
||||
return vers.licenceType.GetLicenseName()
|
||||
}
|
||||
|
||||
func (vers versionModel) GetLicenseLegal(addMoreLicence ...license) string {
|
||||
if len(addMoreLicence) == 0 {
|
||||
return vers.licenceType.GetLicense()
|
||||
|
||||
94
viper/cleaner.go
Normal file
94
viper/cleaner.go
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 viper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
spfvpr "github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func (v *viper) Unset(key ...string) error {
|
||||
if len(key) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
configMap := v.v.AllSettings()
|
||||
|
||||
for _, k := range key {
|
||||
configMap = unsetSub(configMap, k)
|
||||
}
|
||||
|
||||
_v := &viper{
|
||||
v: spfvpr.New(),
|
||||
base: v.base,
|
||||
prfx: v.prfx,
|
||||
deft: v.deft,
|
||||
remote: v.remote,
|
||||
}
|
||||
|
||||
var (
|
||||
encodedConfig []byte
|
||||
err error
|
||||
)
|
||||
|
||||
if encodedConfig, err = json.MarshalIndent(configMap, "", " "); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_v.v.SetConfigType("json")
|
||||
|
||||
if err = _v.v.ReadConfig(bytes.NewReader(encodedConfig)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.v = _v.v
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func unsetSub(configMap map[string]interface{}, key string) map[string]interface{} {
|
||||
kkey := strings.Split(key, ".")
|
||||
|
||||
if len(kkey) == 1 {
|
||||
delete(configMap, key)
|
||||
return configMap
|
||||
}
|
||||
|
||||
for k, v := range configMap {
|
||||
if k != kkey[0] {
|
||||
continue
|
||||
}
|
||||
|
||||
configMap[k] = unsetSub(v.(map[string]interface{}), strings.Join(kkey[1:], "."))
|
||||
break
|
||||
}
|
||||
|
||||
return configMap
|
||||
}
|
||||
58
viper/config.go
Normal file
58
viper/config.go
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 viper
|
||||
|
||||
import (
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
)
|
||||
|
||||
func (v *viper) Config(logLevelRemoteKO, logLevelRemoteOK liblog.Level) liberr.Error {
|
||||
if err := v.initAddRemote(); err == nil {
|
||||
v.initWatchRemote(logLevelRemoteKO, logLevelRemoteOK)
|
||||
return nil
|
||||
} else if !err.IsCodeError(ErrorParamMissing) {
|
||||
return err
|
||||
}
|
||||
|
||||
err := v.v.ReadInConfig()
|
||||
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.deft != nil {
|
||||
v.v.SetConfigType("json")
|
||||
if err = v.v.ReadConfig(v.deft()); err != nil {
|
||||
return ErrorConfigReadDefault.ErrorParent(err)
|
||||
}
|
||||
|
||||
return ErrorConfigIsDefault.Error(nil)
|
||||
}
|
||||
|
||||
return ErrorConfigRead.ErrorParent(err)
|
||||
}
|
||||
85
viper/errors.go
Normal file
85
viper/errors.go
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Nicolas JUHEL
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package viper
|
||||
|
||||
import (
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgViper
|
||||
ErrorParamMissing
|
||||
ErrorHomePathNotFound
|
||||
ErrorBasePathNotFound
|
||||
ErrorRemoteProvider
|
||||
ErrorRemoteProviderSecure
|
||||
ErrorRemoteProviderRead
|
||||
ErrorRemoteProviderMarshall
|
||||
ErrorConfigRead
|
||||
ErrorConfigReadDefault
|
||||
ErrorConfigIsDefault
|
||||
)
|
||||
|
||||
var isCodeError = false
|
||||
|
||||
func IsCodeError() bool {
|
||||
return isCodeError
|
||||
}
|
||||
|
||||
func init() {
|
||||
isCodeError = liberr.ExistInMapMessage(ErrorParamEmpty)
|
||||
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
|
||||
}
|
||||
|
||||
func getMessage(code liberr.CodeError) (message string) {
|
||||
switch code {
|
||||
case liberr.UNK_ERROR:
|
||||
return ""
|
||||
case ErrorParamMissing:
|
||||
return "at least one parameter is missing"
|
||||
case ErrorHomePathNotFound:
|
||||
return "cannot retrieve user home path"
|
||||
case ErrorBasePathNotFound:
|
||||
return "cannot retrieve base config path"
|
||||
case ErrorRemoteProvider:
|
||||
return "cannot define remote provider"
|
||||
case ErrorRemoteProviderSecure:
|
||||
return "cannot define secure remote provider"
|
||||
case ErrorRemoteProviderRead:
|
||||
return "cannot read config from remote provider"
|
||||
case ErrorRemoteProviderMarshall:
|
||||
return "cannot marshall config from remote provider"
|
||||
case ErrorConfigRead:
|
||||
return "cannot read config from file"
|
||||
case ErrorConfigReadDefault:
|
||||
return "cannot read default config"
|
||||
case ErrorConfigIsDefault:
|
||||
return "cannot read config, use default config"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
61
viper/interface.go
Normal file
61
viper/interface.go
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 viper
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
spfvpr "github.com/spf13/viper"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
)
|
||||
|
||||
type Viper interface {
|
||||
SetRemoteProvider(provider string)
|
||||
SetRemoteEndpoint(endpoint string)
|
||||
SetRemotePath(path string)
|
||||
SetRemoteSecureKey(key string)
|
||||
SetRemoteModel(model interface{})
|
||||
SetRemoteReloadFunc(fct func())
|
||||
|
||||
SetHomeBaseName(base string)
|
||||
SetEnvVarsPrefix(prefix string)
|
||||
SetDefaultConfig(fct func() io.Reader)
|
||||
SetConfigFile(fileConfig string) liberr.Error
|
||||
|
||||
Config(logLevelRemoteKO, logLevelRemoteOK liblog.Level) liberr.Error
|
||||
Viper() *spfvpr.Viper
|
||||
WatchFS(logLevelFSInfo liblog.Level)
|
||||
Unset(key ...string) error
|
||||
}
|
||||
|
||||
func New() Viper {
|
||||
return &viper{
|
||||
v: spfvpr.New(),
|
||||
}
|
||||
}
|
||||
127
viper/model.go
Normal file
127
viper/model.go
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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 viper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
libhom "github.com/mitchellh/go-homedir"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
spfvpr "github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
RemoteETCD = "etcd"
|
||||
)
|
||||
|
||||
type viperRemote struct {
|
||||
model interface{}
|
||||
provider string
|
||||
endpoint string
|
||||
path string
|
||||
secure string
|
||||
fct func()
|
||||
}
|
||||
|
||||
type viper struct {
|
||||
v *spfvpr.Viper
|
||||
|
||||
base string
|
||||
prfx string
|
||||
deft func() io.Reader
|
||||
|
||||
remote viperRemote
|
||||
}
|
||||
|
||||
func (v *viper) SetRemoteProvider(provider string) {
|
||||
v.remote.provider = provider
|
||||
}
|
||||
|
||||
func (v *viper) SetRemoteEndpoint(endpoint string) {
|
||||
v.remote.endpoint = endpoint
|
||||
}
|
||||
|
||||
func (v *viper) SetRemotePath(path string) {
|
||||
v.remote.path = path
|
||||
}
|
||||
|
||||
func (v *viper) SetRemoteSecureKey(key string) {
|
||||
v.remote.secure = key
|
||||
}
|
||||
|
||||
func (v *viper) SetRemoteModel(model interface{}) {
|
||||
v.remote.model = model
|
||||
}
|
||||
|
||||
func (v *viper) SetRemoteReloadFunc(fct func()) {
|
||||
v.remote.fct = fct
|
||||
}
|
||||
|
||||
func (v *viper) SetHomeBaseName(base string) {
|
||||
v.base = base
|
||||
}
|
||||
|
||||
func (v *viper) SetEnvVarsPrefix(prefix string) {
|
||||
v.prfx = prefix
|
||||
}
|
||||
|
||||
func (v *viper) SetDefaultConfig(fct func() io.Reader) {
|
||||
v.deft = fct
|
||||
}
|
||||
|
||||
func (v *viper) SetConfigFile(fileConfig string) liberr.Error {
|
||||
if fileConfig != "" {
|
||||
v.v.SetConfigFile(fileConfig)
|
||||
} else {
|
||||
// Find home directory.
|
||||
home, err := libhom.Dir()
|
||||
if err != nil {
|
||||
return ErrorHomePathNotFound.ErrorParent(err)
|
||||
}
|
||||
|
||||
// Search config in home directory with name defined in SetConfigName (without extension).
|
||||
v.v.AddConfigPath(home)
|
||||
|
||||
if v.base == "" {
|
||||
return ErrorBasePathNotFound.ErrorParent(fmt.Errorf("base name of config file is empty"))
|
||||
}
|
||||
|
||||
v.v.SetConfigName("." + v.base)
|
||||
|
||||
if v.prfx != "" {
|
||||
v.v.SetEnvPrefix(v.prfx)
|
||||
v.v.AutomaticEnv()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *viper) Viper() *spfvpr.Viper {
|
||||
return v.v
|
||||
}
|
||||
61
viper/remote.go
Normal file
61
viper/remote.go
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 viper
|
||||
|
||||
import (
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
func (v *viper) initAddRemote() liberr.Error {
|
||||
if v.remote.provider == "" || v.remote.endpoint == "" || v.remote.path == "" {
|
||||
return ErrorParamMissing.Error(nil)
|
||||
}
|
||||
|
||||
if v.remote.secure != "" {
|
||||
if err := v.v.AddSecureRemoteProvider(v.remote.provider, v.remote.endpoint, v.remote.path, v.remote.secure); err != nil {
|
||||
return ErrorRemoteProviderSecure.ErrorParent(err)
|
||||
}
|
||||
} else if err := v.v.AddRemoteProvider(v.remote.provider, v.remote.endpoint, v.remote.path); err != nil {
|
||||
return ErrorRemoteProvider.ErrorParent(err)
|
||||
}
|
||||
|
||||
return v.initSetRemote()
|
||||
}
|
||||
|
||||
func (v *viper) initSetRemote() liberr.Error {
|
||||
v.v.SetConfigType("json")
|
||||
|
||||
if err := v.v.ReadRemoteConfig(); err != nil {
|
||||
return ErrorRemoteProviderRead.ErrorParent(err)
|
||||
}
|
||||
|
||||
if err := v.v.Unmarshal(v.remote.model); err != nil {
|
||||
return ErrorRemoteProviderMarshall.ErrorParent(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
74
viper/watch.go
Normal file
74
viper/watch.go
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 viper
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
libnot "github.com/fsnotify/fsnotify"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
)
|
||||
|
||||
func (v *viper) initWatchRemote(logLevelRemoteKO, logLevelRemoteOK liblog.Level) {
|
||||
// open a goroutine to watch remote changes forever
|
||||
go func() {
|
||||
// unstopped for loop
|
||||
for {
|
||||
// delay after each request
|
||||
time.Sleep(time.Second * 5)
|
||||
|
||||
if v.remote.provider == RemoteETCD {
|
||||
if logLevelRemoteKO.LogErrorCtxf(logLevelRemoteOK, "Remote config watching", v.v.WatchRemoteConfig()) {
|
||||
// skip error and try next time
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
// reading remote config
|
||||
if logLevelRemoteKO.LogErrorCtxf(logLevelRemoteOK, "Remote config loading", v.v.ReadRemoteConfig()) {
|
||||
// skip error and try next time
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// add config model
|
||||
if logLevelRemoteKO.LogErrorCtxf(logLevelRemoteOK, "Remote config parsing", v.v.Unmarshal(v.remote.model)) {
|
||||
// skip error and try next time
|
||||
continue
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (v *viper) WatchFS(logLevelFSInfo liblog.Level) {
|
||||
v.v.WatchConfig()
|
||||
v.v.OnConfigChange(func(e libnot.Event) {
|
||||
if v.remote.fct != nil {
|
||||
logLevelFSInfo.Logf("reloaded config file '%s'...", e.Name)
|
||||
v.remote.fct()
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user