169 lines
3.6 KiB
Go
169 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"syscall"
|
|
"time"
|
|
|
|
"Moonshark/modules/http"
|
|
"Moonshark/modules/sql"
|
|
"Moonshark/state"
|
|
)
|
|
|
|
var (
|
|
watchFlag = flag.Bool("watch", false, "Watch script files for changes and restart")
|
|
wFlag = flag.Bool("w", false, "Watch script files for changes and restart")
|
|
)
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
if flag.NArg() < 1 {
|
|
fmt.Fprintf(os.Stderr, "Usage: %s [--watch|-w] <script.lua>\n", filepath.Base(os.Args[0]))
|
|
os.Exit(1)
|
|
}
|
|
|
|
scriptPath := flag.Arg(0)
|
|
watchMode := *watchFlag || *wFlag
|
|
|
|
if watchMode {
|
|
runWithWatcher(scriptPath)
|
|
} else {
|
|
runOnce(scriptPath)
|
|
}
|
|
}
|
|
|
|
func runOnce(scriptPath string) {
|
|
luaState, err := state.NewFromScript(scriptPath)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
defer luaState.Close()
|
|
|
|
if err := luaState.ExecuteFile(scriptPath); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if http.HasActiveServers() {
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
fmt.Println("HTTP servers running. Press Ctrl+C to exit.")
|
|
|
|
go func() {
|
|
<-sigChan
|
|
fmt.Println("\nShutting down...")
|
|
|
|
// Close main state first (saves KV stores)
|
|
luaState.Close()
|
|
// Then stop servers (closes worker states)
|
|
http.StopAllServers()
|
|
sql.CloseAllConnections()
|
|
os.Exit(0)
|
|
}()
|
|
|
|
http.WaitForServers()
|
|
}
|
|
}
|
|
|
|
func runWithWatcher(scriptPath string) {
|
|
watcher, err := NewFileWatcher(500) // 500ms debounce
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to create file watcher: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
defer watcher.Close()
|
|
|
|
if err := watcher.DiscoverRequiredFiles(scriptPath); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to watch files: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
restartCh := watcher.Start()
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
fmt.Printf("Starting %s in watch mode...\n", scriptPath)
|
|
|
|
var hadError bool
|
|
firstRun := true
|
|
|
|
for {
|
|
// If we had an error on the last run and this isn't the first run,
|
|
// wait for file changes before retrying
|
|
if hadError && !firstRun {
|
|
fmt.Println("Waiting for file changes before retrying...")
|
|
select {
|
|
case <-restartCh:
|
|
fmt.Println("Files changed, retrying...")
|
|
case <-sigChan:
|
|
fmt.Println("\nExiting...")
|
|
return
|
|
}
|
|
}
|
|
|
|
firstRun = false
|
|
hadError = false
|
|
|
|
// Clear cache before each run
|
|
state.ClearCache()
|
|
|
|
// Create and run state
|
|
luaState, err := state.NewFromScript(scriptPath)
|
|
if err != nil {
|
|
log.Printf("Error creating state: %v", err)
|
|
hadError = true
|
|
continue
|
|
}
|
|
|
|
if err := luaState.ExecuteFile(scriptPath); err != nil {
|
|
log.Printf("Execution error: %v", err)
|
|
luaState.Close()
|
|
hadError = true
|
|
continue
|
|
}
|
|
|
|
// If not a long-running process, wait for changes and restart
|
|
if !http.HasActiveServers() {
|
|
fmt.Println("Script completed. Waiting for changes...")
|
|
luaState.Close()
|
|
|
|
select {
|
|
case <-restartCh:
|
|
fmt.Println("Files changed, restarting...")
|
|
continue
|
|
case <-sigChan:
|
|
fmt.Println("\nExiting...")
|
|
return
|
|
}
|
|
}
|
|
|
|
// Long-running process - wait for restart signal or exit signal
|
|
fmt.Println("HTTP servers running. Watching for file changes...")
|
|
|
|
select {
|
|
case <-restartCh:
|
|
fmt.Println("Files changed, restarting...")
|
|
http.StopAllServers()
|
|
luaState.Close()
|
|
sql.CloseAllConnections()
|
|
time.Sleep(100 * time.Millisecond) // Brief pause for cleanup
|
|
continue
|
|
|
|
case <-sigChan:
|
|
fmt.Println("\nShutting down...")
|
|
http.StopAllServers()
|
|
luaState.Close()
|
|
sql.CloseAllConnections()
|
|
return
|
|
}
|
|
}
|
|
}
|