rack-stream icon indicating copy to clipboard operation
rack-stream copied to clipboard

How to pass arguments to the Handlers?

Open penguinpowernz opened this issue 10 years ago • 3 comments

How can I pass arguments to the Handlers? I want to pass the timeout options to the EventSource and WebSockets instantiate but I can't figure out how to get them there. Could you offer some advice?

penguinpowernz avatar Dec 11 '14 09:12 penguinpowernz

Sorry, I don't understand what you're trying to accomplish. Do you have example code?

jch avatar Dec 11 '14 19:12 jch

OK sorry, a bit of background.

I am using this with grape, following the recommended way from the examples. I am pushing messages out from redis subscribe. It works great, but it will timeout after a while when there are no messages, and the javascript client will close the connection.

Looking over the EventSource and WebSockets Readme I found that you can pass in an option to make the server ping the client at a specified interval:

es = Faye::EventSource.new(es,
  :headers => {'Access-Control-Allow-Origin' => '*'},
  :ping    => 15,
  :retry   => 10
)

ws = Faye::WebSocket.new(env, nil, {ping: 15})

Sooo I was looking through the handlers code in this repo, and for the websockets handler I see you do this:

module Rack
  class Stream
    module Handlers
      # This handler uses delegates WebSocket requests to faye-websocket
      class WebSocket < AbstractHandler

      #...snip...

        def open
          @ws = ::Faye::WebSocket.new(@app.env) # object init
          @ws.onopen = lambda do |event|
            @body.each {|c| @ws.send(c)}
          end
        end

So... what I want to be able to do is pass the extra options into the open method to give to the object instantiation:

        def open
          @ws = ::Faye::WebSocket.new(@app.env, nil, @options) # pass in the options hash from somewhere
          @ws.onopen = lambda do |event|
            @body.each {|c| @ws.send(c)}
          end
        end

While I could add the options argument to AbstractHandler#initialize I got lost trying to find where the handlers are initialized and how to pass options from Grape (or rack use/builder/handler) to a handlers new method. Could you point me in the right direction?.

Or maybe I should just fork, and hard code the ping intervals in each handler. I could do a pull request if I figure out the above but I would have no idea how to quantify the changes in a spec.

Cheers

penguinpowernz avatar Dec 11 '14 21:12 penguinpowernz

While I could add the options argument to AbstractHandler#initialize

@penguinpowernz you were on the right track. The concrete subclasses do not implement their own initialize method, instead using AbstractHandler#initialize. A new @options instance variable there will be made available to all subclasses.

        def initialize(app, options = {})
          @app  = app
          @options = options
          @body = DeferrableBody.new
        end

The specific Handler is detected at runtime in Rack::Stream::App#open! with the Handler.find method. I didn't expect options, so Rack::Stream::App#initialize takes an options hash, but does not save it. The same is true for Rack::Stream#initialize. You would need to save the options hash in these places to make it work.

Does that give you enough context to try a pull request? I'm happy to review or give more tips.

jch avatar Dec 12 '14 18:12 jch