move go files to src/

This commit is contained in:
2025-10-10 22:46:24 +03:00
parent f0c591f325
commit 57f35e8f33
45 changed files with 0 additions and 0 deletions

View 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())
}
}
}

View 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"`
}

View 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"
}
}

View 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))
}
}
}