Class: LivereloadRails::WebSocket

Inherits:
Object
  • Object
show all
Defined in:
lib/livereload_rails/web_socket.rb

Overview

Embodies a WebSocket connection as a separate thread.

Constant Summary collapse

PING_TIMEOUT =
1

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env) ⇒ WebSocket

Returns a new instance of WebSocket.

Parameters:

  • env

    a rack environment hash

Raises:

  • (ArgumentError)


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/livereload_rails/web_socket.rb', line 31

def initialize(env)
  raise ArgumentError, "no block given" unless block_given?

  @env = env
  @handlers = { open: Set.new, close: Set.new, message: Set.new }
  @handshake = ::WebSocket::Handshake::Server.new(secure: false)

  queue = Queue.new

  @thread = Thread.new do
    begin
      finish_initialize = proc do |event|
        finish_initialize = nil
        queue << event
      end

      hijack do
        yield self
        finish_initialize[:connected]
      end
    ensure
      finish_initialize[$!] if finish_initialize
    end
  end

  message = queue.pop
  raise message if message.is_a?(Exception)
end

Instance Attribute Details

#threadObject (readonly)

Returns the value of attribute thread.



60
61
62
# File 'lib/livereload_rails/web_socket.rb', line 60

def thread
  @thread
end

Class Method Details

.from_rack(env, &block) ⇒ WebSocket?

Same as #initialize, but first checks if the request is a websocket upgrade.

Examples:

WebSocket.from_rack(env) do |ws|
  
  ws.on(:open)    {  }
  ws.on(:message) {  }
  ws.on(:close)   {  }
end

Returns:

  • (WebSocket, nil)

    a websocket instance, or nil if request was not a websocket.



25
26
27
# File 'lib/livereload_rails/web_socket.rb', line 25

def from_rack(env, &block)
  new(env, &block) if env["HTTP_UPGRADE"] == "websocket"
end

Instance Method Details

#closeObject

Close the connection.

Can safely be called multiple times.



88
89
90
# File 'lib/livereload_rails/web_socket.rb', line 88

def close
  @stream.close if @stream
end

#on(event, &handler) ⇒ Object

Note:

If an event handler raises an error, handlers after it will not run.

Register an event handler.

Examples:

handler = websocket.on(:open) {  }

Parameters:

  • event (Symbol)

    (one of :open, :close, :message)

Raises:

  • (ArgumentError)


69
70
71
72
73
74
# File 'lib/livereload_rails/web_socket.rb', line 69

def on(event, &handler)
  raise ArgumentError, "no event named #{event.inspect}" unless @handlers.has_key?(event)

  @handlers[event].add(handler)
  handler
end

#write(data, type: :text) ⇒ Object

Queues data for writing. It is not guaranteed that client will receive message.

Parameters:

  • data (#to_s)
  • type (Symbol) (defaults to: :text)


80
81
82
83
# File 'lib/livereload_rails/web_socket.rb', line 80

def write(data, type: :text)
  frame = ::WebSocket::Frame::Outgoing::Server.new(data: data, type: type, version: @handshake.version)
  @stream.write(frame.to_s)
end