313 lines
6.2 KiB
Go
313 lines
6.2 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
|
|
Static 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) {
|
|
// For simple configs, use standard libraries to ensure proper loading
|
|
state := luajit.New(true)
|
|
if state == nil {
|
|
return nil, errors.New("failed to create Lua state")
|
|
}
|
|
defer state.Close()
|
|
|
|
// Create config with default values
|
|
config := New()
|
|
|
|
// Execute the config file
|
|
if err := state.DoFile(filePath); err != nil {
|
|
return nil, fmt.Errorf("%w", err)
|
|
}
|
|
|
|
// Extract configuration values
|
|
extractConfig(state, config)
|
|
|
|
return config, nil
|
|
}
|
|
|
|
// extractConfig extracts configuration values directly by name
|
|
func extractConfig(state *luajit.State, config *Config) {
|
|
// Process known config values directly by key
|
|
if value := extractValue(state, "debug"); value != nil {
|
|
if boolVal, ok := value.(bool); ok {
|
|
config.Debug = boolVal
|
|
}
|
|
}
|
|
|
|
if value := extractValue(state, "log_level"); value != nil {
|
|
if strVal, ok := value.(string); ok {
|
|
config.LogLevel = strVal
|
|
}
|
|
}
|
|
|
|
if value := extractValue(state, "port"); value != nil {
|
|
if numVal, ok := value.(float64); ok {
|
|
config.Port = int(numVal)
|
|
}
|
|
}
|
|
|
|
if value := extractValue(state, "routes_dir"); value != nil {
|
|
if strVal, ok := value.(string); ok {
|
|
config.RoutesDir = strVal
|
|
}
|
|
}
|
|
|
|
if value := extractValue(state, "static_dir"); value != nil {
|
|
if strVal, ok := value.(string); ok {
|
|
config.StaticDir = strVal
|
|
}
|
|
}
|
|
|
|
if value := extractValue(state, "override_dir"); value != nil {
|
|
if strVal, ok := value.(string); ok {
|
|
config.OverrideDir = strVal
|
|
}
|
|
}
|
|
|
|
if value := extractValue(state, "pool_size"); value != nil {
|
|
if numVal, ok := value.(float64); ok {
|
|
config.PoolSize = int(numVal)
|
|
}
|
|
}
|
|
|
|
if value := extractValue(state, "http_logging_enabled"); value != nil {
|
|
if boolVal, ok := value.(bool); ok {
|
|
config.HTTPLoggingEnabled = boolVal
|
|
}
|
|
}
|
|
|
|
// Handle watchers table
|
|
if value := extractValue(state, "watchers"); value != nil {
|
|
if table, ok := value.(map[string]any); ok {
|
|
if routes, ok := table["routes"].(bool); ok {
|
|
config.Watchers.Routes = routes
|
|
}
|
|
if static, ok := table["static"].(bool); ok {
|
|
config.Watchers.Static = static
|
|
}
|
|
if modules, ok := table["modules"].(bool); ok {
|
|
config.Watchers.Modules = modules
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle lib_dirs array
|
|
if value := extractValue(state, "lib_dirs"); value != nil {
|
|
if dirs := extractStringArray(value); len(dirs) > 0 {
|
|
config.LibDirs = dirs
|
|
}
|
|
}
|
|
}
|
|
|
|
// extractValue extracts a specific global value from the Lua state
|
|
func extractValue(state *luajit.State, key string) any {
|
|
state.GetGlobal(key)
|
|
defer state.Pop(1)
|
|
|
|
if state.IsNil(-1) {
|
|
return nil
|
|
}
|
|
|
|
value, err := state.ToValue(-1)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
// extractStringArray extracts a string array from various possible formats
|
|
func extractStringArray(value any) []string {
|
|
// Check if it's a direct array
|
|
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
|
|
}
|
|
|
|
// Check if it's in special array format (map with empty key)
|
|
valueMap, ok := value.(map[string]any)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
arr, ok := valueMap[""]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
// Handle different array types
|
|
switch arr := arr.(type) {
|
|
case []string:
|
|
return arr
|
|
case []any:
|
|
result := make([]string, 0, len(arr))
|
|
for _, v := range arr {
|
|
if str, ok := v.(string); ok {
|
|
result = append(result, str)
|
|
}
|
|
}
|
|
return result
|
|
case []float64:
|
|
result := make([]string, 0, len(arr))
|
|
for _, v := range arr {
|
|
result = append(result, fmt.Sprintf("%g", v))
|
|
}
|
|
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
|
|
}
|