config rewrite
This commit is contained in:
parent
3f86c31c9f
commit
ac646bbad8
3
go.mod
3
go.mod
@ -4,6 +4,7 @@ go 1.24.1
|
||||
|
||||
require (
|
||||
git.sharkk.net/Go/LRU v1.0.0
|
||||
git.sharkk.net/Sharkk/Fin v1.2.0
|
||||
git.sharkk.net/Sky/LuaJIT-to-Go v0.4.1
|
||||
github.com/VictoriaMetrics/fastcache v1.12.4
|
||||
github.com/alexedwards/argon2id v1.0.0
|
||||
@ -26,7 +27,7 @@ require (
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
golang.org/x/crypto v0.38.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
|
||||
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
modernc.org/libc v1.65.8 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
|
6
go.sum
6
go.sum
@ -1,5 +1,7 @@
|
||||
git.sharkk.net/Go/LRU v1.0.0 h1:/KqdRVhHldi23aVfQZ4ss6vhCWZqA3vFiQyf1MJPpQc=
|
||||
git.sharkk.net/Go/LRU v1.0.0/go.mod h1:8tdTyl85mss9a+KKwo+Wj9gKHOizhfLfpJhz1ltYz50=
|
||||
git.sharkk.net/Sharkk/Fin v1.2.0 h1:axhme8vHRYoaB3us7PNfXzXxKOxhpS5BMuNpN8ESe6U=
|
||||
git.sharkk.net/Sharkk/Fin v1.2.0/go.mod h1:ca0Ej9yCM/vHh1o3YMvBZspme3EtbwoEL2UXN5UPXMo=
|
||||
git.sharkk.net/Sky/LuaJIT-to-Go v0.4.1 h1:CAYt+C6Vgo4JxK876j0ApQ2GDFFvy9FKO0OoZBVD18k=
|
||||
git.sharkk.net/Sky/LuaJIT-to-Go v0.4.1/go.mod h1:HQz+D7AFxOfNbTIogjxP+shEBtz1KKrLlLucU+w07c8=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.4 h1:2xvmwZBW+9QtHsXggfzAZRs1FZWCsBs8QDg22bMidf0=
|
||||
@ -52,8 +54,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
|
||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
|
||||
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b h1:QoALfVG9rhQ/M7vYDScfPdWjGL9dlsVVM5VGh7aKoAA=
|
||||
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
|
@ -3,6 +3,7 @@ package http
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -32,14 +33,12 @@ type Server struct {
|
||||
staticFS *fasthttp.FS
|
||||
luaRunner *runner.Runner
|
||||
fasthttpServer *fasthttp.Server
|
||||
loggingEnabled bool
|
||||
debugMode bool
|
||||
config *config.Config
|
||||
cfg *config.Config
|
||||
sessionManager *sessions.SessionManager
|
||||
errorConfig utils.ErrorPageConfig
|
||||
ctxPool sync.Pool
|
||||
paramsPool sync.Pool
|
||||
staticDir string
|
||||
staticPrefix string
|
||||
staticPrefixBytes []byte
|
||||
|
||||
@ -49,34 +48,25 @@ type Server struct {
|
||||
errorCacheMu sync.RWMutex
|
||||
}
|
||||
|
||||
func New(luaRouter *router.LuaRouter, staticDir string,
|
||||
runner *runner.Runner, loggingEnabled bool, debugMode bool,
|
||||
overrideDir string, config *config.Config) *Server {
|
||||
|
||||
staticPrefix := config.Server.StaticPrefix
|
||||
if staticPrefix == "" {
|
||||
staticPrefix = "/static/"
|
||||
}
|
||||
|
||||
if staticPrefix[0] != '/' {
|
||||
func New(luaRouter *router.LuaRouter, runner *runner.Runner, cfg *config.Config, debugMode bool) *Server {
|
||||
staticPrefix := cfg.Server.StaticPrefix
|
||||
if !strings.HasPrefix(staticPrefix, "/") {
|
||||
staticPrefix = "/" + staticPrefix
|
||||
}
|
||||
if staticPrefix[len(staticPrefix)-1] != '/' {
|
||||
if !strings.HasSuffix(staticPrefix, "/") {
|
||||
staticPrefix = staticPrefix + "/"
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
luaRouter: luaRouter,
|
||||
luaRunner: runner,
|
||||
loggingEnabled: loggingEnabled,
|
||||
debugMode: debugMode,
|
||||
config: config,
|
||||
cfg: cfg,
|
||||
sessionManager: sessions.GlobalSessionManager,
|
||||
staticDir: staticDir,
|
||||
staticPrefix: staticPrefix,
|
||||
staticPrefixBytes: []byte(staticPrefix),
|
||||
errorConfig: utils.ErrorPageConfig{
|
||||
OverrideDir: overrideDir,
|
||||
OverrideDir: cfg.Dirs.Override,
|
||||
DebugMode: debugMode,
|
||||
},
|
||||
ctxPool: sync.Pool{
|
||||
@ -96,9 +86,9 @@ func New(luaRouter *router.LuaRouter, staticDir string,
|
||||
s.cached500 = []byte(utils.InternalErrorPage(s.errorConfig, "", "Internal Server Error"))
|
||||
|
||||
// Setup static file serving
|
||||
if staticDir != "" {
|
||||
if cfg.Dirs.Static != "" {
|
||||
s.staticFS = &fasthttp.FS{
|
||||
Root: staticDir,
|
||||
Root: cfg.Dirs.Static,
|
||||
IndexNames: []string{"index.html"},
|
||||
GenerateIndexPages: false,
|
||||
AcceptByteRange: true,
|
||||
@ -144,25 +134,22 @@ func (s *Server) handleRequest(ctx *fasthttp.RequestCtx) {
|
||||
methodBytes := ctx.Method()
|
||||
pathBytes := ctx.Path()
|
||||
|
||||
// Fast path for debug stats
|
||||
if s.debugMode && bytes.Equal(pathBytes, debugPath) {
|
||||
s.handleDebugStats(ctx)
|
||||
if s.loggingEnabled {
|
||||
if s.cfg.Server.HTTPLogging {
|
||||
logger.LogRequest(ctx.Response.StatusCode(), string(methodBytes), string(pathBytes), time.Since(start))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Fast path for static files
|
||||
if s.staticHandler != nil && bytes.HasPrefix(pathBytes, s.staticPrefixBytes) {
|
||||
s.staticHandler(ctx)
|
||||
if s.loggingEnabled {
|
||||
if s.cfg.Server.HTTPLogging {
|
||||
logger.LogRequest(ctx.Response.StatusCode(), string(methodBytes), string(pathBytes), time.Since(start))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Lua route lookup - only allocate params if found
|
||||
bytecode, scriptPath, routeErr, params, found := s.luaRouter.GetRouteInfo(methodBytes, pathBytes)
|
||||
|
||||
if found {
|
||||
@ -175,7 +162,7 @@ func (s *Server) handleRequest(ctx *fasthttp.RequestCtx) {
|
||||
s.send404(ctx, pathBytes)
|
||||
}
|
||||
|
||||
if s.loggingEnabled {
|
||||
if s.cfg.Server.HTTPLogging {
|
||||
logger.LogRequest(ctx.Response.StatusCode(), string(methodBytes), string(pathBytes), time.Since(start))
|
||||
}
|
||||
}
|
||||
@ -310,7 +297,7 @@ func (s *Server) sendError(ctx *fasthttp.RequestCtx, status int, pathBytes []byt
|
||||
}
|
||||
|
||||
func (s *Server) handleDebugStats(ctx *fasthttp.RequestCtx) {
|
||||
stats := utils.CollectSystemStats(s.config)
|
||||
stats := utils.CollectSystemStats(s.cfg)
|
||||
routeCount, bytecodeBytes := s.luaRouter.GetRouteStats()
|
||||
stats.Components = utils.ComponentStats{
|
||||
RouteCount: routeCount,
|
||||
|
39
main.go
39
main.go
@ -21,6 +21,8 @@ import (
|
||||
"Moonshark/utils/logger"
|
||||
"Moonshark/utils/metadata"
|
||||
"Moonshark/watchers"
|
||||
|
||||
fin "git.sharkk.net/Sharkk/Fin"
|
||||
)
|
||||
|
||||
// Moonshark represents the server and all its dependencies
|
||||
@ -34,7 +36,7 @@ type Moonshark struct {
|
||||
}
|
||||
|
||||
func main() {
|
||||
configPath := flag.String("config", "config.lua", "Path to configuration file")
|
||||
configPath := flag.String("config", "config", "Path to configuration file")
|
||||
debugFlag := flag.Bool("debug", false, "Enable debug mode")
|
||||
scriptPath := flag.String("script", "", "Path to Lua script to execute once")
|
||||
flag.Parse()
|
||||
@ -42,26 +44,20 @@ func main() {
|
||||
|
||||
color.SetColors(color.DetectShellColors())
|
||||
banner(scriptMode)
|
||||
cfg := config.New(readConfig(*configPath))
|
||||
|
||||
// Load config
|
||||
cfg, err := config.Load(*configPath)
|
||||
if err != nil {
|
||||
logger.Warning("Config load failed: %v, using defaults", color.Red(err.Error()))
|
||||
cfg = config.New()
|
||||
}
|
||||
|
||||
// Setup logging with debug mode
|
||||
if *debugFlag || cfg.Server.Debug {
|
||||
logger.EnableDebug()
|
||||
logger.Debug("Debug logging enabled")
|
||||
}
|
||||
|
||||
var moonshark *Moonshark
|
||||
var err error
|
||||
|
||||
if scriptMode {
|
||||
moonshark, err = initScriptMode(cfg)
|
||||
} else {
|
||||
moonshark, err = initServerMode(cfg, *debugFlag)
|
||||
moonshark, err = initServerMode(cfg, *debugFlag || cfg.Server.Debug)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -156,12 +152,9 @@ func initServerMode(cfg *config.Config, debug bool) (*Moonshark, error) {
|
||||
|
||||
moonshark.HTTPServer = http.New(
|
||||
moonshark.LuaRouter,
|
||||
staticDir,
|
||||
moonshark.LuaRunner,
|
||||
cfg.Server.HTTPLogging,
|
||||
cfg.Server.Debug,
|
||||
cfg.Dirs.Override,
|
||||
cfg,
|
||||
debug,
|
||||
)
|
||||
|
||||
// For development, disable caching. For production, enable it
|
||||
@ -387,3 +380,21 @@ func banner(scriptMode bool) {
|
||||
`
|
||||
fmt.Println(color.Blue(fmt.Sprintf(banner, metadata.Version)))
|
||||
}
|
||||
|
||||
// readConfig attempts to read config data from a Fin file
|
||||
func readConfig(path string) *fin.Data {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
logger.Error("Failed to open config file %s", color.Yellow(path))
|
||||
cfg, _ := fin.Load(nil)
|
||||
return cfg
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
cfg, err := fin.Load(file)
|
||||
if err != nil {
|
||||
logger.Warning("Config load failed: %v, using defaults", color.Red(err.Error()))
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
@ -24,8 +24,7 @@ const (
|
||||
|
||||
var useColors = true
|
||||
|
||||
// Color function. Makes a call to makeColorFunc with the associated
|
||||
// color code.
|
||||
// Color function; makes a call to makeColorFunc with the associated color code
|
||||
var (
|
||||
Reset = makeColorFunc(resetCode)
|
||||
Red = makeColorFunc(redCode)
|
||||
|
@ -1,16 +1,11 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
|
||||
fin "git.sharkk.net/Sharkk/Fin"
|
||||
)
|
||||
|
||||
// Config represents a configuration loaded from a Lua file
|
||||
type Config struct {
|
||||
// Server settings
|
||||
Server struct {
|
||||
@ -35,256 +30,29 @@ type Config struct {
|
||||
Libs []string
|
||||
}
|
||||
|
||||
// Raw values map for custom values
|
||||
values map[string]any
|
||||
// Raw fin data struct for custom data
|
||||
data *fin.Data
|
||||
}
|
||||
|
||||
// NewConfig creates a new configuration with default values
|
||||
func New() *Config {
|
||||
func New(data *fin.Data) *Config {
|
||||
config := &Config{
|
||||
// Initialize values map
|
||||
values: make(map[string]any),
|
||||
data: data,
|
||||
}
|
||||
|
||||
// Server defaults
|
||||
config.Server.Port = 3117
|
||||
config.Server.Debug = false
|
||||
config.Server.HTTPLogging = false
|
||||
config.Server.StaticPrefix = "static/"
|
||||
config.Server.Port = data.GetOr("server.port", 3117).(int)
|
||||
config.Server.Debug = data.GetOr("server.debug", false).(bool)
|
||||
config.Server.HTTPLogging = data.GetOr("server.http_logging", true).(bool)
|
||||
config.Server.StaticPrefix = data.GetOr("server.static_prefix", "public").(string)
|
||||
|
||||
// Runner defaults
|
||||
config.Runner.PoolSize = runtime.GOMAXPROCS(0)
|
||||
config.Runner.PoolSize = data.GetOr("runner.pool_size", runtime.GOMAXPROCS(0)).(int)
|
||||
|
||||
// Dirs defaults
|
||||
config.Dirs.Routes = "routes"
|
||||
config.Dirs.Static = "public"
|
||||
config.Dirs.FS = "fs"
|
||||
config.Dirs.Data = "data"
|
||||
config.Dirs.Override = "override"
|
||||
config.Dirs.Libs = []string{"libs"}
|
||||
config.Dirs.Routes = data.GetOr("dirs.routes", "routes").(string)
|
||||
config.Dirs.Static = data.GetOr("dirs.static", "public").(string)
|
||||
config.Dirs.FS = data.GetOr("dirs.fs", "fs").(string)
|
||||
config.Dirs.Data = data.GetOr("dirs.data", "data").(string)
|
||||
config.Dirs.Override = data.GetOr("dirs.override", "override").(string)
|
||||
config.Dirs.Libs = data.GetOr("dirs.libs", []string{"libs"}).([]string)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// 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 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[table] = tableMap
|
||||
}
|
||||
}
|
||||
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, 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["http_logging"].(bool); ok {
|
||||
config.Server.HTTPLogging = v
|
||||
}
|
||||
if v, ok := serverTable["static_prefix"].(string); ok {
|
||||
config.Server.StaticPrefix = v
|
||||
}
|
||||
}
|
||||
|
||||
// Apply runner settings
|
||||
if runnerTable, ok := values["runner"].(map[string]any); ok {
|
||||
if v, ok := runnerTable["pool_size"].(float64); ok && v != 0 {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// Key can be a dotted path like "server.port"
|
||||
func (c *Config) GetCustomValue(key string) any {
|
||||
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.GetCustomValue(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.GetCustomValue(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.GetCustomValue(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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user