package runner import ( "Moonshark/core/runner/sandbox" "Moonshark/core/utils/logger" "fmt" "strings" "sync" luajit "git.sharkk.net/Sky/LuaJIT-to-Go" ) // StateInitFunc is a function that initializes a module in a Lua state type StateInitFunc func(*luajit.State) error // CoreModuleRegistry manages the initialization and reloading of core modules type CoreModuleRegistry struct { modules map[string]StateInitFunc // Module initializers initOrder []string // Explicit initialization order dependencies map[string][]string // Module dependencies initializedFlag map[string]bool // Track which modules are initialized mu sync.RWMutex debug bool } // NewCoreModuleRegistry creates a new core module registry func NewCoreModuleRegistry() *CoreModuleRegistry { return &CoreModuleRegistry{ modules: make(map[string]StateInitFunc), initOrder: []string{}, dependencies: make(map[string][]string), initializedFlag: make(map[string]bool), debug: false, } } // EnableDebug turns on debug logging func (r *CoreModuleRegistry) EnableDebug() { r.debug = true } // debugLog prints debug messages if enabled func (r *CoreModuleRegistry) debugLog(format string, args ...interface{}) { if r.debug { logger.Debug("CoreRegistry "+format, args...) } } // debugLogCont prints continuation debug messages if enabled func (r *CoreModuleRegistry) debugLogCont(format string, args ...interface{}) { if r.debug { logger.DebugCont(format, args...) } } // Register adds a module to the registry func (r *CoreModuleRegistry) Register(name string, initFunc StateInitFunc) { r.mu.Lock() defer r.mu.Unlock() r.modules[name] = initFunc // Add to initialization order if not already there for _, n := range r.initOrder { if n == name { return // Already registered, silently continue } } r.initOrder = append(r.initOrder, name) r.debugLog("registered module %s", name) } // RegisterWithDependencies registers a module with explicit dependencies func (r *CoreModuleRegistry) RegisterWithDependencies(name string, initFunc StateInitFunc, dependencies []string) { r.mu.Lock() defer r.mu.Unlock() r.modules[name] = initFunc r.dependencies[name] = dependencies // Add to initialization order if not already there for _, n := range r.initOrder { if n == name { return // Already registered, silently continue } } r.initOrder = append(r.initOrder, name) r.debugLog("registered module %s", name) if len(dependencies) > 0 { r.debugLogCont("Dependencies: %v", dependencies) } } // SetInitOrder sets explicit initialization order func (r *CoreModuleRegistry) SetInitOrder(order []string) { r.mu.Lock() defer r.mu.Unlock() // Create new init order newOrder := make([]string, 0, len(order)) // First add all known modules that are in the specified order for _, name := range order { if _, exists := r.modules[name]; exists { // Check for duplicates isDuplicate := false for _, existing := range newOrder { if existing == name { isDuplicate = true break } } if !isDuplicate { newOrder = append(newOrder, name) } } } // Then add any modules not in the specified order for name := range r.modules { // Check if module already in the new order found := false for _, n := range newOrder { if n == name { found = true break } } if !found { newOrder = append(newOrder, name) } } r.initOrder = newOrder r.debugLog("Set initialization order: %v", r.initOrder) } // Initialize initializes all registered modules func (r *CoreModuleRegistry) Initialize(state *luajit.State, stateIndex int) error { r.mu.RLock() defer r.mu.RUnlock() verbose := stateIndex == 0 if verbose { r.debugLog("initializing %d modules...", len(r.initOrder)) } // Clear initialization flags r.initializedFlag = make(map[string]bool) // Initialize modules in order, respecting dependencies for _, name := range r.initOrder { if err := r.initializeModule(state, name, []string{}, verbose); err != nil { return err } } if verbose { r.debugLogCont("All modules initialized successfully") } return nil } // initializeModule initializes a module and its dependencies func (r *CoreModuleRegistry) initializeModule(state *luajit.State, name string, initStack []string, verbose bool) error { // Check if already initialized if r.initializedFlag[name] { return nil } // Check for circular dependencies for _, n := range initStack { if n == name { return fmt.Errorf("circular dependency detected: %s -> %s", strings.Join(initStack, " -> "), name) } } // Get init function initFunc, ok := r.modules[name] if !ok { return fmt.Errorf("module not found: %s", name) } // Initialize dependencies first deps := r.dependencies[name] if len(deps) > 0 { newStack := append(initStack, name) for _, dep := range deps { if err := r.initializeModule(state, dep, newStack, verbose); err != nil { return err } } } err := initFunc(state) if err != nil { // Always log failures regardless of verbose setting r.debugLogCont("Initializing module %s... failure: %v", name, err) return fmt.Errorf("failed to initialize module %s: %w", name, err) } r.initializedFlag[name] = true if verbose { r.debugLogCont("Initializing module %s... success", name) } return nil } // InitializeModule initializes a specific module func (r *CoreModuleRegistry) InitializeModule(state *luajit.State, name string) error { r.mu.RLock() defer r.mu.RUnlock() // Clear initialization flag for this module r.initializedFlag[name] = false // Always use verbose logging for explicit module initialization return r.initializeModule(state, name, []string{}, true) } // ModuleNames returns a list of all registered module names func (r *CoreModuleRegistry) ModuleNames() []string { r.mu.RLock() defer r.mu.RUnlock() names := make([]string, 0, len(r.modules)) for name := range r.modules { names = append(names, name) } return names } // MatchModuleName checks if a file path corresponds to a registered module func (r *CoreModuleRegistry) MatchModuleName(modName string) (string, bool) { r.mu.RLock() defer r.mu.RUnlock() // Exact match if _, ok := r.modules[modName]; ok { return modName, true } // Check if the module name ends with a registered module for name := range r.modules { if strings.HasSuffix(modName, "."+name) { return name, true } } return "", false } // Global registry instance var GlobalRegistry = NewCoreModuleRegistry() // Initialize global registry with core modules func init() { GlobalRegistry.EnableDebug() // Enable debugging by default logger.Debug("[ModuleRegistry] Registering core modules...") // Register core modules - these now point to the sandbox implementations GlobalRegistry.Register("util", func(state *luajit.State) error { return sandbox.UtilModuleInitFunc()(state) }) GlobalRegistry.Register("http", func(state *luajit.State) error { return sandbox.HTTPModuleInitFunc()(state) }) // Set explicit initialization order GlobalRegistry.SetInitOrder([]string{ "util", // First: core utilities "http", // Second: HTTP functionality "session", // Third: Session functionality "csrf", // Fourth: CSRF protection }) logger.DebugCont("Core modules registered successfully") } // RegisterCoreModule is a helper to register a core module with the global registry func RegisterCoreModule(name string, initFunc StateInitFunc) { GlobalRegistry.Register(name, initFunc) } // RegisterCoreModuleWithDependencies registers a module with dependencies func RegisterCoreModuleWithDependencies(name string, initFunc StateInitFunc, dependencies []string) { GlobalRegistry.RegisterWithDependencies(name, initFunc, dependencies) }