298 lines
7.7 KiB
Go
298 lines
7.7 KiB
Go
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)
|
|
}
|