Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add experimental websocket support relying on a monkey patched thin

  • Loading branch information...
commit 04b3deb4ae14efe99c43d2fcce1ca21d42eef29c 1 parent 4c68313
@lifo lifo authored
View
29 examples/hello_websock.rb
@@ -0,0 +1,29 @@
+require File.join(File.dirname(__FILE__), "../vendor/gems/environment")
+$: << File.join(File.dirname(__FILE__), "../lib")
+
+# $: << "/Users/lifo/Rails/thin/lib"
+require 'thin'
+
+require 'cramp/controller'
+
+class WelcomeController < Cramp::Controller::Websocket
+ periodic_timer :send_hello_world, :every => 2
+ on_data :received_data
+
+ def received_data(data)
+ if data =~ /fuck/
+ render "You cant say fuck in here"
+ finish
+ else
+ render "Got your #{data}"
+ end
+ end
+
+ def send_hello_world
+ render "Hello from the Server!"
+ end
+end
+
+Thin::Logging.trace = true
+
+Rack::Handler::Thin.run WelcomeController, :Port => 3000
View
1  lib/cramp/controller.rb
@@ -5,6 +5,7 @@
module Cramp
module Controller
autoload :Action, "cramp/controller/action"
+ autoload :Websocket, "cramp/controller/websocket"
autoload :Body, "cramp/controller/body"
autoload :PeriodicTimer, "cramp/controller/periodic_timer"
autoload :KeepConnectionAlive, "cramp/controller/keep_connection_alive"
View
8 lib/cramp/controller/abstract.rb
@@ -56,6 +56,14 @@ def halt(status, headers = {}, halt_body = '')
send_initial_response(status, headers, halt_body)
end
+ def request
+ @request ||= Rack::Request.new(@env)
+ end
+
+ def params
+ @params ||= @env['usher.params']
+ end
+
end
end
end
View
8 lib/cramp/controller/action.rb
@@ -5,14 +5,6 @@ class Action < Abstract
include PeriodicTimer
include KeepConnectionAlive
- def request
- @request ||= Rack::Request.new(@env)
- end
-
- def params
- @params ||= @env['usher.params']
- end
-
def render(body)
@body.call(body)
end
View
35 lib/cramp/controller/websocket.rb
@@ -0,0 +1,35 @@
+module Cramp
+ module Controller
+ class Websocket < Abstract
+
+ include PeriodicTimer
+
+ class_inheritable_accessor :on_data_callbacks, :instance_reader => false
+ self.on_data_callbacks = []
+
+ class << self
+ def on_data(*methods)
+ self.on_data_callbacks += methods
+ end
+ end
+
+ def process
+ @env['websocket.receive_calback'] = method(:_on_data_receive)
+ super
+ end
+
+ def render(body)
+ @body.call("\x00#{body}\xff")
+ end
+
+ def _on_data_receive(data)
+ data = data.slice(/\000([^\377]*)\377/).gsub(/^\x00|\xff$/, '')
+
+ self.on_data_callbacks.each do |callback|
+ EM.next_tick { send(callback, data) }
+ end
+ end
+
+ end
+ end
+end
View
32 test/controller/websocket_test.rb
@@ -0,0 +1,32 @@
+require 'test_helper'
+
+class WebSocketTest < Cramp::Controller::TestCase
+
+ class WebSocketAction < Cramp::Controller::Websocket
+ cattr_accessor :logs
+ self.logs = []
+
+ on_data :write_logs
+
+ def write_logs(data)
+ self.logs << data
+ end
+ end
+
+ def app
+ WebSocketAction
+ end
+
+ def test_sending_data_over_websocket
+ env = Rack::MockRequest.env_for('/')
+ env['async.callback'] = proc {|resp| }
+
+ EM.run do
+ app.call(env)
+ env['websocket.receive_calback'].call("\000Hello Websock!\377")
+ EM.stop
+ end
+
+ assert_equal ['Hello Websock!'], WebSocketAction.logs
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.