Chat server: Difference between revisions
Content added Content deleted
(added omit from ML/I) |
(add javascript (node.js) solution) |
||
Line 473: | Line 473: | ||
} |
} |
||
</lang> |
</lang> |
||
=={{header|JavaScript}}== |
|||
{{works with|Node.js}} |
|||
<lang javascript>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();</lang> |
|||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |