diff --git a/lib/errors.js b/lib/errors.js index a213a7a9..9e9676f9 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -12,9 +12,13 @@ class InvalidMessage extends Error { } // Errror class for known errors occuring during startup class StartupError extends Error { } +// Errors outside of our control. +class EnvironmentError extends Error { } + module.exports = { CommandError, RequestError, InvalidMessage, StartupError, + EnvironmentError, } diff --git a/lib/factorio/server.js b/lib/factorio/server.js index b93e9b73..0f45921a 100644 --- a/lib/factorio/server.js +++ b/lib/factorio/server.js @@ -14,6 +14,8 @@ const crypto = require("crypto"); const ini = require("ini"); const rconClient = require("rcon-client"); +const errors = require("lib/errors"); + /** * Determines the version of Factorio the datadir is pointing to by @@ -461,7 +463,21 @@ class FactorioServer extends events.EventEmitter { this._server.on('exit', (code, signal) => { if (this._state !== "stopping") { if (this._unexpected.length === 0) { - this.emit('error', new Error("Factorio server unexpectedly shut down")); + if (signal === 'SIGKILL') { + this.emit('error', new errors.EnvironmentError( + "Factorio server was unexpectedly killed, is the system low on memory?" + )); + + } else { + let msg; + if (code !== null) { + msg = `Factorio server unexpectedly shut down with code ${code}` + } else { + msg = `Factorio server was unexpectedly shut by down by signal ${signal}`; + } + + this.emit('error', new Error(msg)); + } } else if (this._unexpected.length === 1) { this.emit('error', new Error(this._unexpected[0])); diff --git a/test/integration/server.js b/test/integration/server.js index 9c8de5ee..0c135ec8 100644 --- a/test/integration/server.js +++ b/test/integration/server.js @@ -4,6 +4,7 @@ const fs = require("fs-extra"); const path = require("path"); const factorio = require("lib/factorio"); +const errors = require("lib/errors"); describe("Integration of lib/factorio/server", function() { @@ -182,5 +183,34 @@ describe("Integration of lib/factorio/server", function() { await server.stop(); }); }); + + describe(".start() termination detection", function() { + it("should tell if Factorio got killed", async function() { + // This does not work on Windows + if (process.platform == "win32") { + this.skip(); + } + slowTest(this); + log(".start() for kill detection"); + + let startPromise = server.start("test.zip"); + server.once('output', () => server._server.kill('SIGKILL')); + + await assert.rejects( + startPromise, + new errors.EnvironmentError("Factorio server was unexpectedly killed, is the system low on memory?") + ); + }); + + it("should tell if Factorio unexpectedly closed with a code", async function() { + slowTest(this); + log(".start() for unexpected close detection"); + + await assert.rejects( + server.start("does-not-exist.zip"), + new errors.EnvironmentError("Factorio server unexpectedly shut down with code 1") + ); + }); + }); }); });