config and debug page upgrades
This commit is contained in:
parent
da48f65e43
commit
0a1d0daa60
|
@ -9,12 +9,54 @@ import (
|
||||||
|
|
||||||
// Config represents a configuration loaded from a Lua file
|
// Config represents a configuration loaded from a Lua file
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
// Server settings
|
||||||
|
LogLevel string
|
||||||
|
Port int
|
||||||
|
Debug bool
|
||||||
|
|
||||||
|
// Directory paths
|
||||||
|
RoutesDir string
|
||||||
|
StaticDir string
|
||||||
|
OverrideDir string
|
||||||
|
LibDirs []string
|
||||||
|
|
||||||
|
// Performance settings
|
||||||
|
BufferSize int
|
||||||
|
|
||||||
|
// Feature flags
|
||||||
|
HTTPLoggingEnabled bool
|
||||||
|
Watchers map[string]bool
|
||||||
|
|
||||||
|
// Raw values map for backward compatibility and custom values
|
||||||
values map[string]any
|
values map[string]any
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new empty configuration
|
// New creates a new configuration with default values
|
||||||
func New() *Config {
|
func New() *Config {
|
||||||
return &Config{
|
return &Config{
|
||||||
|
// Server defaults
|
||||||
|
LogLevel: "info",
|
||||||
|
Port: 3117,
|
||||||
|
Debug: false,
|
||||||
|
|
||||||
|
// Directory defaults
|
||||||
|
RoutesDir: "./routes",
|
||||||
|
StaticDir: "./static",
|
||||||
|
OverrideDir: "./override",
|
||||||
|
LibDirs: []string{"./libs"},
|
||||||
|
|
||||||
|
// Performance defaults
|
||||||
|
BufferSize: 20,
|
||||||
|
|
||||||
|
// Feature flag defaults
|
||||||
|
HTTPLoggingEnabled: true,
|
||||||
|
Watchers: map[string]bool{
|
||||||
|
"routes": false,
|
||||||
|
"static": false,
|
||||||
|
"modules": false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Initialize values map
|
||||||
values: make(map[string]any),
|
values: make(map[string]any),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,16 +70,16 @@ func Load(filePath string) (*Config, error) {
|
||||||
}
|
}
|
||||||
defer state.Close()
|
defer state.Close()
|
||||||
|
|
||||||
|
// Create config with default values
|
||||||
|
config := New()
|
||||||
|
|
||||||
// Execute the Lua file
|
// Execute the Lua file
|
||||||
if err := state.DoFile(filePath); err != nil {
|
if err := state.DoFile(filePath); err != nil {
|
||||||
return nil, fmt.Errorf("failed to load config file: %w", err)
|
return nil, fmt.Errorf("failed to load config file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the config instance
|
|
||||||
config := New()
|
|
||||||
|
|
||||||
// Extract values from the Lua state
|
// Extract values from the Lua state
|
||||||
if err := extractGlobals(state, config.values); err != nil {
|
if err := extractGlobals(state, config); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +87,7 @@ func Load(filePath string) (*Config, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractGlobals extracts global variables from the Lua state
|
// extractGlobals extracts global variables from the Lua state
|
||||||
func extractGlobals(state *luajit.State, values map[string]any) error {
|
func extractGlobals(state *luajit.State, config *Config) error {
|
||||||
// Get the globals table (_G)
|
// Get the globals table (_G)
|
||||||
state.GetGlobal("_G")
|
state.GetGlobal("_G")
|
||||||
if !state.IsTable(-1) {
|
if !state.IsTable(-1) {
|
||||||
|
@ -123,68 +165,8 @@ func extractGlobals(state *luajit.State, values map[string]any) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle primitive types directly
|
// Process based on key and type
|
||||||
switch valueType {
|
processConfigValue(state, config, key, valueType)
|
||||||
case luajit.TypeBoolean:
|
|
||||||
values[key] = state.ToBoolean(-1)
|
|
||||||
state.Pop(1)
|
|
||||||
continue
|
|
||||||
case luajit.TypeNumber:
|
|
||||||
values[key] = state.ToNumber(-1)
|
|
||||||
state.Pop(1)
|
|
||||||
continue
|
|
||||||
case luajit.TypeString:
|
|
||||||
values[key] = state.ToString(-1)
|
|
||||||
state.Pop(1)
|
|
||||||
continue
|
|
||||||
case luajit.TypeTable:
|
|
||||||
// For tables, use the existing conversion logic
|
|
||||||
default:
|
|
||||||
// Skip unsupported types
|
|
||||||
state.Pop(1)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle tables (arrays and maps)
|
|
||||||
if valueType == luajit.TypeTable {
|
|
||||||
// Check if it looks like an array first
|
|
||||||
arrLen := state.GetTableLength(-1)
|
|
||||||
if arrLen > 0 {
|
|
||||||
// Process as array
|
|
||||||
arr := make([]any, arrLen)
|
|
||||||
for i := 1; i <= arrLen; i++ {
|
|
||||||
state.PushNumber(float64(i))
|
|
||||||
state.GetTable(-2) // Get t[i]
|
|
||||||
|
|
||||||
switch state.GetType(-1) {
|
|
||||||
case luajit.TypeBoolean:
|
|
||||||
arr[i-1] = state.ToBoolean(-1)
|
|
||||||
case luajit.TypeNumber:
|
|
||||||
arr[i-1] = state.ToNumber(-1)
|
|
||||||
case luajit.TypeString:
|
|
||||||
arr[i-1] = state.ToString(-1)
|
|
||||||
default:
|
|
||||||
// For complex elements, try to convert
|
|
||||||
if val, err := state.ToValue(-1); err == nil {
|
|
||||||
arr[i-1] = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state.Pop(1) // Pop value
|
|
||||||
}
|
|
||||||
values[key] = arr
|
|
||||||
state.Pop(1)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try normal table conversion for non-array tables
|
|
||||||
if table, err := state.ToTable(-1); err == nil {
|
|
||||||
values[key] = table
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pop value, leave key for next iteration
|
|
||||||
state.Pop(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pop the globals table
|
// Pop the globals table
|
||||||
|
@ -193,6 +175,147 @@ func extractGlobals(state *luajit.State, values map[string]any) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// processConfigValue processes a specific config value from Lua
|
||||||
|
func processConfigValue(state *luajit.State, config *Config, key string, valueType luajit.LuaType) {
|
||||||
|
// Store in the values map first (for backward compatibility)
|
||||||
|
var value any
|
||||||
|
|
||||||
|
// Extract the value based on its type
|
||||||
|
switch valueType {
|
||||||
|
case luajit.TypeBoolean:
|
||||||
|
value = state.ToBoolean(-1)
|
||||||
|
case luajit.TypeNumber:
|
||||||
|
value = state.ToNumber(-1)
|
||||||
|
case luajit.TypeString:
|
||||||
|
value = state.ToString(-1)
|
||||||
|
case luajit.TypeTable:
|
||||||
|
// For tables, use the existing conversion logic
|
||||||
|
if table, err := state.ToTable(-1); err == nil {
|
||||||
|
value = table
|
||||||
|
|
||||||
|
// Special case for watchers table
|
||||||
|
if key == "watchers" {
|
||||||
|
processWatchersTable(config, table)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Skip unsupported types
|
||||||
|
state.Pop(1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store in the values map
|
||||||
|
config.values[key] = value
|
||||||
|
|
||||||
|
// Now set specific struct fields based on key
|
||||||
|
switch key {
|
||||||
|
case "log_level":
|
||||||
|
if strVal, ok := value.(string); ok {
|
||||||
|
config.LogLevel = strVal
|
||||||
|
}
|
||||||
|
case "port":
|
||||||
|
if numVal, ok := value.(float64); ok {
|
||||||
|
config.Port = int(numVal)
|
||||||
|
}
|
||||||
|
case "debug":
|
||||||
|
if boolVal, ok := value.(bool); ok {
|
||||||
|
config.Debug = boolVal
|
||||||
|
}
|
||||||
|
case "routes_dir":
|
||||||
|
if strVal, ok := value.(string); ok {
|
||||||
|
config.RoutesDir = strVal
|
||||||
|
}
|
||||||
|
case "static_dir":
|
||||||
|
if strVal, ok := value.(string); ok {
|
||||||
|
config.StaticDir = strVal
|
||||||
|
}
|
||||||
|
case "override_dir":
|
||||||
|
if strVal, ok := value.(string); ok {
|
||||||
|
config.OverrideDir = strVal
|
||||||
|
}
|
||||||
|
case "buffer_size":
|
||||||
|
if numVal, ok := value.(float64); ok {
|
||||||
|
config.BufferSize = int(numVal)
|
||||||
|
}
|
||||||
|
case "http_logging_enabled":
|
||||||
|
if boolVal, ok := value.(bool); ok {
|
||||||
|
config.HTTPLoggingEnabled = boolVal
|
||||||
|
}
|
||||||
|
case "lib_dirs":
|
||||||
|
// Handle lib_dirs array
|
||||||
|
processLibDirs(config, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Pop(1) // Pop value, leave key for next iteration
|
||||||
|
}
|
||||||
|
|
||||||
|
// processWatchersTable processes the watchers table configuration
|
||||||
|
func processWatchersTable(config *Config, watchersTable map[string]any) {
|
||||||
|
for key, value := range watchersTable {
|
||||||
|
if boolVal, ok := value.(bool); ok {
|
||||||
|
config.Watchers[key] = boolVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// processLibDirs processes the lib_dirs array configuration
|
||||||
|
func processLibDirs(config *Config, value any) {
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(result) > 0 {
|
||||||
|
config.LibDirs = result
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's in our special array format (map with empty key)
|
||||||
|
valueMap, ok := value.(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
arr, ok := valueMap[""]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle array format
|
||||||
|
if strArray := extractStringArray(arr); len(strArray) > 0 {
|
||||||
|
config.LibDirs = strArray
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractStringArray extracts a string array from various possible formats
|
||||||
|
func extractStringArray(arr any) []string {
|
||||||
|
// Check different possible array formats
|
||||||
|
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:
|
||||||
|
// Unlikely but handle numeric arrays too
|
||||||
|
result := make([]string, 0, len(arr))
|
||||||
|
for _, v := range arr {
|
||||||
|
result = append(result, fmt.Sprintf("%g", v))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Get returns a configuration value by key
|
// Get returns a configuration value by key
|
||||||
func (c *Config) Get(key string) any {
|
func (c *Config) Get(key string) any {
|
||||||
return c.values[key]
|
return c.values[key]
|
||||||
|
@ -200,6 +323,19 @@ func (c *Config) Get(key string) any {
|
||||||
|
|
||||||
// GetString returns a string configuration value
|
// GetString returns a string configuration value
|
||||||
func (c *Config) GetString(key string, defaultValue string) string {
|
func (c *Config) GetString(key string, defaultValue string) string {
|
||||||
|
// Check for specific struct fields first
|
||||||
|
switch key {
|
||||||
|
case "log_level":
|
||||||
|
return c.LogLevel
|
||||||
|
case "routes_dir":
|
||||||
|
return c.RoutesDir
|
||||||
|
case "static_dir":
|
||||||
|
return c.StaticDir
|
||||||
|
case "override_dir":
|
||||||
|
return c.OverrideDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to values map for other keys
|
||||||
value, ok := c.values[key]
|
value, ok := c.values[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
return defaultValue
|
return defaultValue
|
||||||
|
@ -215,6 +351,15 @@ func (c *Config) GetString(key string, defaultValue string) string {
|
||||||
|
|
||||||
// GetInt returns an integer configuration value
|
// GetInt returns an integer configuration value
|
||||||
func (c *Config) GetInt(key string, defaultValue int) int {
|
func (c *Config) GetInt(key string, defaultValue int) int {
|
||||||
|
// Check for specific struct fields first
|
||||||
|
switch key {
|
||||||
|
case "port":
|
||||||
|
return c.Port
|
||||||
|
case "buffer_size":
|
||||||
|
return c.BufferSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to values map for other keys
|
||||||
value, ok := c.values[key]
|
value, ok := c.values[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
return defaultValue
|
return defaultValue
|
||||||
|
@ -251,6 +396,24 @@ func (c *Config) GetFloat(key string, defaultValue float64) float64 {
|
||||||
|
|
||||||
// GetBool returns a boolean configuration value
|
// GetBool returns a boolean configuration value
|
||||||
func (c *Config) GetBool(key string, defaultValue bool) bool {
|
func (c *Config) GetBool(key string, defaultValue bool) bool {
|
||||||
|
// Check for specific struct fields first
|
||||||
|
switch key {
|
||||||
|
case "debug":
|
||||||
|
return c.Debug
|
||||||
|
case "http_logging_enabled":
|
||||||
|
return c.HTTPLoggingEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for watcher settings
|
||||||
|
if key == "watchers.routes" {
|
||||||
|
return c.Watchers["routes"]
|
||||||
|
} else if key == "watchers.static" {
|
||||||
|
return c.Watchers["static"]
|
||||||
|
} else if key == "watchers.modules" {
|
||||||
|
return c.Watchers["modules"]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to values map for other keys
|
||||||
value, ok := c.values[key]
|
value, ok := c.values[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
return defaultValue
|
return defaultValue
|
||||||
|
@ -266,6 +429,15 @@ func (c *Config) GetBool(key string, defaultValue bool) bool {
|
||||||
|
|
||||||
// GetMap returns a map configuration value
|
// GetMap returns a map configuration value
|
||||||
func (c *Config) GetMap(key string) map[string]any {
|
func (c *Config) GetMap(key string) map[string]any {
|
||||||
|
// Special case for watchers
|
||||||
|
if key == "watchers" {
|
||||||
|
result := make(map[string]any)
|
||||||
|
for k, v := range c.Watchers {
|
||||||
|
result[k] = v
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
value, ok := c.values[key]
|
value, ok := c.values[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
|
@ -281,6 +453,15 @@ func (c *Config) GetMap(key string) map[string]any {
|
||||||
|
|
||||||
// GetArray returns an array of values from a Lua array
|
// GetArray returns an array of values from a Lua array
|
||||||
func (c *Config) GetArray(key string) []any {
|
func (c *Config) GetArray(key string) []any {
|
||||||
|
// Special case for lib_dirs
|
||||||
|
if key == "lib_dirs" {
|
||||||
|
result := make([]any, len(c.LibDirs))
|
||||||
|
for i, v := range c.LibDirs {
|
||||||
|
result[i] = v
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
value := c.Get(key)
|
value := c.Get(key)
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -369,6 +550,11 @@ func (c *Config) GetIntArray(key string) []int {
|
||||||
|
|
||||||
// GetStringArray returns an array of strings from a Lua array
|
// GetStringArray returns an array of strings from a Lua array
|
||||||
func (c *Config) GetStringArray(key string) []string {
|
func (c *Config) GetStringArray(key string) []string {
|
||||||
|
// Special case for lib_dirs
|
||||||
|
if key == "lib_dirs" {
|
||||||
|
return c.LibDirs
|
||||||
|
}
|
||||||
|
|
||||||
arr := c.GetArray(key)
|
arr := c.GetArray(key)
|
||||||
if arr == nil {
|
if arr == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -393,4 +579,44 @@ func (c *Config) Values() map[string]any {
|
||||||
// Set sets a configuration value
|
// Set sets a configuration value
|
||||||
func (c *Config) Set(key string, value any) {
|
func (c *Config) Set(key string, value any) {
|
||||||
c.values[key] = value
|
c.values[key] = value
|
||||||
|
|
||||||
|
// Also update the struct field if applicable
|
||||||
|
switch key {
|
||||||
|
case "log_level":
|
||||||
|
if strVal, ok := value.(string); ok {
|
||||||
|
c.LogLevel = strVal
|
||||||
|
}
|
||||||
|
case "port":
|
||||||
|
if numVal, ok := value.(float64); ok {
|
||||||
|
c.Port = int(numVal)
|
||||||
|
} else if intVal, ok := value.(int); ok {
|
||||||
|
c.Port = intVal
|
||||||
|
}
|
||||||
|
case "debug":
|
||||||
|
if boolVal, ok := value.(bool); ok {
|
||||||
|
c.Debug = boolVal
|
||||||
|
}
|
||||||
|
case "routes_dir":
|
||||||
|
if strVal, ok := value.(string); ok {
|
||||||
|
c.RoutesDir = strVal
|
||||||
|
}
|
||||||
|
case "static_dir":
|
||||||
|
if strVal, ok := value.(string); ok {
|
||||||
|
c.StaticDir = strVal
|
||||||
|
}
|
||||||
|
case "override_dir":
|
||||||
|
if strVal, ok := value.(string); ok {
|
||||||
|
c.OverrideDir = strVal
|
||||||
|
}
|
||||||
|
case "buffer_size":
|
||||||
|
if numVal, ok := value.(float64); ok {
|
||||||
|
c.BufferSize = int(numVal)
|
||||||
|
} else if intVal, ok := value.(int); ok {
|
||||||
|
c.BufferSize = intVal
|
||||||
|
}
|
||||||
|
case "http_logging_enabled":
|
||||||
|
if boolVal, ok := value.(bool); ok {
|
||||||
|
c.HTTPLoggingEnabled = boolVal
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.sharkk.net/Sky/Moonshark/core/config"
|
||||||
"git.sharkk.net/Sky/Moonshark/core/logger"
|
"git.sharkk.net/Sky/Moonshark/core/logger"
|
||||||
"git.sharkk.net/Sky/Moonshark/core/routers"
|
"git.sharkk.net/Sky/Moonshark/core/routers"
|
||||||
"git.sharkk.net/Sky/Moonshark/core/runner"
|
"git.sharkk.net/Sky/Moonshark/core/runner"
|
||||||
|
@ -22,13 +23,14 @@ type Server struct {
|
||||||
httpServer *http.Server
|
httpServer *http.Server
|
||||||
loggingEnabled bool
|
loggingEnabled bool
|
||||||
debugMode bool // Controls whether to show error details
|
debugMode bool // Controls whether to show error details
|
||||||
|
config *config.Config
|
||||||
errorConfig utils.ErrorPageConfig
|
errorConfig utils.ErrorPageConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new HTTP server with optimized connection settings
|
// New creates a new HTTP server with optimized connection settings
|
||||||
func New(luaRouter *routers.LuaRouter, staticRouter *routers.StaticRouter,
|
func New(luaRouter *routers.LuaRouter, staticRouter *routers.StaticRouter,
|
||||||
runner *runner.LuaRunner, log *logger.Logger,
|
runner *runner.LuaRunner, log *logger.Logger,
|
||||||
loggingEnabled bool, debugMode bool, overrideDir string) *Server {
|
loggingEnabled bool, debugMode bool, overrideDir string, config *config.Config) *Server {
|
||||||
|
|
||||||
server := &Server{
|
server := &Server{
|
||||||
luaRouter: luaRouter,
|
luaRouter: luaRouter,
|
||||||
|
@ -38,6 +40,7 @@ func New(luaRouter *routers.LuaRouter, staticRouter *routers.StaticRouter,
|
||||||
httpServer: &http.Server{},
|
httpServer: &http.Server{},
|
||||||
loggingEnabled: loggingEnabled,
|
loggingEnabled: loggingEnabled,
|
||||||
debugMode: debugMode,
|
debugMode: debugMode,
|
||||||
|
config: config,
|
||||||
errorConfig: utils.ErrorPageConfig{
|
errorConfig: utils.ErrorPageConfig{
|
||||||
OverrideDir: overrideDir,
|
OverrideDir: overrideDir,
|
||||||
DebugMode: debugMode,
|
DebugMode: debugMode,
|
||||||
|
@ -297,7 +300,7 @@ func setContentTypeIfMissing(w http.ResponseWriter, contentType string) {
|
||||||
// handleDebugStats displays debug statistics
|
// handleDebugStats displays debug statistics
|
||||||
func (s *Server) handleDebugStats(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleDebugStats(w http.ResponseWriter, r *http.Request) {
|
||||||
// Collect system stats
|
// Collect system stats
|
||||||
stats := utils.CollectSystemStats()
|
stats := utils.CollectSystemStats(s.config)
|
||||||
|
|
||||||
// Add component stats
|
// Add component stats
|
||||||
routeCount, bytecodeBytes := s.luaRouter.GetRouteStats()
|
routeCount, bytecodeBytes := s.luaRouter.GetRouteStats()
|
||||||
|
|
11
core/metadata/metadata.go
Normal file
11
core/metadata/metadata.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package metadata
|
||||||
|
|
||||||
|
// Version holds the current Moonshark version
|
||||||
|
const Version = "0.1"
|
||||||
|
|
||||||
|
// Build time information
|
||||||
|
var (
|
||||||
|
BuildTime = "unknown"
|
||||||
|
GitCommit = "unknown"
|
||||||
|
GoVersion = "unknown"
|
||||||
|
)
|
|
@ -6,6 +6,9 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.sharkk.net/Sky/Moonshark/core/config"
|
||||||
|
"git.sharkk.net/Sky/Moonshark/core/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ComponentStats holds stats from various system components
|
// ComponentStats holds stats from various system components
|
||||||
|
@ -22,10 +25,12 @@ type SystemStats struct {
|
||||||
GoRoutines int
|
GoRoutines int
|
||||||
Memory runtime.MemStats
|
Memory runtime.MemStats
|
||||||
Components ComponentStats
|
Components ComponentStats
|
||||||
|
Version string
|
||||||
|
Config *config.Config // Configuration information
|
||||||
}
|
}
|
||||||
|
|
||||||
// CollectSystemStats gathers basic system statistics
|
// CollectSystemStats gathers basic system statistics
|
||||||
func CollectSystemStats() SystemStats {
|
func CollectSystemStats(cfg *config.Config) SystemStats {
|
||||||
var stats SystemStats
|
var stats SystemStats
|
||||||
var mem runtime.MemStats
|
var mem runtime.MemStats
|
||||||
|
|
||||||
|
@ -33,6 +38,8 @@ func CollectSystemStats() SystemStats {
|
||||||
stats.Timestamp = time.Now()
|
stats.Timestamp = time.Now()
|
||||||
stats.GoVersion = runtime.Version()
|
stats.GoVersion = runtime.Version()
|
||||||
stats.GoRoutines = runtime.NumGoroutine()
|
stats.GoRoutines = runtime.NumGoroutine()
|
||||||
|
stats.Version = metadata.Version
|
||||||
|
stats.Config = cfg
|
||||||
|
|
||||||
// Collect memory stats
|
// Collect memory stats
|
||||||
runtime.ReadMemStats(&mem)
|
runtime.ReadMemStats(&mem)
|
||||||
|
@ -62,8 +69,8 @@ h1 {
|
||||||
box-shadow: 0 2px 4px 0px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 2px 4px 0px rgba(0, 0, 0, 0.2);
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
h2 { margin-top: 25px; }
|
h2 { margin-top: 0; margin-bottom: 0.5rem; }
|
||||||
table { width: 100%; border-collapse: collapse; margin: 15px 0; }
|
table { width: 100%; border-collapse: collapse; }
|
||||||
th { width: 1%; white-space: nowrap; border-right: 1px solid rgba(0, 0, 0, 0.1); }
|
th { width: 1%; white-space: nowrap; border-right: 1px solid rgba(0, 0, 0, 0.1); }
|
||||||
th, td { text-align: left; padding: 0.75rem 0.5rem; border-bottom: 1px solid #ddd; }
|
th, td { text-align: left; padding: 0.75rem 0.5rem; border-bottom: 1px solid #ddd; }
|
||||||
tr:last-child th, tr:last-child td { border-bottom: none; }
|
tr:last-child th, tr:last-child td { border-bottom: none; }
|
||||||
|
@ -72,10 +79,10 @@ table tr:nth-child(even), tbody tr:nth-child(even) { background-color: rgba(0, 0
|
||||||
background: #F2F2F2;
|
background: #F2F2F2;
|
||||||
color: #333;
|
color: #333;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 1rem;
|
||||||
box-shadow: 0 2px 4px 0px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 2px 4px 0px rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
.timestamp { color: #999; font-size: 0.9em; }
|
.timestamp { color: #999; font-size: 0.9em; margin-bottom: 1rem; }
|
||||||
.section { margin-bottom: 30px; }
|
.section { margin-bottom: 30px; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
@ -83,6 +90,15 @@ table tr:nth-child(even), tbody tr:nth-child(even) { background-color: rgba(0, 0
|
||||||
<h1>Moonshark</h1>
|
<h1>Moonshark</h1>
|
||||||
<div class="timestamp">Generated at: {{.Timestamp.Format "2006-01-02 15:04:05"}}</div>
|
<div class="timestamp">Generated at: {{.Timestamp.Format "2006-01-02 15:04:05"}}</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<h2>Server</h2>
|
||||||
|
<div class="card">
|
||||||
|
<table>
|
||||||
|
<tr><th>Version</th><td>{{.Version}}</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h2>System</h2>
|
<h2>System</h2>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
@ -106,15 +122,36 @@ table tr:nth-child(even), tbody tr:nth-child(even) { background-color: rgba(0, 0
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h2>Lua Engine</h2>
|
<h2>LuaRunner</h2>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<table>
|
<table>
|
||||||
|
<tr><th>Interpreter</th><td>LuaJIT 2.1 (Lua 5.1)</td></tr>
|
||||||
<tr><th>Active Routes</th><td>{{.Components.RouteCount}}</td></tr>
|
<tr><th>Active Routes</th><td>{{.Components.RouteCount}}</td></tr>
|
||||||
<tr><th>Bytecode Size</th><td>{{ByteCount .Components.BytecodeBytes}}</td></tr>
|
<tr><th>Bytecode Size</th><td>{{ByteCount .Components.BytecodeBytes}}</td></tr>
|
||||||
<tr><th>Loaded Modules</th><td>{{.Components.ModuleCount}}</td></tr>
|
<tr><th>Loaded Modules</th><td>{{.Components.ModuleCount}}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<h2>Config</h2>
|
||||||
|
<div class="card">
|
||||||
|
<table>
|
||||||
|
<tr><th>Port</th><td>{{.Config.Port}}</td></tr>
|
||||||
|
<tr><th>Debug Mode</th><td>{{.Config.Debug}}</td></tr>
|
||||||
|
<tr><th>Log Level</th><td>{{.Config.LogLevel}}</td></tr>
|
||||||
|
<tr><th>Routes Directory</th><td>{{.Config.RoutesDir}}</td></tr>
|
||||||
|
<tr><th>Static Directory</th><td>{{.Config.StaticDir}}</td></tr>
|
||||||
|
<tr><th>Override Directory</th><td>{{.Config.OverrideDir}}</td></tr>
|
||||||
|
<tr><th>Buffer Size</th><td>{{.Config.BufferSize}}</td></tr>
|
||||||
|
<tr><th>HTTP Logging</th><td>{{.Config.HTTPLoggingEnabled}}</td></tr>
|
||||||
|
<tr><th>Lib Directories</th><td>{{range .Config.LibDirs}}{{.}}<br>{{end}}</td></tr>
|
||||||
|
<tr><th>Watch Routes</th><td>{{index .Config.Watchers "routes"}}</td></tr>
|
||||||
|
<tr><th>Watch Static</th><td>{{index .Config.Watchers "static"}}</td></tr>
|
||||||
|
<tr><th>Watch Modules</th><td>{{index .Config.Watchers "modules"}}</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`
|
`
|
||||||
|
|
|
@ -237,7 +237,7 @@ func main() {
|
||||||
debugMode := cfg.GetBool("debug", false)
|
debugMode := cfg.GetBool("debug", false)
|
||||||
|
|
||||||
// Create HTTP server
|
// Create HTTP server
|
||||||
server := http.New(luaRouter, staticRouter, luaRunner, log, httpLoggingEnabled, debugMode, overrideDir)
|
server := http.New(luaRouter, staticRouter, luaRunner, log, httpLoggingEnabled, debugMode, overrideDir, cfg)
|
||||||
|
|
||||||
// Handle graceful shutdown
|
// Handle graceful shutdown
|
||||||
stop := make(chan os.Signal, 1)
|
stop := make(chan os.Signal, 1)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user