mirror of
https://github.com/OpenFactorioServerManager/factorio-server-manager.git
synced 2025-01-24 05:17:24 +02:00
Merge pull request #77 from JakenVeina/server-save-on-stop-windows
Stop & Save functionality on Windows, and additional Kill functionality.
This commit is contained in:
commit
f33e540393
8
Makefile
8
Makefile
@ -4,16 +4,18 @@
|
|||||||
NODE_ENV:=production
|
NODE_ENV:=production
|
||||||
|
|
||||||
build:
|
build:
|
||||||
|
# make sure this project is located within GOPATH, I.E. $GOPATH/src/factorio-server-manager
|
||||||
|
|
||||||
# Build Linux release
|
# Build Linux release
|
||||||
mkdir build
|
mkdir build
|
||||||
GOOS=linux GOARCH=amd64 go build -o factorio-server-manager/factorio-server-manager src/*
|
GOOS=linux GOARCH=amd64 go build -o factorio-server-manager/factorio-server-manager factorio-server-manager/src
|
||||||
# ui/node_modules/webpack/bin/webpack.js ui/webpack.config.js app/bundle.js --progress --profile --colors
|
# ui/node_modules/webpack/bin/webpack.js ui/webpack.config.js app/bundle.js --progress --profile --colors
|
||||||
cp -r app/ factorio-server-manager/
|
cp -r app/ factorio-server-manager/
|
||||||
cp conf.json.example factorio-server-manager/conf.json
|
cp conf.json.example factorio-server-manager/conf.json
|
||||||
zip -r build/factorio-server-manager-linux-x64.zip factorio-server-manager
|
zip -r build/factorio-server-manager-linux-x64.zip factorio-server-manager
|
||||||
rm -rf factorio-server-manager
|
rm -rf factorio-server-manager
|
||||||
# Build Windows release
|
# Build Windows release
|
||||||
GOOS=windows GOARCH=386 go build -o factorio-server-manager/factorio-server-manager.exe src/*
|
GOOS=windows GOARCH=386 go build -o factorio-server-manager/factorio-server-manager.exe factorio-server-manager/src
|
||||||
cp -r app/ factorio-server-manager/
|
cp -r app/ factorio-server-manager/
|
||||||
cp conf.json.example factorio-server-manager/conf.json
|
cp conf.json.example factorio-server-manager/conf.json
|
||||||
zip -r build/factorio-server-manager-windows.zip factorio-server-manager
|
zip -r build/factorio-server-manager-windows.zip factorio-server-manager
|
||||||
@ -21,7 +23,7 @@ build:
|
|||||||
|
|
||||||
dev:
|
dev:
|
||||||
mkdir dev
|
mkdir dev
|
||||||
GOOS=linux GOARCH=amd64 go build -o factorio-server-linux/factorio-server-manager src/*
|
GOOS=linux GOARCH=amd64 go build -o factorio-server-linux/factorio-server-manager factorio-server-manager/src
|
||||||
cp -r app/ dev/
|
cp -r app/ dev/
|
||||||
cp conf.json.example dev/conf.json
|
cp conf.json.example dev/conf.json
|
||||||
mv factorio-server-linux/factorio-server-manager dev/factorio-server-manager
|
mv factorio-server-linux/factorio-server-manager dev/factorio-server-manager
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/majormjr/rcon"
|
"github.com/majormjr/rcon"
|
||||||
)
|
)
|
||||||
@ -225,21 +226,27 @@ func (f *FactorioServer) checkLogError(logline []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *FactorioServer) Stop() error {
|
func (f *FactorioServer) Stop() error {
|
||||||
// TODO: Find an alternative to os.Kill on Windows. os.Interupt
|
|
||||||
// is not implemented. Maps will not be saved.
|
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
err := f.Cmd.Process.Signal(os.Kill)
|
|
||||||
if err != nil {
|
|
||||||
if err.Error() == "os: process already finished" {
|
|
||||||
f.Running = false
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Printf("Error sending SIGKILLL to Factorio process: %s", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
f.Running = false
|
|
||||||
log.Println("Sent SIGKILL to Factorio process. Factorio forced to exit.")
|
|
||||||
|
|
||||||
|
// Disable our own handling of CTRL+C, so we don't close when we send it to the console.
|
||||||
|
setCtrlHandlingIsDisabledForThisProcess(true)
|
||||||
|
|
||||||
|
// Send CTRL+C to all processes attached to the console (ourself, and the factorio server instance)
|
||||||
|
sendCtrlCToPid(0)
|
||||||
|
log.Println("Sent SIGINT to Factorio process. Factorio shutting down...")
|
||||||
|
|
||||||
|
// Somehow, the Factorio devs managed to code the game to react appropriately to CTRL+C, including
|
||||||
|
// saving the game, but not actually exit. So, we still have to manually kill the process, and
|
||||||
|
// for extra fun, there's no way to know when the server save has actually completed (unless we want
|
||||||
|
// to inject filesystem logic into what should be a process-level Stop() routine), so our best option
|
||||||
|
// is to just wait an arbitrary amount of time and hope that the save is successful in that time.
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
f.Cmd.Process.Signal(os.Kill)
|
||||||
|
|
||||||
|
// Re-enable handling of CTRL+C after we're sure that the factrio server is shut down.
|
||||||
|
setCtrlHandlingIsDisabledForThisProcess(false)
|
||||||
|
|
||||||
|
f.Running = false
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,3 +269,43 @@ func (f *FactorioServer) Stop() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FactorioServer) Kill() error {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
|
||||||
|
err := f.Cmd.Process.Signal(os.Kill)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "os: process already finished" {
|
||||||
|
f.Running = false
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("Error sending SIGKILL to Factorio process: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.Running = false
|
||||||
|
log.Println("Sent SIGKILL to Factorio process. Factorio forced to exit.")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := f.Cmd.Process.Signal(os.Kill)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "os: process already finished" {
|
||||||
|
f.Running = false
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("Error sending SIGKILL to Factorio process: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.Running = false
|
||||||
|
log.Printf("Sent SIGKILL to Factorio process. Factorio forced to exit.")
|
||||||
|
|
||||||
|
err = f.Rcon.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error close rcon connection: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
10
src/factorio_server_linux.go
Normal file
10
src/factorio_server_linux.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
|
||||||
|
// Stubs for windows-only functions
|
||||||
|
|
||||||
|
func sendCtrlCToPid(pid int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func setCtrlHandlingIsDisabledForThisProcess(disabled bool) {
|
||||||
|
}
|
41
src/factorio_server_windows.go
Normal file
41
src/factorio_server_windows.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func sendCtrlCToPid(pid int) {
|
||||||
|
d, e := syscall.LoadDLL("kernel32.dll")
|
||||||
|
if e != nil {
|
||||||
|
log.Fatalf("LoadDLL: %v\n", e)
|
||||||
|
}
|
||||||
|
p, e := d.FindProc("GenerateConsoleCtrlEvent")
|
||||||
|
if e != nil {
|
||||||
|
log.Fatalf("FindProc: %v\n", e)
|
||||||
|
}
|
||||||
|
r, _, e := p.Call(uintptr(syscall.CTRL_C_EVENT), uintptr(pid))
|
||||||
|
if r == 0 {
|
||||||
|
log.Fatalf("GenerateConsoleCtrlEvent: %v\n", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setCtrlHandlingIsDisabledForThisProcess(disabled bool) {
|
||||||
|
disabledInt := 0
|
||||||
|
if(disabled){
|
||||||
|
disabledInt = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
d, e := syscall.LoadDLL("kernel32.dll")
|
||||||
|
if e != nil {
|
||||||
|
log.Fatalf("LoadDLL: %v\n", e)
|
||||||
|
}
|
||||||
|
p, e := d.FindProc("SetConsoleCtrlHandler")
|
||||||
|
if e != nil {
|
||||||
|
log.Fatalf("FindProc: %v\n", e)
|
||||||
|
}
|
||||||
|
r, _, e := p.Call(uintptr(0), uintptr(disabledInt))
|
||||||
|
if r == 0 {
|
||||||
|
log.Fatalf("SetConsoleCtrlHandler: %v\n", e)
|
||||||
|
}
|
||||||
|
}
|
@ -667,6 +667,41 @@ func StopServer(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func KillServer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
resp := JSONResponse{
|
||||||
|
Success: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
|
||||||
|
|
||||||
|
if FactorioServ.Running {
|
||||||
|
err := FactorioServ.Kill()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error in kill server handler: %s", err)
|
||||||
|
resp.Data = fmt.Sprintf("Error in kill server handler: %s", err)
|
||||||
|
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||||
|
log.Printf("Error encoding config file JSON reponse: ", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Killed Factorio server.")
|
||||||
|
resp.Success = true
|
||||||
|
resp.Data = fmt.Sprintf("Factorio server killed")
|
||||||
|
} else {
|
||||||
|
resp.Data = "Factorio server is not running"
|
||||||
|
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||||
|
log.Printf("Error encoding config file JSON reponse: ", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||||
|
log.Printf("Error encoding config file JSON reponse: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func CheckServer(w http.ResponseWriter, r *http.Request) {
|
func CheckServer(w http.ResponseWriter, r *http.Request) {
|
||||||
resp := JSONResponse{
|
resp := JSONResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
@ -228,6 +228,11 @@ var apiRoutes = Routes{
|
|||||||
"GET",
|
"GET",
|
||||||
"/server/stop",
|
"/server/stop",
|
||||||
StopServer,
|
StopServer,
|
||||||
|
}, {
|
||||||
|
"KillServer",
|
||||||
|
"GET",
|
||||||
|
"/server/kill",
|
||||||
|
KillServer,
|
||||||
}, {
|
}, {
|
||||||
"RunningServer",
|
"RunningServer",
|
||||||
"GET",
|
"GET",
|
||||||
|
@ -5,6 +5,7 @@ class ServerCtl extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
this.startServer = this.startServer.bind(this);
|
this.startServer = this.startServer.bind(this);
|
||||||
this.stopServer = this.stopServer.bind(this);
|
this.stopServer = this.stopServer.bind(this);
|
||||||
|
this.killServer = this.killServer.bind(this);
|
||||||
|
|
||||||
this.incrementPort = this.incrementPort.bind(this);
|
this.incrementPort = this.incrementPort.bind(this);
|
||||||
this.decrementPort = this.decrementPort.bind(this);
|
this.decrementPort = this.decrementPort.bind(this);
|
||||||
@ -58,6 +59,21 @@ class ServerCtl extends React.Component {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
killServer(e) {
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: "/api/server/kill",
|
||||||
|
dataType: "json",
|
||||||
|
success: (resp) => {
|
||||||
|
this.props.facServStatus();
|
||||||
|
this.props.getStatus();
|
||||||
|
console.log(resp)
|
||||||
|
swal(resp.data)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
incrementPort() {
|
incrementPort() {
|
||||||
let port = this.state.port + 1;
|
let port = this.state.port + 1;
|
||||||
this.setState({port: port})
|
this.setState({port: port})
|
||||||
@ -85,7 +101,11 @@ class ServerCtl extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-md-4">
|
<div className="col-md-4">
|
||||||
<button className="btn btn-block btn-danger" type="button" onClick={this.stopServer}><i className="fa fa-stop fa-fw"></i>Stop Factorio Server</button>
|
<button className="btn btn-block btn-warning" type="button" onClick={this.stopServer}><i className="fa fa-stop fa-fw"></i>Stop & Save Factorio Server</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-md-4">
|
||||||
|
<button className="btn btn-block btn-danger" type="button" onClick={this.killServer}><i className="fa fa-close fa-fw"></i>Stop Factorio Server without Saving</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -132,3 +152,4 @@ ServerCtl.propTypes = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default ServerCtl
|
export default ServerCtl
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user