package runner import ( "fmt" "strings" "sync" luajit "git.sharkk.net/Sky/LuaJIT-to-Go" "git.sharkk.net/Sky/Moonshark/core/logger" ) // CoreModuleRegistry manages the initialization and reloading of core modules type CoreModuleRegistry struct { modules map[string]StateInitFunc 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("[CoreModuleRegistry] "+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 found := false for _, n := range r.initOrder { if n == name { found = true break } } if !found { 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 found := false for _, n := range r.initOrder { if n == name { found = true break } } if !found { r.initOrder = append(r.initOrder, name) } r.debugLog("Registered module %s with dependencies: %v", name, dependencies) } // SetInitOrder sets explicit initialization order func (r *CoreModuleRegistry) SetInitOrder(order []string) { r.mu.Lock() defer r.mu.Unlock() // First add all known modules that are in the specified order for _, name := range order { if _, exists := r.modules[name]; exists { r.initOrder = append(r.initOrder, name) } } // Then add any modules not in the specified order for name := range r.modules { found := false for _, n := range r.initOrder { if n == name { found = true break } } if !found { r.initOrder = append(r.initOrder, name) } } r.debugLog("Set initialization order: %v", r.initOrder) } // Initialize initializes all registered modules func (r *CoreModuleRegistry) Initialize(state *luajit.State) error { r.mu.RLock() defer r.mu.RUnlock() r.debugLog("Initializing all modules...") // 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{}); err != nil { return err } } r.debugLog("All modules initialized successfully") return nil } // initializeModule initializes a module and its dependencies func (r *CoreModuleRegistry) initializeModule(state *luajit.State, name string, initStack []string) 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] for _, dep := range deps { newStack := append(initStack, name) if err := r.initializeModule(state, dep, newStack); err != nil { return err } } // Initialize this module r.debugLog("Initializing module: %s", name) if err := initFunc(state); err != nil { r.debugLog("Failed to initialize module %s: %v", name, err) return fmt.Errorf("failed to initialize module %s: %w", name, err) } // Mark as initialized r.initializedFlag[name] = true r.debugLog("Module %s initialized successfully", 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 return r.initializeModule(state, name, []string{}) } // 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 // Register modules GlobalRegistry.Register("go", GoModuleInitFunc()) // Register HTTP module (no dependencies) GlobalRegistry.Register("http", HTTPModuleInitFunc()) // Register cookie module (depends on http) GlobalRegistry.RegisterWithDependencies("cookie", CookieModuleInitFunc(), []string{"http"}) // Register CSRF module (depends on go) GlobalRegistry.RegisterWithDependencies("csrf", CSRFModuleInitFunc(), []string{"go"}) // Set explicit initialization order GlobalRegistry.SetInitOrder([]string{ "go", // First: core utilities "http", // Second: HTTP functionality "cookie", // Third: Cookie functionality (uses HTTP) "csrf", // Fourth: CSRF protection (uses go and possibly session) }) logger.Debug("[CoreModuleRegistry] Core modules registered in init()") } // 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) }