From d07673e0884c15df32df8346b8573b7a23f06e7e Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Fri, 4 Apr 2025 18:33:39 -0500 Subject: [PATCH] refactor config, add example config --- config-example.lua | 21 +++++ core/Moonshark.go | 72 +++++++-------- core/config/Config.go | 204 ++++++++++++++++++++++-------------------- 3 files changed, 164 insertions(+), 133 deletions(-) create mode 100644 config-example.lua diff --git a/config-example.lua b/config-example.lua new file mode 100644 index 0000000..cd6767e --- /dev/null +++ b/config-example.lua @@ -0,0 +1,21 @@ +server = { + port = 3117, + debug = false, + log_level = "info", + http_logging = false +} + +runner = { + pool_size = GOMAXPROCS +} + +dirs = { + routes = "./routes", + static = "./static", + fs = "./fs", + data = "./data", + override = "./override", + libs = { + "./libs" + } +} diff --git a/core/Moonshark.go b/core/Moonshark.go index 6007261..39af91c 100644 --- a/core/Moonshark.go +++ b/core/Moonshark.go @@ -61,9 +61,9 @@ func NewMoonshark(configPath string) (*Moonshark, error) { server.LuaRouter, server.StaticRouter, server.LuaRunner, - server.Config.HTTPLoggingEnabled, - server.Config.Debug, - server.Config.OverrideDir, + server.Config.Server.HTTPLogging, + server.Config.Server.Debug, + server.Config.Dirs.Override, server.Config, ) @@ -88,7 +88,7 @@ func (s *Moonshark) loadConfig(configPath string) error { // setupLogging configures the logger based on config settings func (s *Moonshark) setupLogging() { // Set log level from config - switch s.Config.LogLevel { + switch s.Config.Server.LogLevel { case "warn": logger.SetLevel(logger.LevelWarning) case "error": @@ -102,7 +102,7 @@ func (s *Moonshark) setupLogging() { } // Set debug mode if configured - if s.Config.Debug { + if s.Config.Server.Debug { logger.EnableDebug() // Force debug logs regardless of level logger.Debug("Debug mode is ready to party, bro") } @@ -111,17 +111,17 @@ func (s *Moonshark) setupLogging() { // initRouters initializes the Lua and static routers func (s *Moonshark) initRouters() error { // Ensure directories exist - if err := utils.EnsureDir(s.Config.RoutesDir); err != nil { + if err := utils.EnsureDir(s.Config.Dirs.Routes); err != nil { return fmt.Errorf("routes directory doesn't exist and could not be created: %v", err) } - if err := utils.EnsureDir(s.Config.StaticDir); err != nil { + if err := utils.EnsureDir(s.Config.Dirs.Static); err != nil { return fmt.Errorf("static directory doesn't exist and could not be created: %v", err) } // Initialize Lua router for dynamic routes var err error - s.LuaRouter, err = routers.NewLuaRouter(s.Config.RoutesDir) + s.LuaRouter, err = routers.NewLuaRouter(s.Config.Dirs.Routes) if err != nil { // Check if this is a compilation warning or a more serious error if errors.Is(err, routers.ErrRoutesCompilationErrors) { @@ -139,14 +139,14 @@ func (s *Moonshark) initRouters() error { return fmt.Errorf("failed to initialize Lua router: %v", err) } } - logger.Info("Lua router is stoked and riding routes from %s", s.Config.RoutesDir) + logger.Info("Lua router is stoked and riding routes from %s", s.Config.Dirs.Routes) // Initialize static file router - s.StaticRouter, err = routers.NewStaticRouter(s.Config.StaticDir) + s.StaticRouter, err = routers.NewStaticRouter(s.Config.Dirs.Static) if err != nil { return fmt.Errorf("failed to initialize static router: %v", err) } - logger.Info("Static router catching waves with files from %s", s.Config.StaticDir) + logger.Info("Static router catching waves with files from %s", s.Config.Dirs.Static) s.StaticRouter.EnableDebugLog() return nil @@ -155,13 +155,13 @@ func (s *Moonshark) initRouters() error { // initRunner initializes the Lua runner func (s *Moonshark) initRunner() error { // Ensure override directory exists - if err := utils.EnsureDir(s.Config.OverrideDir); err != nil { + if err := utils.EnsureDir(s.Config.Dirs.Override); err != nil { logger.Warning("Override directory doesn't exist and could not be created: %v", err) - s.Config.OverrideDir = "" // Disable overrides if directory can't be created + s.Config.Dirs.Override = "" // Disable overrides if directory can't be created } // Ensure lib directories exist - for _, dir := range s.Config.LibDirs { + for _, dir := range s.Config.Dirs.Libs { if err := utils.EnsureDir(dir); err != nil { logger.Warning("Lib directory doesn't exist and could not be created: %v", err) } @@ -182,14 +182,14 @@ func (s *Moonshark) initRunner() error { // Set up runner options runnerOpts := []runner.RunnerOption{ - runner.WithPoolSize(s.Config.PoolSize), - runner.WithLibDirs(s.Config.LibDirs...), + runner.WithPoolSize(s.Config.Runner.PoolSize), + runner.WithLibDirs(s.Config.Dirs.Libs...), runner.WithSessionManager(sessionManager), runner.WithCSRFProtection(), } // Add debug option conditionally - if s.Config.Debug { + if s.Config.Server.Debug { runnerOpts = append(runnerOpts, runner.WithDebugEnabled()) logger.Debug("Debug logging enabled for Lua runner") } @@ -201,34 +201,30 @@ func (s *Moonshark) initRunner() error { return fmt.Errorf("failed to initialize Lua runner: %v", err) } - logger.Server("Lua runner waxing up with a pool size of %d", s.Config.PoolSize) + logger.Server("Lua runner waxing up with a pool size of %d", s.Config.Runner.PoolSize) return nil } // setupWatchers initializes and starts all configured file watchers func (s *Moonshark) setupWatchers() error { // Set up watcher for Lua routes - if s.Config.Watchers.Routes { - luaRouterWatcher, err := watchers.WatchLuaRouter(s.LuaRouter, s.LuaRunner, s.Config.RoutesDir) - if err != nil { - logger.Warning("Failed to watch routes directory: %v", err) - } else { - s.cleanupFuncs = append(s.cleanupFuncs, luaRouterWatcher.Close) - } + luaRouterWatcher, err := watchers.WatchLuaRouter(s.LuaRouter, s.LuaRunner, s.Config.Dirs.Routes) + if err != nil { + logger.Warning("Failed to watch routes directory: %v", err) + } else { + s.cleanupFuncs = append(s.cleanupFuncs, luaRouterWatcher.Close) } // Set up watchers for Lua modules libraries - if s.Config.Watchers.Modules && len(s.Config.LibDirs) > 0 { - moduleWatchers, err := watchers.WatchLuaModules(s.LuaRunner, s.Config.LibDirs) - if err != nil { - logger.Warning("Failed to watch Lua module directories: %v", err) - } else { - for _, watcher := range moduleWatchers { - w := watcher // Capture variable for closure - s.cleanupFuncs = append(s.cleanupFuncs, w.Close) - } - logger.Info("File watchers active for %d Lua module directories", len(moduleWatchers)) + moduleWatchers, err := watchers.WatchLuaModules(s.LuaRunner, s.Config.Dirs.Libs) + if err != nil { + logger.Warning("Failed to watch Lua module directories: %v", err) + } else { + for _, watcher := range moduleWatchers { + w := watcher // Capture variable for closure + s.cleanupFuncs = append(s.cleanupFuncs, w.Close) } + logger.Info("File watchers active for %d Lua module directories", len(moduleWatchers)) } return nil @@ -236,10 +232,10 @@ func (s *Moonshark) setupWatchers() error { // Start starts the HTTP server func (s *Moonshark) Start() error { - logger.Server("Surf's up on port %d!", s.Config.Port) + logger.Server("Surf's up on port %d!", s.Config.Server.Port) // Log HTTP logging status - if s.Config.HTTPLoggingEnabled { + if s.Config.Server.HTTPLogging { logger.ServerCont("HTTP logging is turned on - watch those waves") } else { logger.ServerCont("HTTP logging is turned off - waves are flat bro") @@ -247,7 +243,7 @@ func (s *Moonshark) Start() error { // Start the server in a non-blocking way go func() { - if err := s.HTTPServer.ListenAndServe(fmt.Sprintf(":%d", s.Config.Port)); err != nil { + if err := s.HTTPServer.ListenAndServe(fmt.Sprintf(":%d", s.Config.Server.Port)); err != nil { if err.Error() != "http: Server closed" { logger.Error("Server error: %v", err) } diff --git a/core/config/Config.go b/core/config/Config.go index 7725693..67e69dd 100644 --- a/core/config/Config.go +++ b/core/config/Config.go @@ -5,6 +5,7 @@ import ( "fmt" "runtime" "strconv" + "strings" luajit "git.sharkk.net/Sky/LuaJIT-to-Go" ) @@ -12,24 +13,26 @@ import ( // Config represents a configuration loaded from a Lua file type Config struct { // Server settings - LogLevel string - Port int - Debug bool + Server struct { + Port int + Debug bool + LogLevel string + HTTPLogging bool + } + + // Runner settings + Runner struct { + PoolSize int + } // Directory paths - RoutesDir string - StaticDir string - OverrideDir string - LibDirs []string - - // Performance settings - PoolSize int - - // Feature flags - HTTPLoggingEnabled bool - Watchers struct { - Routes bool - Modules bool + Dirs struct { + Routes string + Static string + FS string + Data string + Override string + Libs []string } // Raw values map for custom values @@ -38,27 +41,29 @@ type Config struct { // New creates a new configuration with default values func New() *Config { - return &Config{ - // Server defaults - LogLevel: "info", - Port: 3117, - Debug: false, - - // Directory defaults - RoutesDir: "./routes", - StaticDir: "./static", - OverrideDir: "./override", - LibDirs: []string{"./libs"}, - - // Performance defaults - respect GOMAXPROCS - PoolSize: runtime.GOMAXPROCS(0), - - // Feature flag defaults - HTTPLoggingEnabled: true, - + config := &Config{ // Initialize values map values: make(map[string]any), } + + // Server defaults + config.Server.Port = 3117 + config.Server.Debug = false + config.Server.LogLevel = "info" + config.Server.HTTPLogging = false + + // Runner defaults + config.Runner.PoolSize = runtime.GOMAXPROCS(0) + + // Dirs defaults + config.Dirs.Routes = "./routes" + config.Dirs.Static = "./static" + config.Dirs.FS = "./fs" + config.Dirs.Data = "./data" + config.Dirs.Override = "./override" + config.Dirs.Libs = []string{"./libs"} + + return config } // Load loads configuration from a Lua file @@ -82,19 +87,14 @@ func Load(filePath string) (*Config, error) { // Store values directly to the config config.values = make(map[string]any) - // Extract all globals individually - globalKeys := []string{ - "debug", "log_level", "port", "routes_dir", "static_dir", - "override_dir", "pool_size", "http_logging_enabled", - "watchers", "lib_dirs", - } - - for _, key := range globalKeys { - state.GetGlobal(key) - if !state.IsNil(-1) { - value, err := state.ToValue(-1) + // Extract top-level tables + tables := []string{"server", "runner", "dirs"} + for _, table := range tables { + state.GetGlobal(table) + if state.IsTable(-1) { + tableMap, err := state.ToTable(-1) if err == nil { - config.values[key] = value + config.values[table] = tableMap } } state.Pop(1) @@ -107,54 +107,52 @@ func Load(filePath string) (*Config, error) { } // applyConfig applies configuration values from the globals map -func applyConfig(config *Config, globals map[string]any) { - // Server settings - if v, ok := globals["debug"].(bool); ok { - config.Debug = v - } - if v, ok := globals["log_level"].(string); ok { - config.LogLevel = v - } - if v, ok := globals["port"].(float64); ok { - config.Port = int(v) - } - - // Directory paths - if v, ok := globals["routes_dir"].(string); ok { - config.RoutesDir = v - } - if v, ok := globals["static_dir"].(string); ok { - config.StaticDir = v - } - if v, ok := globals["override_dir"].(string); ok { - config.OverrideDir = v - } - - // Performance settings - if v, ok := globals["pool_size"].(float64); ok { - config.PoolSize = int(v) - } - - // Feature flags - if v, ok := globals["http_logging_enabled"].(bool); ok { - config.HTTPLoggingEnabled = v - } - - // Handle lib_dirs array more efficiently - if libDirs, ok := globals["lib_dirs"]; ok { - if dirs := extractStringArray(libDirs); len(dirs) > 0 { - config.LibDirs = dirs +func applyConfig(config *Config, values map[string]any) { + // Apply server settings + if serverTable, ok := values["server"].(map[string]any); ok { + if v, ok := serverTable["port"].(float64); ok { + config.Server.Port = int(v) + } + if v, ok := serverTable["debug"].(bool); ok { + config.Server.Debug = v + } + if v, ok := serverTable["log_level"].(string); ok { + config.Server.LogLevel = v + } + if v, ok := serverTable["http_logging"].(bool); ok { + config.Server.HTTPLogging = v } } - // Handle watchers table - if watchersVal, ok := globals["watchers"]; ok { - if watchers, ok := watchersVal.(map[string]any); ok { - if v, ok := watchers["routes"].(bool); ok { - config.Watchers.Routes = v - } - if v, ok := watchers["modules"].(bool); ok { - config.Watchers.Modules = v + // Apply runner settings + if runnerTable, ok := values["runner"].(map[string]any); ok { + if v, ok := runnerTable["pool_size"].(float64); ok { + config.Runner.PoolSize = int(v) + } + } + + // Apply dirs settings + if dirsTable, ok := values["dirs"].(map[string]any); ok { + if v, ok := dirsTable["routes"].(string); ok { + config.Dirs.Routes = v + } + if v, ok := dirsTable["static"].(string); ok { + config.Dirs.Static = v + } + if v, ok := dirsTable["fs"].(string); ok { + config.Dirs.FS = v + } + if v, ok := dirsTable["data"].(string); ok { + config.Dirs.Data = v + } + if v, ok := dirsTable["override"].(string); ok { + config.Dirs.Override = v + } + + // Handle libs array + if libs, ok := dirsTable["libs"]; ok { + if libsArray := extractStringArray(libs); len(libsArray) > 0 { + config.Dirs.Libs = libsArray } } } @@ -188,13 +186,29 @@ func extractStringArray(value any) []string { } // GetCustomValue returns any custom configuration value by key +// Key can be a dotted path like "server.port" func (c *Config) GetCustomValue(key string) any { - return c.values[key] + parts := strings.Split(key, ".") + + if len(parts) == 1 { + return c.values[key] + } + + current := c.values + for _, part := range parts[:len(parts)-1] { + next, ok := current[part].(map[string]any) + if !ok { + return nil + } + current = next + } + + return current[parts[len(parts)-1]] } // GetCustomString returns a custom string configuration value func (c *Config) GetCustomString(key string, defaultValue string) string { - value := c.values[key] + value := c.GetCustomValue(key) if value == nil { return defaultValue } @@ -219,7 +233,7 @@ func (c *Config) GetCustomString(key string, defaultValue string) string { // GetCustomInt returns a custom integer configuration value func (c *Config) GetCustomInt(key string, defaultValue int) int { - value := c.values[key] + value := c.GetCustomValue(key) if value == nil { return defaultValue } @@ -248,7 +262,7 @@ func (c *Config) GetCustomInt(key string, defaultValue int) int { // GetCustomBool returns a custom boolean configuration value func (c *Config) GetCustomBool(key string, defaultValue bool) bool { - value := c.values[key] + value := c.GetCustomValue(key) if value == nil { return defaultValue }