mirror of
https://github.com/akyaiy/GoSally-mvp.git
synced 2026-01-08 20:52:24 +00:00
move go files to src/
This commit is contained in:
186
src/internal/engine/config/compositor.go
Normal file
186
src/internal/engine/config/compositor.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func NewCompositor() *Compositor {
|
||||
return &Compositor{}
|
||||
}
|
||||
|
||||
func (c *Compositor) LoadEnv() error {
|
||||
v := viper.New()
|
||||
|
||||
// defaults
|
||||
v.SetDefault("config_path", "./cfg/config.yaml")
|
||||
v.SetDefault("node_path", "./")
|
||||
v.SetDefault("parent_pid", -1)
|
||||
|
||||
// GS_*
|
||||
v.SetEnvPrefix("GS")
|
||||
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
v.AutomaticEnv()
|
||||
|
||||
var env Env
|
||||
if err := v.Unmarshal(&env); err != nil {
|
||||
return fmt.Errorf("error unmarshaling env: %w", err)
|
||||
}
|
||||
|
||||
c.Env = &env
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Compositor) LoadConf(path string) error {
|
||||
v := viper.New()
|
||||
|
||||
v.SetConfigFile(path)
|
||||
v.SetConfigType("yaml")
|
||||
|
||||
// defaults
|
||||
v.SetDefault("node.name", "noname")
|
||||
v.SetDefault("node.mode", "dev")
|
||||
v.SetDefault("node.show_config", "false")
|
||||
v.SetDefault("node.com_dir", "./com/")
|
||||
v.SetDefault("http_server.address", "0.0.0.0")
|
||||
v.SetDefault("http_server.port", "8080")
|
||||
v.SetDefault("http_server.session_ttl", "30m")
|
||||
v.SetDefault("http_server.timeout", "5s")
|
||||
v.SetDefault("http_server.idle_timeout", "60s")
|
||||
v.SetDefault("tls.enabled", false)
|
||||
v.SetDefault("tls.cert_file", "./cert/server.crt")
|
||||
v.SetDefault("tls.key_file", "./cert/server.key")
|
||||
v.SetDefault("updates.enabled", false)
|
||||
v.SetDefault("updates.check_interval", "2h")
|
||||
v.SetDefault("updates.wanted_version", "latest-stable")
|
||||
v.SetDefault("log.json_format", "false")
|
||||
v.SetDefault("log.level", "info")
|
||||
v.SetDefault("log.output", "%2%")
|
||||
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
return fmt.Errorf("error reading config: %w", err)
|
||||
}
|
||||
|
||||
var cfg Conf
|
||||
if err := v.Unmarshal(&cfg); err != nil {
|
||||
return fmt.Errorf("error unmarshaling config: %w", err)
|
||||
}
|
||||
|
||||
c.Conf = &Conf{}
|
||||
c.Conf = &cfg
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Compositor) LoadCMDLine(root *cobra.Command) {
|
||||
cmdLine := &CMDLine{}
|
||||
c.CMDLine = cmdLine
|
||||
|
||||
t := reflect.TypeOf(cmdLine).Elem()
|
||||
v := reflect.ValueOf(cmdLine).Elem()
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
fieldVal := v.Field(i)
|
||||
ptr := fieldVal.Addr().Interface()
|
||||
use := strings.ToLower(field.Name)
|
||||
|
||||
var cmd *cobra.Command
|
||||
for _, sub := range root.Commands() {
|
||||
|
||||
if sub.Use == use {
|
||||
cmd = sub
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if use == root.Use {
|
||||
cmd = root
|
||||
}
|
||||
|
||||
if cmd == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
Unmarshal(cmd, ptr)
|
||||
}
|
||||
}
|
||||
|
||||
func Unmarshal(cmd *cobra.Command, target any) {
|
||||
t := reflect.TypeOf(target).Elem()
|
||||
v := reflect.ValueOf(target).Elem()
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
valPtr := v.Field(i).Addr().Interface()
|
||||
|
||||
full := field.Tag.Get("full")
|
||||
short := field.Tag.Get("short")
|
||||
def := field.Tag.Get("def")
|
||||
desc := field.Tag.Get("desc")
|
||||
isPersistent := field.Tag.Get("persistent") == "true"
|
||||
|
||||
flagSet := cmd.Flags()
|
||||
if isPersistent {
|
||||
flagSet = cmd.PersistentFlags()
|
||||
}
|
||||
|
||||
switch field.Type.Kind() {
|
||||
case reflect.String:
|
||||
flagSet.StringVarP(valPtr.(*string), full, short, def, desc)
|
||||
|
||||
case reflect.Bool:
|
||||
defVal, err := strconv.ParseBool(def)
|
||||
if err != nil && def != "" {
|
||||
fmt.Printf("warning: cannot parse default bool: %q\n", def)
|
||||
}
|
||||
flagSet.BoolVarP(valPtr.(*bool), full, short, defVal, desc)
|
||||
|
||||
case reflect.Int:
|
||||
defVal, err := strconv.Atoi(def)
|
||||
if err != nil && def != "" {
|
||||
fmt.Printf("warning: cannot parse default int: %q\n", def)
|
||||
}
|
||||
flagSet.IntVarP(valPtr.(*int), full, short, defVal, desc)
|
||||
|
||||
case reflect.Slice:
|
||||
elemKind := field.Type.Elem().Kind()
|
||||
switch elemKind {
|
||||
case reflect.String:
|
||||
defVals := []string{}
|
||||
if def != "" {
|
||||
defVals = strings.Split(def, ",")
|
||||
}
|
||||
flagSet.StringSliceVarP(valPtr.(*[]string), full, short, defVals, desc)
|
||||
|
||||
case reflect.Int:
|
||||
var intVals []int
|
||||
if def != "" {
|
||||
for _, s := range strings.Split(def, ",") {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
n, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
fmt.Printf("warning: cannot parse int in slice: %q\n", s)
|
||||
continue
|
||||
}
|
||||
intVals = append(intVals, n)
|
||||
}
|
||||
}
|
||||
flagSet.IntSliceVarP(valPtr.(*[]int), full, short, intVals, desc)
|
||||
|
||||
default:
|
||||
fmt.Printf("unsupported slice element type: %s\n", elemKind)
|
||||
}
|
||||
|
||||
default:
|
||||
fmt.Printf("unsupported field type: %s\n", field.Type.Kind())
|
||||
}
|
||||
}
|
||||
}
|
||||
82
src/internal/engine/config/config.go
Normal file
82
src/internal/engine/config/config.go
Normal file
@@ -0,0 +1,82 @@
|
||||
// Package config provides configuration management for the application.
|
||||
// config is built on top of the third-party module cleanenv
|
||||
package config
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type CompositorContract interface {
|
||||
LoadEnv() error
|
||||
LoadConf(path string) error
|
||||
}
|
||||
|
||||
type Compositor struct {
|
||||
CMDLine *CMDLine
|
||||
Conf *Conf
|
||||
Env *Env
|
||||
}
|
||||
|
||||
type Conf struct {
|
||||
Node *Node `mapstructure:"node"`
|
||||
HTTPServer *HTTPServer `mapstructure:"http_server"`
|
||||
TLS *TLS `mapstructure:"tls"`
|
||||
Updates *Updates `mapstructure:"updates"`
|
||||
Log *Log `mapstructure:"log"`
|
||||
DisableWarnings *[]string `mapstructure:"disable_warnings"`
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
Mode *string `mapstructure:"mode"`
|
||||
Name *string `mapstructure:"name"`
|
||||
ShowConfig *bool `mapstructure:"show_config"`
|
||||
ComDir *string `mapstructure:"com_dir"`
|
||||
}
|
||||
|
||||
type HTTPServer struct {
|
||||
Address *string `mapstructure:"address"`
|
||||
Port *string `mapstructure:"port"`
|
||||
SessionTTL *time.Duration `mapstructure:"session_ttl"`
|
||||
Timeout *time.Duration `mapstructure:"timeout"`
|
||||
IdleTimeout *time.Duration `mapstructure:"idle_timeout"`
|
||||
}
|
||||
|
||||
type TLS struct {
|
||||
TlsEnabled *bool `mapstructure:"enabled"`
|
||||
CertFile *string `mapstructure:"cert_file"`
|
||||
KeyFile *string `mapstructure:"key_file"`
|
||||
}
|
||||
|
||||
type Updates struct {
|
||||
UpdatesEnabled *bool `mapstructure:"enabled"`
|
||||
CheckInterval *time.Duration `mapstructure:"check_interval"`
|
||||
RepositoryURL *string `mapstructure:"repository_url"`
|
||||
WantedVersion *string `mapstructure:"wanted_version"`
|
||||
}
|
||||
|
||||
type Log struct {
|
||||
JSON *bool `mapstructure:"json_format"`
|
||||
Level *string `mapstructure:"level"`
|
||||
OutPath *string `mapstructure:"output"`
|
||||
}
|
||||
|
||||
// ConfigEnv structure for environment variables
|
||||
type Env struct {
|
||||
ConfigPath *string `mapstructure:"config_path"`
|
||||
NodePath *string `mapstructure:"node_path"`
|
||||
ParentStagePID *int `mapstructure:"parent_pid"`
|
||||
}
|
||||
|
||||
type CMDLine struct {
|
||||
Run Run
|
||||
Node Root
|
||||
}
|
||||
|
||||
type Root struct {
|
||||
Debug bool `persistent:"true" full:"debug" short:"d" def:"false" desc:"Set debug mode"`
|
||||
}
|
||||
|
||||
type Run struct {
|
||||
ConfigPath string `persistent:"true" full:"config" short:"c" def:"./config.yaml" desc:"Path to configuration file"`
|
||||
Test []int `persistent:"true" full:"test" short:"t" def:"" desc:"js test"`
|
||||
}
|
||||
36
src/internal/engine/config/consts.go
Normal file
36
src/internal/engine/config/consts.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package config
|
||||
|
||||
import "os"
|
||||
|
||||
// TODO: Need to make a more harmonious and understandable way of storing global variables
|
||||
|
||||
// UUIDLength is uuids length for sessions. By default it is 16 bytes.
|
||||
var UUIDLength int = 16
|
||||
|
||||
// ApiRoute setting for go-chi for main route for api requests
|
||||
var ApiRoute string = "/api/{ver}"
|
||||
|
||||
// ComDirRoute setting for go-chi for main route for commands
|
||||
var ComDirRoute string = "/com"
|
||||
|
||||
// NodeVersion is the version of the node. It can be set by the build system or manually.
|
||||
// If not set, it will return "version0.0.0-none" by default
|
||||
var NodeVersion string
|
||||
|
||||
// ActualFileName is a feature of the GoSally update system.
|
||||
// In the repository, the file specified in the variable contains the current information about updates
|
||||
var ActualFileName string = "actual.txt"
|
||||
|
||||
// UpdateArchiveName is the name of the archive that will be used for updates.
|
||||
var UpdateArchiveName string = "gosally-node"
|
||||
|
||||
// UpdateInstallPath is the path where the update will be installed.
|
||||
var UpdateDownloadPath string = os.TempDir()
|
||||
|
||||
var MetaDir string = "./.meta"
|
||||
|
||||
func init() {
|
||||
if NodeVersion == "" {
|
||||
NodeVersion = "v0.0.0-none"
|
||||
}
|
||||
}
|
||||
72
src/internal/engine/config/print.go
Normal file
72
src/internal/engine/config/print.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/akyaiy/GoSally-mvp/internal/colors"
|
||||
)
|
||||
|
||||
func (c *Compositor) Print(v any) {
|
||||
c.printConfig(v, " ")
|
||||
}
|
||||
|
||||
func (c *Compositor) printConfig(v any, prefix string) {
|
||||
val := reflect.ValueOf(v)
|
||||
if val.Kind() == reflect.Ptr {
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
typ := val.Type()
|
||||
|
||||
for i := 0; i < val.NumField(); i++ {
|
||||
field := val.Field(i)
|
||||
fieldType := typ.Field(i)
|
||||
|
||||
fieldName := fieldType.Name
|
||||
if tag, ok := fieldType.Tag.Lookup("mapstructure"); ok {
|
||||
if tag != "" {
|
||||
fieldName = tag
|
||||
}
|
||||
}
|
||||
|
||||
coloredFieldName := colors.SetBrightCyan(fieldName)
|
||||
|
||||
if field.Kind() == reflect.Ptr {
|
||||
if field.IsNil() {
|
||||
fmt.Printf("%s%s: %s\n", prefix, coloredFieldName, colors.SetBrightRed("<nil>"))
|
||||
continue
|
||||
}
|
||||
field = field.Elem()
|
||||
}
|
||||
|
||||
if field.Kind() == reflect.Struct {
|
||||
if field.Type() == reflect.TypeOf(time.Duration(0)) {
|
||||
duration := field.Interface().(time.Duration)
|
||||
fmt.Printf("%s%s: %s\n",
|
||||
prefix,
|
||||
coloredFieldName,
|
||||
colors.SetBrightYellow(duration.String()))
|
||||
} else {
|
||||
fmt.Printf("%s%s:\n", prefix, coloredFieldName)
|
||||
c.printConfig(field.Addr().Interface(), prefix+" ")
|
||||
}
|
||||
} else if field.Kind() == reflect.Slice {
|
||||
fmt.Printf("%s%s: %s\n",
|
||||
prefix,
|
||||
coloredFieldName,
|
||||
colors.SetBrightYellow(fmt.Sprintf("%v", field.Interface())))
|
||||
} else {
|
||||
value := field.Interface()
|
||||
valueStr := fmt.Sprintf("%v", value)
|
||||
if field.Kind() == reflect.String {
|
||||
valueStr = fmt.Sprintf("\"%s\"", value)
|
||||
}
|
||||
fmt.Printf("%s%s: %s\n",
|
||||
prefix,
|
||||
coloredFieldName,
|
||||
colors.SetBrightYellow(valueStr))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user