diff --git a/index.js b/index.js index 53c26e2..dabf84d 100644 --- a/index.js +++ b/index.js @@ -11,6 +11,8 @@ var EventEmitter = require('events').EventEmitter exports.createClient = createClient; exports.createServer = createServer; +exports.Client = Client; +exports.Server = Server; function createServer(options) { var port = options.port != null ? @@ -20,7 +22,7 @@ function createServer(options) { 25565 ; var host = options.host || '0.0.0.0'; var timeout = options.timeout || 10 * 1000; - var keepAliveInterval = options.keepAliveInterval || 4 * 1000; + var kickTimeout = options.kickTimeout || 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"); @@ -36,7 +38,12 @@ function createServer(options) { var loggedIn = false; var lastKeepAlive = null; - var keepAliveTimer = setInterval(keepAliveLoop, keepAliveInterval); + var keepAliveTimer = null; + var loginKickTimer = setTimeout(kickForNotLoggingIn, kickTimeout); + + function kickForNotLoggingIn() { + client.end('LoginTimeout'); + } function keepAliveLoop() { if (keepAlive) { @@ -44,7 +51,7 @@ function createServer(options) { if (lastKeepAlive) { var elapsed = new Date() - lastKeepAlive; if (elapsed > timeout) { - client.end(); + client.end('KeepAliveTimeout'); return; } } @@ -56,6 +63,7 @@ function createServer(options) { function onEnd() { clearInterval(keepAliveTimer); + clearTimeout(loginKickTimer); } function onKeepAlive(packet) { @@ -85,6 +93,11 @@ function createServer(options) { loggedIn = true; keepAlive = true; client.username = packet.username; + + clearTimeout(loginKickTimer); + loginKickTimer = null; + keepAliveTimer = setInterval(keepAliveLoop, kickTimeout); + server.emit('login', client); } }); @@ -99,6 +112,7 @@ function createClient(options) { var host = options.host || 'localhost'; assert.ok(options.username, "username is required"); var haveCredentials = options.email && options.password; + var keepAlive = !!options.keepAlive; var client = new Client({ isServer: false @@ -112,10 +126,7 @@ function createClient(options) { serverPort: port, }); }); - client.on('packet', function(packet) { - console.log(packet.id, packet); - }); - client.on(0x00, onKeepAlive); + if (keepAlive) client.on(0x00, onKeepAlive); client.once(0xFC, onEncryptionKeyResponse); client.once(0xFD, onEncryptionKeyRequest); client.connect(port, host); diff --git a/lib/client.js b/lib/client.js index 9df9660..11738b8 100644 --- a/lib/client.js +++ b/lib/client.js @@ -10,7 +10,9 @@ module.exports = Client; function Client(options) { EventEmitter.call(this); - this.isServer = options.isServer; + options = options || {}; + + this.isServer = !!options.isServer; this.socket = null; this.encryptionEnabled = false; this.cipher = null; @@ -40,7 +42,7 @@ Client.prototype.setSocket = function(socket) { }); self.socket.on('close', function() { - self.emit('end'); + self.emit('end', self._endReason); }); }; @@ -51,7 +53,8 @@ Client.prototype.connect = function(port, host) { })); }; -Client.prototype.end = function() { +Client.prototype.end = function(reason) { + this._endReason = reason; this.socket.end(); }; diff --git a/lib/server.js b/lib/server.js index 5472a3f..b78951f 100644 --- a/lib/server.js +++ b/lib/server.js @@ -32,13 +32,13 @@ Server.prototype.listen = function(port, host) { client.on('error', function(err) { self.emit('error', err); }); - client.setSocket(socket); - self.emit('connection', client); client.on('end', function() { delete self.clients[client.id]; this.playerCount -= 1; }); this.playerCount += 1; + client.setSocket(socket); + self.emit('connection', client); }); self.socketServer.on('error', function(err) { self.emit('error', err); @@ -56,7 +56,7 @@ Server.prototype.close = function() { var client; for(var clientId in this.clients) { client = this.clients[clientId]; - client.end(); + client.end('ServerShutdown'); } this.socketServer.close(); }; diff --git a/test/test.js b/test/test.js index 9af688d..3ba6207 100644 --- a/test/test.js +++ b/test/test.js @@ -214,7 +214,7 @@ describe("client", function() { }); }); describe("server", function() { - it("starts listening", function(done) { + it("starts listening and shuts down cleanly", function(done) { var server = mc.createServer({ 'online-mode': false }); var listening = false; server.on('listening', function() { @@ -226,6 +226,25 @@ describe("server", function() { done(); }); }); - it("kicks clients that do not emit keep alive"); + it("kicks clients that do not log in", function(done) { + var server = mc.createServer({ + 'online-mode': false, + kickTimeout: 500, + }); + server.on('connection', function(client) { + client.on('end', function(reason) { + assert.strictEqual(reason, "LoginTimeout"); + }); + }); + server.on('listening', function() { + var client = new mc.Client(); + client.on('end', function() { + done(); + }); + client.connect(25565, 'localhost'); + }); + }); it("responds to ping requests"); + it("clients can log in and chat"); + it("gives correct reason for kicking clients when shutting down"); });