Created
March 20, 2015 18:13
-
-
Save wookiecooking/f84098e9ad7a1610870b to your computer and use it in GitHub Desktop.
Example Chat Server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var net = require("net"); | |
var sys = require("sys"); | |
var EventEmitter = require("events").EventEmitter; | |
/******************************************************************************* | |
* ChatServer | |
* | |
* Manages connections, users, and chat messages. | |
******************************************************************************/ | |
function ChatServer() { | |
this.chatters = {}; | |
this.server = net.createServer(this.handleConnection.bind(this)); | |
this.server.listen(1212, "localhost"); | |
} | |
ChatServer.prototype.isNicknameLegal = function(nickname) { | |
// A nickname may contain letters or numbers only, | |
// and may only be used once. | |
if(nickname.replace(/[A-Za-z0-9]*/, '') != "") { | |
return false | |
} | |
for(used_nick in this.chatters) { | |
if(used_nick == nickname) { | |
return false; | |
} | |
} | |
return true; | |
}; | |
ChatServer.prototype.handleConnection = function(connection) { | |
console.log("Incoming connection from " + connection.remoteAddress); | |
connection.setEncoding("utf8"); | |
var chatter = new Chatter(connection, this); | |
chatter.on("chat", this.handleChat.bind(this)); | |
chatter.on("join", this.handleJoin.bind(this)); | |
chatter.on("leave", this.handleLeave.bind(this)); | |
}; | |
ChatServer.prototype.handleChat = function(chatter, message) { | |
this.sendToEveryChatterExcept(chatter, chatter.nickname + ": " + message); | |
}; | |
ChatServer.prototype.handleJoin = function(chatter) { | |
console.log(chatter.nickname + " has joined the chat."); | |
this.sendToEveryChatter(chatter.nickname + " has joined the chat."); | |
this.addChatter(chatter); | |
}; | |
ChatServer.prototype.handleLeave = function(chatter) { | |
console.log(chatter.nickname + " has left the chat."); | |
this.removeChatter(chatter); | |
this.sendToEveryChatter(chatter.nickname + " has left the chat."); | |
}; | |
ChatServer.prototype.addChatter = function(chatter) { | |
this.chatters[chatter.nickname] = chatter; | |
}; | |
ChatServer.prototype.removeChatter = function(chatter) { | |
delete this.chatters[chatter.nickname]; | |
}; | |
ChatServer.prototype.sendToEveryChatter = function(data) { | |
for(nickname in this.chatters) { | |
this.chatters[nickname].send(data); | |
} | |
}; | |
ChatServer.prototype.sendToEveryChatterExcept = function(chatter, data) { | |
for(nickname in this.chatters) { | |
if(nickname != chatter.nickname) { | |
this.chatters[nickname].send(data); | |
} | |
} | |
}; | |
/******************************************************************************* | |
* Chatter | |
* | |
* Represents a single user/connection in the chat server. | |
******************************************************************************/ | |
function Chatter(socket, server) { | |
EventEmitter.call(this); | |
this.socket = socket; | |
this.server = server; | |
this.nickname = ""; | |
this.lineBuffer = new SocketLineBuffer(socket); | |
this.lineBuffer.on("line", this.handleNickname.bind(this)); | |
this.socket.on("close", this.handleDisconnect.bind(this)); | |
this.send("Welcome! What is your nickname?"); | |
}; | |
sys.inherits(Chatter, EventEmitter); | |
Chatter.prototype.handleNickname = function(nickname) { | |
if(server.isNicknameLegal(nickname)) { | |
this.nickname = nickname; | |
this.lineBuffer.removeAllListeners("line"); | |
this.lineBuffer.on("line", this.handleChat.bind(this)); | |
this.send("Welcome to the chat, " + nickname + "!"); | |
this.emit("join", this); | |
} else { | |
this.send("Sorry, but that nickname is not legal or is already in use!"); | |
this.send("What is your nickname?"); | |
} | |
}; | |
Chatter.prototype.handleChat = function(line) { | |
this.emit("chat", this, line); | |
}; | |
Chatter.prototype.handleDisconnect = function() { | |
this.emit("leave", this); | |
}; | |
Chatter.prototype.send = function(data) { | |
this.socket.write(data + "\r\n"); | |
}; | |
/******************************************************************************* | |
* SocketLineBuffer | |
* | |
* Listens for and buffers incoming data on a socket and emits a 'line' event | |
* whenever a complete line is detected. | |
******************************************************************************/ | |
function SocketLineBuffer(socket) { | |
EventEmitter.call(this); | |
this.socket = socket; | |
this.buffer = ""; | |
this.socket.on("data", this.handleData.bind(this)); | |
}; | |
sys.inherits(SocketLineBuffer, EventEmitter); | |
SocketLineBuffer.prototype.handleData = function(data) { | |
for(var i = 0; i < data.length; i++) { | |
var char = data.charAt(i); | |
this.buffer += char; | |
if(char == "\n") { | |
this.buffer = this.buffer.replace("\r\n", ""); | |
this.buffer = this.buffer.replace("\n", ""); | |
this.emit("line", this.buffer); | |
this.buffer = ""; | |
} | |
} | |
}; | |
// Start the server! | |
server = new ChatServer(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment