mirror of
https://github.com/WiiLink24/wfc-server.git
synced 2026-03-21 17:44:58 -05:00
Main: Change backend reload system
This commit is contained in:
parent
c6927a3cb6
commit
b952c9e386
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -19,6 +19,7 @@ state
|
|||
|
||||
# Executables
|
||||
*.exe
|
||||
*.exe~
|
||||
|
||||
# Editor files
|
||||
.vscode
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ func ConnectFrontend() {
|
|||
var err error
|
||||
rpcFrontend, err = rpc.Dial("tcp", "localhost:29998")
|
||||
if err != nil {
|
||||
logging.Error("BACKEND", "Failed to connect to frontend:", err)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -47,3 +47,29 @@ func CloseConnection(server string, index uint64) error {
|
|||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Ready will notify the frontend that the backend is ready to accept connections
|
||||
func Ready() error {
|
||||
if rpcFrontend == nil {
|
||||
ConnectFrontend()
|
||||
}
|
||||
|
||||
err := rpcFrontend.Call("RPCFrontendPacket.Ready", struct{}{}, nil)
|
||||
if err != nil {
|
||||
logging.Error("COMMON", "Failed to notify frontend that backend is ready:", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Shutdown will notify the frontend that the backend is shutting down
|
||||
func Shutdown() error {
|
||||
if rpcFrontend == nil {
|
||||
ConnectFrontend()
|
||||
}
|
||||
|
||||
err := rpcFrontend.Call("RPCFrontendPacket.ShutdownBackend", struct{}{}, nil)
|
||||
if err != nil {
|
||||
logging.Error("COMMON", "Failed to notify frontend that backend is shutting down:", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
112
main.go
112
main.go
|
|
@ -2,14 +2,15 @@ package main
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/rpc"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"wwfc/api"
|
||||
"wwfc/common"
|
||||
"wwfc/gamestats"
|
||||
|
|
@ -25,7 +26,9 @@ import (
|
|||
"github.com/logrusorgru/aurora/v3"
|
||||
)
|
||||
|
||||
var config = common.GetConfig()
|
||||
var (
|
||||
config = common.GetConfig()
|
||||
)
|
||||
|
||||
func main() {
|
||||
logging.SetLevel(*config.LogLevel)
|
||||
|
|
@ -38,10 +41,8 @@ func main() {
|
|||
// Start the backend instead of the frontend if the first argument is "backend"
|
||||
if len(args) > 0 && args[0] == "backend" {
|
||||
backendMain(len(args) > 1 && args[1] == "reload")
|
||||
} else if len(args) > 0 && args[0] == "cmd" {
|
||||
handleCommand(args[1:])
|
||||
} else {
|
||||
frontendMain(len(args) > 0 && args[0] == "skipbackend")
|
||||
frontendMain(len(args) > 0 && args[0] == "frontend")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,6 +55,9 @@ type RPCPacket struct {
|
|||
|
||||
// backendMain starts all the servers and creates an RPC server to communicate with the frontend
|
||||
func backendMain(reload bool) {
|
||||
sigExit := make(chan os.Signal, 1)
|
||||
signal.Notify(sigExit, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
if err := logging.SetOutput(config.LogOutput); err != nil {
|
||||
logging.Error("BACKEND", err)
|
||||
}
|
||||
|
|
@ -96,8 +100,17 @@ func backendMain(reload bool) {
|
|||
|
||||
logging.Notice("BACKEND", "Listening on", aurora.BrightCyan(address))
|
||||
|
||||
// Prevent application from exiting
|
||||
select {}
|
||||
common.Ready()
|
||||
|
||||
// Wait for a signal to shutdown
|
||||
<-sigExit
|
||||
|
||||
err = common.Shutdown()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
(&RPCPacket{}).Shutdown(struct{}{}, &struct{}{})
|
||||
}
|
||||
|
||||
// RPCPacket.NewConnection is called by the frontend to notify the backend of a new connection
|
||||
|
|
@ -183,12 +196,13 @@ var (
|
|||
|
||||
rpcMutex sync.Mutex
|
||||
rpcBusyCount sync.WaitGroup
|
||||
backendReady = make(chan struct{})
|
||||
|
||||
connections = map[string]map[uint64]net.Conn{}
|
||||
)
|
||||
|
||||
// frontendMain starts the backend process and communicates with it using RPC
|
||||
func frontendMain(skipBackend bool) {
|
||||
func frontendMain(noBackend bool) {
|
||||
// Don't allow the frontend to output to a file (there's no reason to)
|
||||
logOutput := config.LogOutput
|
||||
if logOutput == "StdOutAndFile" {
|
||||
|
|
@ -203,7 +217,7 @@ func frontendMain(skipBackend bool) {
|
|||
|
||||
startFrontendServer()
|
||||
|
||||
if !skipBackend {
|
||||
if !noBackend {
|
||||
go startBackendProcess(false, true)
|
||||
} else {
|
||||
go waitForBackend()
|
||||
|
|
@ -285,11 +299,16 @@ func startBackendProcess(reload bool, wait bool) {
|
|||
// waitForBackend waits for the backend to start.
|
||||
// Expects the RPC mutex to be locked.
|
||||
func waitForBackend() {
|
||||
<-backendReady
|
||||
backendReady = make(chan struct{})
|
||||
|
||||
for {
|
||||
client, err := rpc.Dial("tcp", "localhost:29999")
|
||||
if err == nil {
|
||||
rpcClient = client
|
||||
rpcMutex.Unlock()
|
||||
|
||||
logging.Notice("FRONTEND", "Connected to backend")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -431,19 +450,6 @@ func (r *RPCFrontendPacket) CloseConnection(args RPCFrontendPacket, _ *struct{})
|
|||
func (r *RPCFrontendPacket) ReloadBackend(_ struct{}, _ *struct{}) error {
|
||||
r.ShutdownBackend(struct{}{}, &struct{}{})
|
||||
|
||||
// Unlocks the mutex locked by ShutdownBackend
|
||||
startBackendProcess(true, false)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RPCFrontendPacket.ShutdownBackend is called by an external program to shutdown the backend
|
||||
func (r *RPCFrontendPacket) ShutdownBackend(_ struct{}, _ *struct{}) error {
|
||||
// Lock indefinitely
|
||||
rpcMutex.Lock()
|
||||
|
||||
rpcBusyCount.Wait()
|
||||
|
||||
err := rpcClient.Call("RPCPacket.Shutdown", struct{}{}, nil)
|
||||
if err != nil && !strings.Contains(err.Error(), "An existing connection was forcibly closed by the remote host.") {
|
||||
logging.Error("FRONTEND", "Failed to reload backend:", err)
|
||||
|
|
@ -454,52 +460,28 @@ func (r *RPCFrontendPacket) ShutdownBackend(_ struct{}, _ *struct{}) error {
|
|||
logging.Error("FRONTEND", "Failed to close RPC client:", err)
|
||||
}
|
||||
|
||||
// Unlocks the mutex locked by ShutdownBackend
|
||||
startBackendProcess(true, true)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RPCFrontendPacket.ShutdownBackend is called by an external program to shutdown the backend
|
||||
func (r *RPCFrontendPacket) ShutdownBackend(_ struct{}, _ *struct{}) error {
|
||||
logging.Notice("FRONTEND", "Shutting down backend")
|
||||
|
||||
// Lock indefinitely
|
||||
rpcMutex.Lock()
|
||||
|
||||
rpcBusyCount.Wait()
|
||||
|
||||
go waitForBackend()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleCommand is used to send a command to the backend
|
||||
func handleCommand(args []string) {
|
||||
if len(args) < 2 {
|
||||
fmt.Printf("Usage: %s cmd <f|b> <command...>\n", os.Args[0])
|
||||
return
|
||||
}
|
||||
|
||||
var client *rpc.Client
|
||||
var err error
|
||||
|
||||
if args[0] == "f" {
|
||||
client, err = rpc.Dial("tcp", "localhost:29998")
|
||||
} else if args[0] == "b" {
|
||||
client, err = rpc.Dial("tcp", "localhost:29999")
|
||||
} else {
|
||||
fmt.Printf("Unknown command type: '%s', please supply 'f' or 'b' (for frontend or backend)\n", args[0])
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Failed to connect to RPC server:", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer client.Close()
|
||||
|
||||
if args[0] == "b" {
|
||||
fmt.Printf("Unknown backend command: '%s'\n", args[1])
|
||||
} else {
|
||||
if args[1] == "backend" {
|
||||
if len(args) > 2 && args[2] == "shutdown" {
|
||||
err = client.Call("RPCFrontendPacket.ShutdownBackend", struct{}{}, nil)
|
||||
} else {
|
||||
err = client.Call("RPCFrontendPacket.ReloadBackend", struct{}{}, nil)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Unknown frontend command: '%s'\n", args[1])
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Failed to send command:", err)
|
||||
}
|
||||
// RPCFrontendPacket.Ready is called by the backend to indicate it is ready to accept connections
|
||||
func (r *RPCFrontendPacket) Ready(_ struct{}, _ *struct{}) error {
|
||||
close(backendReady)
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user