Skip to content

Commit

Permalink
Websocket chat demo
Browse files Browse the repository at this point in the history
  • Loading branch information
lifo committed Mar 16, 2011
1 parent 415d4b0 commit bbbad4d
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 0 deletions.
57 changes: 57 additions & 0 deletions examples/chat_websocket/server.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
require "rubygems"
require "bundler"
Bundler.setup(:default, :example)

require 'cramp'
require 'http_router'
require 'erubis'

if defined?(Rainbows)
puts "Using Rainbows backend for websockets"
Cramp::Websocket.backend = :rainbows
else
puts "Using Thin backend for websockets"
Cramp::Websocket.backend = :thin
end

module ChatRamp
class HomeAction < Cramp::Action
template_path = File.join(File.dirname(__FILE__), 'views/index.erb')
@@template = Erubis::Eruby.new(File.read(template_path))

def start
render @@template.result(binding)
finish
end
end

class SocketAction < Cramp::Websocket
@@users = Set.new

on_start :user_connected
on_finish :user_left
on_data :message_received

def user_connected
@@users << self
end

def user_left
@@users.delete self
end

def message_received(data)
puts "Connected users :#{@@users.size.inspect}"
@@users.each {|u| u.render data }
end
end
end

routes = HttpRouter.new do
add('/').to(ChatRamp::HomeAction)
add('/socket').to(ChatRamp::SocketAction)
end

# bundle exec rainbows -c examples/rainbows.conf examples/chat_websocket/server.ru
# bundle exec thin -V -R examples/chat_websocket/server.ru start
run routes
109 changes: 109 additions & 0 deletions examples/chat_websocket/views/index.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<!-- Taken from http://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk/test-jetty-webapp/src/main/webapp/ws/index.html -->

<html><head>
<title>WebSocket Chat</title>
<script type='text/javascript'>

if (!window.WebSocket)
alert("WebSocket not supported by this browser");

function $() { return document.getElementById(arguments[0]); }
function $F() { return document.getElementById(arguments[0]).value; }

function getKeyCode(ev) { if (window.event) return window.event.keyCode; return ev.keyCode; }

var room = {
join: function(name) {
this._username=name;
var location = 'ws://<%= request.host_with_port %>/socket'
// document.location.toString().replace('http:','ws:');
this._ws=new WebSocket(location);
this._ws.onopen=this._onopen;
this._ws.onmessage=this._onmessage;
this._ws.onclose=this._onclose;
},

_onopen: function(){
$('join').className='hidden';
$('joined').className='';
$('phrase').focus();
room._send(room._username,'has joined!');
},

_send: function(user,message){
user=user.replace(':','_');
if (this._ws)
this._ws.send(user+':'+message);
},

chat: function(text) {
if (text != null && text.length>0 )
room._send(room._username,text);
},

_onmessage: function(m) {
if (m.data){
var c=m.data.indexOf(':');
var from=m.data.substring(0,c).replace('<','&lt;').replace('>','&gt;');
var text=m.data.substring(c+1).replace('<','&lt;').replace('>','&gt;');

var chat=$('chat');
var spanFrom = document.createElement('span');
spanFrom.className='from';
spanFrom.innerHTML=from+':&nbsp;';
var spanText = document.createElement('span');
spanText.className='text';
spanText.innerHTML=text;
var lineBreak = document.createElement('br');
chat.appendChild(spanFrom);
chat.appendChild(spanText);
chat.appendChild(lineBreak);
chat.scrollTop = chat.scrollHeight - chat.clientHeight;
}
},

_onclose: function(m) {
this._ws=null;
$('join').className='';
$('joined').className='hidden';
$('username').focus();
$('chat').innerHTML='';
}

};

</script>
<style type='text/css'>
div { border: 0px solid black; }
div#chat { clear: both; width: 40em; height: 20ex; overflow: auto; background-color: #f0f0f0; padding: 4px; border: 1px solid black; }
div#input { clear: both; width: 40em; padding: 4px; background-color: #e0e0e0; border: 1px solid black; border-top: 0px }
input#phrase { width:30em; background-color: #e0f0f0; }
input#username { width:14em; background-color: #e0f0f0; }
div.hidden { display: none; }
span.from { font-weight: bold; }
span.alert { font-style: italic; }
</style>
</head><body>
<div id='chat'></div>
<div id='input'>
<div id='join' >
Username:&nbsp;<input id='username' type='text'/><input id='joinB' class='button' type='submit' name='join' value='Join'/>
</div>
<div id='joined' class='hidden'>
Chat:&nbsp;<input id='phrase' type='text'/>
<input id='sendB' class='button' type='submit' name='join' value='Send'/>
</div>
</div>
<script type='text/javascript'>
$('username').setAttribute('autocomplete','OFF');
$('username').onkeyup = function(ev) { var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.join($F('username')); return false; } return true; } ;
$('joinB').onclick = function(event) { room.join($F('username')); return false; };
$('phrase').setAttribute('autocomplete','OFF');
$('phrase').onkeyup = function(ev) { var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.chat($F('phrase')); $('phrase').value=''; return false; } return true; };
$('sendB').onclick = function(event) { room.chat($F('phrase')); $('phrase').value=''; return false; };
</script>

<p>
This is a demonstration of the <a href="http://m.onkey.org/2010/1/7/introducing-cramp">Cramp Framework</a>'s websocket capabiltiy using HTML from <a href="http://jetty.mortbay.org/">Jetty websocket server</a>.
</p>
</body></html>

0 comments on commit bbbad4d

Please sign in to comment.