API updates

* test passing: kicks clients that do not log in
 * index exports `Client` and `Server`
 * `createServer`: `options.keepAliveInterval` -> `options.kickTimeout`
 * `Client` event `end` includes `reason` argument
   - `LoginTimeout`
   - `KeepAliveTimeout`
   - `ServerShutdown`
 * `createClient`: Set `options.keepAlive` to `false` to disable sending
   keep alive packets
 * `Client`: `options.isServer` defaults to `false`.
This commit is contained in:
Andrew Kelley 2013-01-04 20:55:53 -05:00
parent c9ed8a2792
commit 1661ef3b4b
4 changed files with 48 additions and 15 deletions

View file

@ -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);

View file

@ -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();
};

View file

@ -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();
};

View file

@ -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");
});