lib/jugglite/app.rb in jugglite-0.4.0 vs lib/jugglite/app.rb in jugglite-0.5.0

- old
+ new

@@ -9,12 +9,16 @@ 'Content-Type' => 'text/event-stream;charset=utf-8', 'Cache-Control' => 'no-cache' # IE (through the Polyfill) will trip without this } # Options include: - # +path+ : the URI path to listen to ('/stream') - # +keepalive_timeout+ : the timeout in seconds between keepalive comments + # +path+ : the URI path to listen to (defaults to '/stream') + # +keepalive_timeout+ : the timeout in seconds between keepalive comments (defaults to 20) + # +namespace+ : a namespace used as prefix for redis pubsub channels + # +allowed_channels+ : + # * an array with allowed channel names + # * a proc that takes a Rack::Request and returns an array of allowed channels for that particular request def initialize(app = nil, options = {}) @app = app @options = { path: '/stream', namespace: '', @@ -49,11 +53,11 @@ end connection.callback { unregister_connection(connection) } connection.errback { unregister_connection(connection) } - # Needed for crappy Rack::Lint + # Needed for Rack::Lint throw :async # Returning a status of -1 keeps the connection open # You need to use env['async.callback'].call to send the status, headers & body later AsyncResponse @@ -75,13 +79,22 @@ end end end def channels_for_request(request) - # TODO: Sanitize? Check signature? channels = Array(request.params["channel"].split(",")) + # Sanitize channels + channels = channels & allowed_channels(request) if @options[:allowed_channels] channels.map! { |channel| @options[:namespace] + channel } Set.new(channels) + end + + def allowed_channels(request) + case @options[:allowed_channels] + when Proc then @options[:allowed_channels].call(request) + when Array then @options[:allowed_channels] + else raise(ArgumentError, ":allowed_channels should be nil, Array or a Proc") + end end def register_connection(connection) requested_channels = channels_for_request(connection.request) subscribe_to_new_channels(requested_channels - @redis_channels)