diff --git a/index.js b/index.js index dabf84d..1125639 100644 --- a/index.js +++ b/index.js @@ -9,10 +9,13 @@ var EventEmitter = require('events').EventEmitter , Client = require('./lib/client') , Server = require('./lib/server') -exports.createClient = createClient; -exports.createServer = createServer; -exports.Client = Client; -exports.Server = Server; +module.exports = { + createClient: createClient, + createServer: createServer, + Client: Client, + Server: Server, + ping: require('./lib/ping'), +}; function createServer(options) { var port = options.port != null ? @@ -21,8 +24,8 @@ function createServer(options) { options['server-port'] : 25565 ; var host = options.host || '0.0.0.0'; - var timeout = options.timeout || 10 * 1000; - var kickTimeout = options.kickTimeout || 4 * 1000; + var kickTimeout = options.kickTimeout || 10 * 1000; + var checkTimeoutInterval = options.checkTimeoutInterval || 4 * 1000; var motd = options.motd || "A Minecraft server"; var onlineMode = options['online-mode'] == null ? true : options['online-mode']; assert.ok(! onlineMode, "online mode for servers is not yet supported"); @@ -47,10 +50,10 @@ function createServer(options) { function keepAliveLoop() { if (keepAlive) { - // check if the last keepAlive was too long ago (timeout) + // check if the last keepAlive was too long ago (kickTimeout) if (lastKeepAlive) { var elapsed = new Date() - lastKeepAlive; - if (elapsed > timeout) { + if (elapsed > kickTimeout) { client.end('KeepAliveTimeout'); return; } @@ -96,7 +99,7 @@ function createServer(options) { clearTimeout(loginKickTimer); loginKickTimer = null; - keepAliveTimer = setInterval(keepAliveLoop, kickTimeout); + keepAliveTimer = setInterval(keepAliveLoop, checkTimeoutInterval); server.emit('login', client); } diff --git a/lib/client.js b/lib/client.js index 11738b8..21d18f6 100644 --- a/lib/client.js +++ b/lib/client.js @@ -44,6 +44,10 @@ Client.prototype.setSocket = function(socket) { self.socket.on('close', function() { self.emit('end', self._endReason); }); + + self.socket.on('connect', function() { + self.emit('connect'); + }); }; Client.prototype.connect = function(port, host) { diff --git a/lib/ping.js b/lib/ping.js new file mode 100644 index 0000000..8a495ef --- /dev/null +++ b/lib/ping.js @@ -0,0 +1,38 @@ +var net = require('net') + , Client = require('./client') + +module.exports = ping; + +function ping(options, cb) { + var host = options.host || 'localhost'; + var port = options.port || 25565; + + var client = new Client(); + client.on(0xff, function(packet) { + var parts = packet.reason.split('\u0000'); + var results; + try { + results = { + prefix: parts[0], + protocol: parseInt(parts[1], 10), + version: parts[2], + motd: parts[3], + playerCount: parseInt(parts[4], 10), + maxPlayers: parseInt(parts[5], 10), + }; + } catch (err) { + client.end(); + cb(err); + return; + } + client.end(); + cb(null, results); + }); + client.on('error', function(err) { + cb(err); + }); + client.on('connect', function() { + client.write(0xfe, { magic: 1 }); + }); + client.connect(port, host); +} diff --git a/test/test.js b/test/test.js index 3ba6207..1446bb5 100644 --- a/test/test.js +++ b/test/test.js @@ -1,4 +1,5 @@ var mc = require('../') + , protocol = require('../lib/protocol') , spawn = require('child_process').spawn , path = require('path') , fs = require('fs') @@ -108,6 +109,7 @@ describe("client", function() { after(function(done) { rimraf(MC_SERVER_PATH, done); }); + it("pings the server"); it("connects successfully - online mode", function(done) { startServer({ 'online-mode': 'true' }, function() { var client = mc.createClient({ @@ -229,22 +231,53 @@ describe("server", function() { it("kicks clients that do not log in", function(done) { var server = mc.createServer({ 'online-mode': false, - kickTimeout: 500, + kickTimeout: 100, + checkTimeoutInterval: 10, }); + var count = 2; server.on('connection', function(client) { client.on('end', function(reason) { assert.strictEqual(reason, "LoginTimeout"); + server.close(); }); }); + server.on('close', function() { + resolve(); + }); server.on('listening', function() { var client = new mc.Client(); client.on('end', function() { - done(); + resolve(); }); client.connect(25565, 'localhost'); }); + + function resolve() { + count -= 1; + if (count <= 0) done(); + } + }); + it("responds to ping requests", function(done) { + var server = mc.createServer({ + 'online-mode': false, + motd: 'test1234', + 'max-players': 120, + }); + server.on('listening', function() { + mc.ping({}, function(err, results) { + if (err) return done(err); + assert.deepEqual(results, { + prefix: "ยง1", + protocol: protocol.version, + version: protocol.minecraftVersion, + motd: 'test1234', + playerCount: 0, + maxPlayers: 120 + }); + done(); + }); + }); }); - it("responds to ping requests"); it("clients can log in and chat"); it("gives correct reason for kicking clients when shutting down"); });