$(document).ready(function () {
var connection,
username = 'Tester',
password = 'Tester',
historyCounter = 0,
members = {},
// displays
jqLogin = $('#login'),
jqChatroom = $('#chatroom'),
// login display components
jqWaiting = $('#waiting'),
jqNickname = $('#nickname'),
jqPassword = $('#password'),
// chat display components
jqHistory = $('#history'),
jqMembers = $('#members'),
jqLine = $('#line');
function addLine(nick, line) {
var jq = $('
'),
jqNick = jq.find('.nick'),
jqLine = jq.find('.line'),
i, lines;
jqNick.text(nick ? nick + ': ' : '*** ');
jqLine.text(line);
jqHistory.append(jq);
historyCounter++;
for (lines = jqHistory.children(), i = 0; historyCounter > 100; i++, historyCounter--) {
$(lines[i]).remove();
}
}
function addMsg(msgObj) {
var msgHandler = states[activeState].messageHandlers[msgObj.type] || function () { addLine(null, 'Neveljaven paket tipa ' + msgObj.type); };
msgHandler(msgObj);
}
function clearMembers() {
var nickname;
for (nickname in members) {
members[nickname].remove();
delete members[nickname];
}
jqMembers.empty(); // just in case
}
function addMember(nickname) {
var jq = $('');
jq.text(nickname);
jqMembers.append(jq);
members[nickname] = jq;
}
function removeMember(nickname) {
if (nickname in members) {
members[nickname].remove();
delete members[nickname];
}
}
function connect () {
connection = new WebSocket('ws://127.0.0.1:8080');
connection.onopen = function () {
states[activeState].onopen();
};
connection.onmessage = function (message) {
try {
addMsg(JSON.parse(message.data));
}
catch (e) {
addLine(null, 'Exception while handling a server message: ' + e.toString());
}
};
connection.onclose = function () {
states[activeState].onclose();
};
}
function loginKeypress(event) {
if (13 !== event.keyCode) return;
username = jqNickname.val();
password = jqPassword.val();
if (!username) jqNickname[0].focus();
else if (!password) jqPassword[0].focus();
else {
jqWaiting.css('display', '');
jqNickname.unbind('keydown', loginKeypress);
jqPassword.unbind('keydown', loginKeypress);
connect();
}
}
function inputKeypress(event) {
var line;
if (13 === event.keyCode) {
line = jqLine.val();
if (line.length === 0) return;
jqLine.val('');
connection.send(JSON.stringify({ 'type': 'line', 'line': line }));
}
}
var states = {
'login': {
'start': function () {
jqChatroom.css('display', 'none');
jqWaiting.css('display', 'none');
jqLogin.css('display', '');
jqNickname.val('');
jqPassword.val('');
jqNickname[0].focus();
activeState = 'login';
jqNickname.bind('keydown', loginKeypress);
jqPassword.bind('keydown', loginKeypress);
},
'onopen': function () {
connection.send(JSON.stringify({ 'type': 'login', 'username': username, 'password': password }));
},
'messageHandlers': {
'state': function (msgObj) {
var i, history, users;
states.chat.start();
history = msgObj.history;
jqHistory.empty();
historyCounter = 0;
for (i = 0; i < history.length; i++) addMsg(history[i]);
users = msgObj.users;
clearMembers();
for (i = 0; i < users.length; i++) addMember(users[i]);
}
},
'unhandledMessage': function (msgObj) {
connection.close(4000, 'Unhandled message type');
},
'onclose': function () {
states.login.start();
}
},
'chat': {
'start': function () {
jqLogin.css('display', 'none');
jqWaiting.css('display', 'none');
jqChatroom.css('display', '');
jqHistory.empty();
historyCounter = 0;
activeState = 'chat';
jqLine.bind('keydown', inputKeypress);
},
'onopen': function () {
connection.close(4001, 'Connection opened while chatting');
},
'messageHandlers': {
'line': function (msgObj) {
addLine(msgObj.nick, msgObj.line);
},
'join': function (msgObj) {
addLine(null, 'Priklopil: ' + msgObj.nick);
addMember(msgObj.nick);
},
'leave': function (msgObj) {
addLine(null, 'Odklopil: ' + msgObj.nick);
removeMember(msgObj.nick);
}
},
'unhandledMessage': function (msgObj) {
connection.close(4000, 'Unhandled message type');
},
'onclose': function () {
addLine(null, 'Connection closed');
jqLine.unbind('keydown', inputKeypress);
}
}
},
activeState = 'login';
states.login.start();
});
// node.js code
var http = require('http'),
url = require('url'),
path = require('path'),
fs = require('fs'),
nano = require('nano')('http://localhost:5984'),
chatroomDb = nano.use('chatroom'),
websocket = require('websocket'),
chatHistory = [],
activeUsers = {};
var filesDir = path.join(process.cwd(), 'web');
var mimeTypes = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'text/javascript'
};
var getContentType = function (extension) {
var mimeType = mimeTypes[extension];
return mimeType ? mimeType : 'application/octet-stream';
};
var server = http.createServer(function (request, response) {
var relativePath = url.parse(request.url).pathname,
absolutePath = path.join(filesDir, relativePath);
var handler = function (err, stats) {
if (stats) {
if (stats.isDirectory()) {
absolutePath = path.join(absolutePath, 'index.html');
fs.stat(absolutePath, handler);
return;
}
if (stats.isFile()) {
response.writeHead(200, getContentType(path.extname(absolutePath)));
var stream = fs.createReadStream(absolutePath);
stream.pipe(response);
return;
}
}
response.writeHead(404, {'Content-Type': 'text/plain'});
response.write('Not found\r\n');
response.end();
};
console.log('HTTP request for ' + relativePath);
fs.stat(absolutePath, handler);
});
server.listen(8080, function () {});
wsServer = new websocket.server({
'httpServer': server
});
function addLine (type, nick, line) {
var msg = { 'type': type, 'nick': nick, 'line': line },
jsonMsg = JSON.stringify(msg),
username;
chatHistory.push(msg);
while (chatHistory.length > 100) chatHistory.shift();
for (username in activeUsers) {
activeUsers[username].sendMessage(jsonMsg);
}
}
wsServer.on('request', function (request) {
console.log('New websocket connection from ' + request.origin);
// TODO: verify that request.origin is our web site
var connection = request.accept(null, request.origin);
var username = null;
connection.on('message', function (message) {
if (message.type !== 'utf8') {
console.log('Refusing a non-utf8 message');
return;
}
console.log('Processing message: ' + message.utf8Data);
try {
var m = JSON.parse(message.utf8Data);
switch (m.type) {
case 'login':
chatroomDb.get(m.username, function (err, body) {
if (err || (body.password !== m.password)) {
connection.close();
return;
}
username = m.username;
addLine('join', username, null);
activeUsers[username] = {
'sendMessage': function (jsonMsg) {
connection.sendUTF(jsonMsg);
}
};
var users = [], u;
for (u in activeUsers) users.push(u);
connection.sendUTF(JSON.stringify({ 'type': 'state', 'history': chatHistory, 'users': users }));
});
break;
case 'line':
if (!username) {
connection.close();
break;
}
addLine('line', username, m.line);
break;
}
}
catch (e) {
console.log(e);
}
});
connection.on('close', function (connection) {
console.log('Connection closed');
if (username) {
delete activeUsers[username];
addLine('leave', username, null);
}
});
});
console.log('Server running');
Chatroom
Chatroom
Matej: Hi
Borut: How are you?
Martina: Ok, thanks!