Permalink
Browse files

Initial snooping

  • Loading branch information...
0 parents commit daea63538bedf8da855dc4d4ed5735c3be90205a @lifo committed Sep 2, 2011
Showing with 2,074 additions and 0 deletions.
  1. +11 −0 Gemfile
  2. +40 −0 Gemfile.lock
  3. +57 −0 app/actions/chat_action.rb
  4. +8 −0 app/actions/home_action.rb
  5. +211 −0 app/views/index.erb
  6. +40 −0 application.rb
  7. +1,681 −0 cadbot.log
  8. +16 −0 config.ru
  9. +5 −0 config/routes.rb
  10. +1 −0 lib/ruby-em-irc2
  11. +4 −0 rainbows.conf
11 Gemfile
@@ -0,0 +1,11 @@
+source :rubygems
+
+gem 'cramp'
+gem 'rainbows'
+
+# Rack based routing
+gem 'http_router'
+
+# Collection of async-proof rack middlewares - https://github.com/rkh/async-rack.git
+gem 'async-rack'
+gem 'yajl-ruby'
@@ -0,0 +1,40 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ activesupport (3.0.10)
+ async-rack (0.5.1)
+ rack (~> 1.1)
+ cramp (0.15.1)
+ activesupport (~> 3.0.9)
+ eventmachine (~> 1.0.0.beta.3)
+ rack (~> 1.3.2)
+ thor (~> 0.14.6)
+ eventmachine (1.0.0.beta.3)
+ http_router (0.10.2)
+ rack (>= 1.0.0)
+ url_mount (~> 0.2.1)
+ kgio (2.6.0)
+ rack (1.3.2)
+ rainbows (4.2.0)
+ kgio (~> 2.5)
+ rack (~> 1.1)
+ unicorn (~> 4.0)
+ raindrops (0.7.0)
+ thor (0.14.6)
+ unicorn (4.0.1)
+ kgio (~> 2.4)
+ rack
+ raindrops (~> 0.6)
+ url_mount (0.2.1)
+ rack
+ yajl-ruby (0.8.2)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ async-rack
+ cramp
+ http_router
+ rainbows
+ yajl-ruby
@@ -0,0 +1,57 @@
+class ChatAction < Cramp::Websocket
+ on_finish :handle_leave
+ on_data :received_data
+
+ def received_data(data)
+ message = parse_json(data)
+ case message[:action]
+ when 'join'
+ handle_join(message)
+ when 'message'
+ handle_message(message)
+ end
+ end
+
+ def handle_join(message)
+ @user = message[:user]
+
+ config = {
+ :server => "irc.freenode.net",
+ :port => 6667,
+ :nickname => @user,
+ :realname => @user,
+ :username => @user,
+ :channels => ["#cramp"]
+ }
+
+ message_handler = Proc.new {|event| render encode_json(:message => event.message, :user => event.from, :action => 'message') }
+ config[:handlers] = {'privmsg' => message_handler}
+
+ @irc = EM.connect(config[:server], config[:port], IRC::Connection, :config => config)
+ end
+
+ def handle_leave
+ return unless @irc
+
+ @irc.quit('Goodbye!')
+ @irc.close_connection
+ end
+
+ def handle_message(message)
+ return unless @irc
+
+ @irc.send_message(@irc.channels[0], message[:message])
+ render encode_json(:message => message[:message], :user => @user, :action => 'message')
+ end
+
+ protected
+
+ def encode_json(payload)
+ Yajl::Encoder.encode(payload)
+ end
+
+ def parse_json(payload)
+ Yajl::Parser.parse(payload, :symbolize_keys => true)
+ end
+
+end
@@ -0,0 +1,8 @@
+class HomeAction < Cramp::Action
+ @@template = ERB.new(File.read(Snoop::Application.root('app/views/index.erb')))
+
+ def start
+ render @@template.result(binding)
+ finish
+ end
+end
@@ -0,0 +1,211 @@
+<html>
+<head>
+<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js'></script>
+<script src='http://jquery-json.googlecode.com/files/jquery.json-2.2.min.js'></script>
+<script src='http://datejs.googlecode.com/svn/trunk/build/date.js'></script>
+<script>
+$(document).ready(function(){
+ if (typeof(WebSocket) != 'undefined' || typeof(MozWebSocket)) {
+ $('#ask').show();
+ } else {
+ $('#error').show();
+ }
+
+ // join on enter
+ $('#ask input').keydown(function(event) {
+ if (event.keyCode == 13) {
+ $('#ask a').click();
+ }
+ })
+
+ // join on click
+ $('#ask a').click(function() {
+ join($('#ask input').val());
+ $('#ask').hide();
+ $('#channel').show();
+ $('input#message').focus();
+ });
+
+ function join(name) {
+ var host = window.location.host.split(':')[0];
+
+ var SocketKlass = "MozWebSocket" in window ? MozWebSocket : WebSocket;
+ var ws = new SocketKlass('ws://<%= request.host_with_port %>/websocket');
+
+ var container = $('div#msgs');
+ ws.onmessage = function(evt) {
+ var obj = $.evalJSON(evt.data);
+ if (typeof obj != 'object') return;
+
+ var action = obj['action'];
+ var struct = container.find('li.' + action + ':first');
+ if (struct.length < 1) {
+ console.log("Could not handle: " + evt.data);
+ return;
+ }
+
+ var msg = struct.clone();
+ msg.find('.time').text((new Date()).toString("HH:mm:ss"));
+
+ if (action == 'message') {
+ var matches;
+ if (matches = obj['message'].match(/^\s*[\/\\]me\s(.*)/)) {
+ msg.find('.user').text(obj['user'] + ' ' + matches[1]);
+ msg.find('.user').css('font-weight', 'bold');
+ } else {
+ msg.find('.user').text(obj['user']);
+ msg.find('.message').text(': ' + obj['message']);
+ }
+ } else if (action == 'control') {
+ msg.find('.user').text(obj['user']);
+ msg.find('.message').text(obj['message']);
+ msg.addClass('control');
+ }
+
+ if (obj['user'] == name) msg.find('.user').addClass('self');
+ container.find('ul').append(msg.show());
+ container.scrollTop(container.find('ul').innerHeight());
+ }
+
+ $('#channel form').submit(function(event) {
+ event.preventDefault();
+ var input = $(this).find(':input');
+ var msg = input.val();
+ ws.send($.toJSON({ action: 'message', message: msg }));
+ input.val('');
+ });
+
+ // send name when joining
+ ws.onopen = function() {
+ ws.send($.toJSON({ action: 'join', user: name }));
+ }
+ }
+});
+</script>
+<style type="text/css" media="screen">
+ * {
+ font-family: Georgia;
+ }
+ a {
+ color: #000;
+ text-decoration: none;
+ }
+ a:hover {
+ text-decoration: underline;
+ }
+ div.bordered {
+ margin: 0 auto;
+ margin-top: 100px;
+ width: 600px;
+ padding: 20px;
+ text-align: center;
+ border: 10px solid #ddd;
+ -webkit-border-radius: 20px;
+ }
+ #error {
+ background-color: #BA0000;
+ color: #fff;
+ font-weight: bold;
+ }
+ #ask {
+ font-size: 20pt;
+ }
+ #ask input {
+ font-size: 20pt;
+ padding: 10px;
+ margin: 0 10px;
+ }
+ #ask span.join {
+ padding: 10px;
+ background-color: #ddd;
+ -webkit-border-radius: 10px;
+ }
+ #channel {
+ margin-top: 100px;
+ height: 480px;
+ position: relative;
+ }
+ #channel div#descr {
+ position: absolute;
+ left: -10px;
+ top: -190px;
+ font-size: 13px;
+ text-align: left;
+ line-height: 20px;
+ padding: 5px;
+ width: 630px;
+ }
+ div#msgs {
+ overflow-y: scroll;
+ height: 400px;
+ }
+ div#msgs ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ text-align: left;
+ }
+ div#msgs li {
+ line-height: 20px;
+ }
+ div#msgs li span.user {
+ color: #ff9900;
+ }
+ div#msgs li span.user.self {
+ color: #aa2211;
+ }
+ div#msgs li span.time {
+ float: right;
+ margin-right: 5px;
+ color: #aaa;
+ font-family: "Courier New";
+ font-size: 12px;
+ }
+ div#msgs li.control {
+ text-align: center;
+ }
+ div#msgs li.control span.message {
+ color: #aaa;
+ }
+ div#input {
+ text-align: left;
+ margin-top: 20px;
+ }
+ div#input #message {
+ width: 600px;
+ border: 5px solid #bbb;
+ -webkit-border-radius: 3px;
+ font-size: 30pt;
+ }
+</style>
+</head>
+<body>
+ <div id="error" class="bordered" style="display: none;">
+ This browser has no native WebSocket support.<br/>
+ Use a WebKit nightly or Google Chrome.
+ </div>
+ <div id="ask" class="bordered" style="display: none;">
+ Name: <input type="text" id="name" /> <a href="#"><span class="join">Join!</span></a>
+ </div>
+ <div id="channel" class="bordered" style="display: none;">
+ <div id="descr" class="bordered">
+ #fauna @ irc.freenode.net
+ </div>
+ <div id="msgs">
+ <ul>
+ <li class="message" style="display: none">
+ <span class="user"></span><span class="message"></span>
+ <span class="time"></span>
+ </li>
+ <li class="control" style="display: none">
+ <span class="user"></span>&nbsp;<span class="message"></span>
+ <span class="time"></span>
+ </li>
+ </ul>
+ </div>
+ <div id="input">
+ <form><input type="text" id="message" /></form>
+ </div>
+ </div>
+</body>
+</html>
@@ -0,0 +1,40 @@
+require "rubygems"
+require "bundler"
+
+module Snoop
+ class Application
+
+ def self.root(path = nil)
+ @_root ||= File.expand_path(File.dirname(__FILE__))
+ path ? File.join(@_root, path.to_s) : @_root
+ end
+
+ def self.env
+ @_env ||= ENV['RACK_ENV'] || 'development'
+ end
+
+ def self.routes
+ @_routes ||= eval(File.read('./config/routes.rb'))
+ end
+
+ # Initialize the application
+ def self.initialize!
+ Cramp::Websocket.backend = :rainbows
+ end
+
+ end
+end
+
+Bundler.require(:default, Snoop::Application.env)
+
+require 'erb'
+require 'yaml'
+require 'stringio'
+require 'yajl'
+
+$: << Snoop::Application.root('lib/ruby-em-irc2/lib')
+require 'em-ruby-irc'
+
+# Preload application classes
+Dir['./app/**/*.rb'].each {|f| require f}
+
Oops, something went wrong.

0 comments on commit daea635

Please sign in to comment.