Skip to content

Instantly share code, notes, and snippets.

@Deisss
Created December 13, 2013 08:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Deisss/7941180 to your computer and use it in GitHub Desktop.
Save Deisss/7941180 to your computer and use it in GitHub Desktop.
Simple multi chat room system using sockjs, tornado, and sockjsroom. To run it, simply do: 'python -m SimpleHTTPServer 7979' and navigate to localhost:7979 to see it in action. Explain: * socket.js should be always the same (for all project, it's just an helper to quickly have disconnect function and event support on top of SockJS) * myChatSyste…
/**
* Create a new socket instance between client and server,
* and start use it
*
* @method mySocketChatRoom
*
* @param roomId {String} A unique string to represent a single room
* @param username {String} The username to use on this room
*/
function mySocketChatRoom(roomId, username) {
var sckt = new socket('chat', true);
// On every connect, the server 'loose' us
// so we have to join again
sckt.on('connect', function() {
// Everytime a connect appear, we have to logon again
this.emit('join', {
username: username,
roomId: roomId
});
}, sckt);
// Start socket instance
sckt.connect();
return sckt;
};
/**
* Create a new chat room (with HTML content and so on...)
*/
function createNewChatRoom() {
var roomId = $('#newRoomId').val(),
username = $('#newUsername').val();
// XXX: roomId should probably not be specified by client...
if(roomId && username && roomId != '' && username != '') {
// Create a new socket instance
var sckt = mySocketChatRoom(roomId, username);
// Create the html content (uber ugly way)
var chatRoom = $('<div>'),
textRoom = $('<div>'),
inputRoom = $('<input>');
chatRoom.addClass('chatRoom');
chatRoom.append(textRoom);
chatRoom.append(inputRoom);
// On enter key, we send the message to server
inputRoom.keyup(function(event) {
if(event.keyCode == 13) {
var message = inputRoom.val();
inputRoom.val('');
// XXX: we should trim message before testing '' value
if(message && message != '') {
sckt.emit('chat', {
message: message
});
}
}
});
// On 'chat' receive, we update the textRoom
sckt.on('chat', function(data) {
var currentUser = $('<a>');
currentUser.html(data.username);
var currentMessage = $('<p>');
currentMessage.html(data.message);
textRoom.append(currentUser);
textRoom.append(currentMessage);
});
// On 'leave/join' receive, we say to all other user who connect/disco
sckt.on('join', function(data) {
var currentUser = $('<small>');
currentUser.html('User ' + data.username + ' enter room');
textRoom.append(currentUser);
textRoom.append($('<br>'));
});
sckt.on('leave', function(data) {
var currentUser = $('<small>');
currentUser.html('User ' + data.username + ' leave room');
textRoom.append(currentUser);
textRoom.append($('<br>'));
})
// Final: Appending to existing dom
$('#chatContent').append(chatRoom);
}
};
/**
* Create a new SockJS instance
*
* @param namespace {String | null} The namespace to link SockJS with (the route)
*/
var socket = function(namespace) {
// Store events list
this._events = {};
// The base url
this._url = '//' + window.location.hostname;
// The base port
this._port = 7878;
// Store the SockJS instance
this._socket = null;
// Store the namespace
this._namespace = namespace || '';
// Should reconnect or not
this.reconnect = true;
};
/**
* Bind a function to an event from server
*
* @param name {String} The message type
* @param fct {Function} The function to call
* @param scope {Object | null} The scope to apply for given function
*/
socket.prototype.on = function(name, fct, scope) {
var fn = fct;
if(scope) {
// We bind scope
fn = function() {
fct.apply(scope, arguments);
};
}
// If it's not existing, we create
if(!this._events[name]) {
this._events[name] = [];
}
// Append event
this._events[name].push(fn);
};
/**
* Send data to server
*
* @param name {String} The message type
* @param data {Object} The linked data with message
*/
socket.prototype.emit = function(name, data) {
this._socket.send(
JSON.stringify({
name: name,
data: data
})
);
};
/**
* Connect to server
*/
socket.prototype.connect = function() {
// Disconnect previous instance
if(this._socket) {
// Get auto-reconnect and re-setup
var p = this.reconnect;
this.disconnect();
this.reconnect = p;
}
// Start new instance
var base = (this._port != 80) ? this._url + ':' + this._port : this._url;
var sckt = new SockJS(base + '/' + this._namespace, null, {
debug : false,
devel : false
});
var _this = this;
/**
* Parse event from server side, and dispatch it
*
* @param response {Object} The data from server side
*/
function _catchEvent(response) {
var name = (response.type) ? response.data.name : response.name,
data = (response.type) ? response.data.data : response.data,
events = _this._events[name];
if(events) {
var parsed = (typeof(data) === 'object' && data !== null) ? data
: JSON.parse(data);
for(var i=0, l=events.length; i<l; ++i) {
var fct = events[i];
if(typeof(fct) === 'function') {
// Defer call on setTimeout
(function(f) {
setTimeout(function() {f(parsed);}, 0);
})(fct);
}
}
}
};
// Catch open
sckt.onopen = function() {
_catchEvent({
name: 'open',
data: {}
});
_catchEvent({
name: 'connect',
data: {}
});
};
sckt.onmessage = function(data) {
_catchEvent(data);
};
// Catch close, and reconnect
sckt.onclose = function() {
_catchEvent({
name: 'close',
data: {}
});
_catchEvent({
name: 'disconnect',
data : {}
});
if(_this.reconnect) {
_this.connect();
}
};
// Link to server
this._socket = sckt;
};
/**
* Disconnect from server
*/
socket.prototype.disconnect = function() {
this.reconnect = false;
if(!this._socket) {
return;
}
this._socket.close();
this._socket = null;
};
<html>
<head>
<title>Test sockjsroom</title>
<link href='//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css' rel='stylesheet'>
<style type='text/css'>
#chatContent {
position: fixed;
bottom: 0;
right: 0;
}
#chatContent > div {
display: inline-block;
}
.chatRoom {
border: 5px solid #444;
}
.chatRoom div {
min-height: 200px;
width: 100%;
border: 1px solid #CCC;
margin-bottom: 2px;
}
.chatRoom input {
width: 100%;
}
.chatRoom a {
color: blue;
}
.chatRoom p {
padding-left: 10px;
color: #888;
}
.chatRoom small {
font-style: italic;
color: #444;
}
</style>
</head>
<body>
<!-- Start new room content -->
<form class='form-inline' onsubmit='createNewChatRoom();return false;'>
<div class='form-group'>
<input type='text' id='newRoomId' class='form-control' placeholder='Room id' />
</div>
<div class='form-group'>
<input type='text' id='newUsername' class='form-control' placeholder='Username' />
</div>
<div class='form-group'>
<input type='submit' class='btn btn-primary' value='Join room' />
</div>
</form>
<!-- Will recieve chat room element here -->
<div id='chatContent'>
</div>
<!-- Scripts -->
<script src='//cdn.sockjs.org/sockjs-0.3.min.js'></script>
<script src='//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'></script>
<script src='socket.js'></script>
<script src='myChatSystem.js'></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment