277 lines
5.5 KiB
Go
277 lines
5.5 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"runtime"
|
|
"strconv"
|
|
|
|
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
|
|
)
|
|
|
|
// Config represents a configuration loaded from a Lua file
|
|
type Config struct {
|
|
// Server settings
|
|
LogLevel string
|
|
Port int
|
|
Debug bool
|
|
|
|
// Directory paths
|
|
RoutesDir string
|
|
StaticDir string
|
|
OverrideDir string
|
|
LibDirs []string
|
|
|
|
// Performance settings
|
|
PoolSize int
|
|
|
|
// Feature flags
|
|
HTTPLoggingEnabled bool
|
|
Watchers struct {
|
|
Routes bool
|
|
Modules bool
|
|
}
|
|
|
|
// Raw values map for custom values
|
|
values map[string]any
|
|
}
|
|
|
|
// 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,
|
|
|
|
// Initialize values map
|
|
values: make(map[string]any),
|
|
}
|
|
}
|
|
|
|
// Load loads configuration from a Lua file
|
|
func Load(filePath string) (*Config, error) {
|
|
// Create Lua state
|
|
state := luajit.New(true)
|
|
if state == nil {
|
|
return nil, errors.New("failed to create Lua state")
|
|
}
|
|
defer state.Close()
|
|
defer state.Cleanup()
|
|
|
|
// Create config with default values
|
|
config := New()
|
|
|
|
// Execute the config file
|
|
if err := state.DoFile(filePath); err != nil {
|
|
return nil, fmt.Errorf("failed to load config file: %w", err)
|
|
}
|
|
|
|
// 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)
|
|
if err == nil {
|
|
config.values[key] = value
|
|
}
|
|
}
|
|
state.Pop(1)
|
|
}
|
|
|
|
// Apply configuration values
|
|
applyConfig(config, config.values)
|
|
|
|
return config, nil
|
|
}
|
|
|
|
// 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
|
|
}
|
|
}
|
|
|
|
// 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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// extractStringArray extracts a string array from a Lua table
|
|
func extractStringArray(value any) []string {
|
|
// Direct array case
|
|
if arr, ok := value.([]any); ok {
|
|
result := make([]string, 0, len(arr))
|
|
for _, v := range arr {
|
|
if str, ok := v.(string); ok {
|
|
result = append(result, str)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// Map with numeric keys case
|
|
if tableMap, ok := value.(map[string]any); ok {
|
|
result := make([]string, 0, len(tableMap))
|
|
for _, v := range tableMap {
|
|
if str, ok := v.(string); ok {
|
|
result = append(result, str)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetCustomValue returns any custom configuration value by key
|
|
func (c *Config) GetCustomValue(key string) any {
|
|
return c.values[key]
|
|
}
|
|
|
|
// GetCustomString returns a custom string configuration value
|
|
func (c *Config) GetCustomString(key string, defaultValue string) string {
|
|
value := c.values[key]
|
|
if value == nil {
|
|
return defaultValue
|
|
}
|
|
|
|
// Convert to string
|
|
switch v := value.(type) {
|
|
case string:
|
|
return v
|
|
case float64:
|
|
return fmt.Sprintf("%g", v)
|
|
case int:
|
|
return strconv.Itoa(v)
|
|
case bool:
|
|
if v {
|
|
return "true"
|
|
}
|
|
return "false"
|
|
default:
|
|
return defaultValue
|
|
}
|
|
}
|
|
|
|
// GetCustomInt returns a custom integer configuration value
|
|
func (c *Config) GetCustomInt(key string, defaultValue int) int {
|
|
value := c.values[key]
|
|
if value == nil {
|
|
return defaultValue
|
|
}
|
|
|
|
// Convert to int
|
|
switch v := value.(type) {
|
|
case int:
|
|
return v
|
|
case float64:
|
|
return int(v)
|
|
case string:
|
|
if i, err := strconv.Atoi(v); err == nil {
|
|
return i
|
|
}
|
|
case bool:
|
|
if v {
|
|
return 1
|
|
}
|
|
return 0
|
|
default:
|
|
return defaultValue
|
|
}
|
|
|
|
return defaultValue
|
|
}
|
|
|
|
// GetCustomBool returns a custom boolean configuration value
|
|
func (c *Config) GetCustomBool(key string, defaultValue bool) bool {
|
|
value := c.values[key]
|
|
if value == nil {
|
|
return defaultValue
|
|
}
|
|
|
|
// Convert to bool
|
|
switch v := value.(type) {
|
|
case bool:
|
|
return v
|
|
case string:
|
|
switch v {
|
|
case "true", "yes", "1":
|
|
return true
|
|
case "false", "no", "0", "":
|
|
return false
|
|
}
|
|
case int:
|
|
return v != 0
|
|
case float64:
|
|
return v != 0
|
|
default:
|
|
return defaultValue
|
|
}
|
|
|
|
return defaultValue
|
|
}
|