283 lines
7.6 KiB
Go
283 lines
7.6 KiB
Go
package core
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"Moonshark/core/config"
|
|
"Moonshark/core/http"
|
|
"Moonshark/core/logger"
|
|
"Moonshark/core/routers"
|
|
"Moonshark/core/runner"
|
|
"Moonshark/core/sessions"
|
|
"Moonshark/core/utils"
|
|
"Moonshark/core/watchers"
|
|
)
|
|
|
|
// Moonshark represents the server and all its dependencies
|
|
type Moonshark struct {
|
|
Config *config.Config
|
|
LuaRouter *routers.LuaRouter
|
|
StaticRouter *routers.StaticRouter
|
|
LuaRunner *runner.Runner
|
|
HTTPServer *http.Server
|
|
|
|
// Clean-up functions for watchers
|
|
cleanupFuncs []func() error
|
|
}
|
|
|
|
// NewMoonshark creates a new Moonshark server instance
|
|
func NewMoonshark(configPath string) (*Moonshark, error) {
|
|
// Initialize server struct
|
|
server := &Moonshark{}
|
|
|
|
// Load configuration
|
|
if err := server.loadConfig(configPath); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Configure logging
|
|
server.setupLogging()
|
|
|
|
// Initialize routers
|
|
if err := server.initRouters(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Initialize Lua runner
|
|
if err := server.initRunner(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Set up file watchers
|
|
if err := server.setupWatchers(); err != nil {
|
|
logger.Warning("Error setting up watchers: %v", err)
|
|
}
|
|
|
|
// Create HTTP server
|
|
server.HTTPServer = http.New(
|
|
server.LuaRouter,
|
|
server.StaticRouter,
|
|
server.LuaRunner,
|
|
server.Config.HTTPLoggingEnabled,
|
|
server.Config.Debug,
|
|
server.Config.OverrideDir,
|
|
server.Config,
|
|
)
|
|
|
|
return server, nil
|
|
}
|
|
|
|
// loadConfig loads the configuration file
|
|
func (s *Moonshark) loadConfig(configPath string) error {
|
|
var err error
|
|
|
|
// Load configuration from file
|
|
s.Config, err = config.Load(configPath)
|
|
if err != nil {
|
|
logger.Warning("Wipeout! Couldn't load config file: %v", err)
|
|
logger.WarningCont("Rolling with the default setup")
|
|
s.Config = config.New()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// setupLogging configures the logger based on config settings
|
|
func (s *Moonshark) setupLogging() {
|
|
// Set log level from config
|
|
switch s.Config.LogLevel {
|
|
case "warn":
|
|
logger.SetLevel(logger.LevelWarning)
|
|
case "error":
|
|
logger.SetLevel(logger.LevelError)
|
|
case "server":
|
|
logger.SetLevel(logger.LevelServer)
|
|
case "fatal":
|
|
logger.SetLevel(logger.LevelFatal)
|
|
default:
|
|
logger.SetLevel(logger.LevelInfo)
|
|
}
|
|
|
|
// Set debug mode if configured
|
|
if s.Config.Debug {
|
|
logger.EnableDebug() // Force debug logs regardless of level
|
|
logger.Debug("Debug mode is ready to party, bro")
|
|
}
|
|
}
|
|
|
|
// initRouters initializes the Lua and static routers
|
|
func (s *Moonshark) initRouters() error {
|
|
// Ensure directories exist
|
|
if err := utils.EnsureDir(s.Config.RoutesDir); err != nil {
|
|
return fmt.Errorf("routes directory doesn't exist and could not be created: %v", err)
|
|
}
|
|
|
|
if err := utils.EnsureDir(s.Config.StaticDir); err != nil {
|
|
return fmt.Errorf("static directory doesn't exist and could not be created: %v", err)
|
|
}
|
|
|
|
// Initialize Lua router for dynamic routes
|
|
var err error
|
|
s.LuaRouter, err = routers.NewLuaRouter(s.Config.RoutesDir)
|
|
if err != nil {
|
|
// Check if this is a compilation warning or a more serious error
|
|
if errors.Is(err, routers.ErrRoutesCompilationErrors) {
|
|
// Some routes failed to compile, but router is still usable
|
|
logger.Warning("Some Lua routes failed to compile. Check logs for details.")
|
|
|
|
// Log details about each failed route
|
|
if failedRoutes := s.LuaRouter.ReportFailedRoutes(); len(failedRoutes) > 0 {
|
|
for _, re := range failedRoutes {
|
|
logger.Error("Route %s %s failed to compile: %v", re.Method, re.Path, re.Err)
|
|
}
|
|
}
|
|
} else {
|
|
// More serious error that prevents router initialization
|
|
return fmt.Errorf("failed to initialize Lua router: %v", err)
|
|
}
|
|
}
|
|
logger.Info("Lua router is stoked and riding routes from %s", s.Config.RoutesDir)
|
|
|
|
// Initialize static file router
|
|
s.StaticRouter, err = routers.NewStaticRouter(s.Config.StaticDir)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to initialize static router: %v", err)
|
|
}
|
|
logger.Info("Static router catching waves with files from %s", s.Config.StaticDir)
|
|
s.StaticRouter.EnableDebugLog()
|
|
|
|
return nil
|
|
}
|
|
|
|
// initRunner initializes the Lua runner
|
|
func (s *Moonshark) initRunner() error {
|
|
// Ensure override directory exists
|
|
if err := utils.EnsureDir(s.Config.OverrideDir); err != nil {
|
|
logger.Warning("Override directory doesn't exist and could not be created: %v", err)
|
|
s.Config.OverrideDir = "" // Disable overrides if directory can't be created
|
|
}
|
|
|
|
// Ensure lib directories exist
|
|
for _, dir := range s.Config.LibDirs {
|
|
if err := utils.EnsureDir(dir); err != nil {
|
|
logger.Warning("Lib directory doesn't exist and could not be created: %v", err)
|
|
}
|
|
}
|
|
|
|
// Initialize session manager
|
|
sessionManager := sessions.GlobalSessionManager
|
|
|
|
// Configure session cookies
|
|
sessionManager.SetCookieOptions(
|
|
"MSSESSID", // name
|
|
"/", // path
|
|
"", // domain
|
|
false, // secure
|
|
true, // httpOnly
|
|
86400, // maxAge (1 day)
|
|
)
|
|
|
|
// Set up runner options
|
|
runnerOpts := []runner.RunnerOption{
|
|
runner.WithPoolSize(s.Config.PoolSize),
|
|
runner.WithLibDirs(s.Config.LibDirs...),
|
|
runner.WithSessionManager(sessionManager),
|
|
runner.WithCSRFProtection(),
|
|
}
|
|
|
|
// Add debug option conditionally
|
|
if s.Config.Debug {
|
|
runnerOpts = append(runnerOpts, runner.WithDebugEnabled())
|
|
logger.Debug("Debug logging enabled for Lua runner")
|
|
}
|
|
|
|
// Initialize the runner
|
|
var err error
|
|
s.LuaRunner, err = runner.NewRunner(runnerOpts...)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to initialize Lua runner: %v", err)
|
|
}
|
|
|
|
logger.Server("Lua runner waxing up with a pool size of %d", s.Config.PoolSize)
|
|
return nil
|
|
}
|
|
|
|
// setupWatchers initializes and starts all configured file watchers
|
|
func (s *Moonshark) setupWatchers() error {
|
|
// Set up watcher for Lua routes
|
|
if s.Config.Watchers.Routes {
|
|
luaRouterWatcher, err := watchers.WatchLuaRouter(s.LuaRouter, s.LuaRunner, s.Config.RoutesDir)
|
|
if err != nil {
|
|
logger.Warning("Failed to watch routes directory: %v", err)
|
|
} else {
|
|
s.cleanupFuncs = append(s.cleanupFuncs, luaRouterWatcher.Close)
|
|
}
|
|
}
|
|
|
|
// Set up watchers for Lua modules libraries
|
|
if s.Config.Watchers.Modules && len(s.Config.LibDirs) > 0 {
|
|
moduleWatchers, err := watchers.WatchLuaModules(s.LuaRunner, s.Config.LibDirs)
|
|
if err != nil {
|
|
logger.Warning("Failed to watch Lua module directories: %v", err)
|
|
} else {
|
|
for _, watcher := range moduleWatchers {
|
|
w := watcher // Capture variable for closure
|
|
s.cleanupFuncs = append(s.cleanupFuncs, w.Close)
|
|
}
|
|
logger.Info("File watchers active for %d Lua module directories", len(moduleWatchers))
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Start starts the HTTP server
|
|
func (s *Moonshark) Start() error {
|
|
logger.Server("Surf's up on port %d!", s.Config.Port)
|
|
|
|
// Log HTTP logging status
|
|
if s.Config.HTTPLoggingEnabled {
|
|
logger.ServerCont("HTTP logging is turned on - watch those waves")
|
|
} else {
|
|
logger.ServerCont("HTTP logging is turned off - waves are flat bro")
|
|
}
|
|
|
|
// Start the server in a non-blocking way
|
|
go func() {
|
|
if err := s.HTTPServer.ListenAndServe(fmt.Sprintf(":%d", s.Config.Port)); err != nil {
|
|
if err.Error() != "http: Server closed" {
|
|
logger.Error("Server error: %v", err)
|
|
}
|
|
}
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
// Shutdown gracefully shuts down the server
|
|
func (s *Moonshark) Shutdown() error {
|
|
logger.Server("Shutting down server...")
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
if err := s.HTTPServer.Shutdown(ctx); err != nil {
|
|
logger.Error("Server shutdown error: %v", err)
|
|
return err
|
|
}
|
|
|
|
for _, cleanup := range s.cleanupFuncs {
|
|
if err := cleanup(); err != nil {
|
|
logger.Warning("Cleanup error: %v", err)
|
|
}
|
|
}
|
|
|
|
s.LuaRunner.Close()
|
|
|
|
logger.ServerCont("Server stopped")
|
|
return nil
|
|
}
|