-
Notifications
You must be signed in to change notification settings - Fork 21.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Revert "Revert "Eliminate the EventMachine dependency""
- Loading branch information
Showing
27 changed files
with
385 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
152 changes: 152 additions & 0 deletions
152
actioncable/lib/action_cable/connection/client_socket.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
require 'websocket/driver' | ||
|
||
module ActionCable | ||
module Connection | ||
#-- | ||
# This class is heavily based on faye-websocket-ruby | ||
# | ||
# Copyright (c) 2010-2015 James Coglan | ||
class ClientSocket # :nodoc: | ||
def self.determine_url(env) | ||
scheme = secure_request?(env) ? 'wss:' : 'ws:' | ||
"#{ scheme }//#{ env['HTTP_HOST'] }#{ env['REQUEST_URI'] }" | ||
end | ||
|
||
def self.secure_request?(env) | ||
return true if env['HTTPS'] == 'on' | ||
return true if env['HTTP_X_FORWARDED_SSL'] == 'on' | ||
return true if env['HTTP_X_FORWARDED_SCHEME'] == 'https' | ||
return true if env['HTTP_X_FORWARDED_PROTO'] == 'https' | ||
return true if env['rack.url_scheme'] == 'https' | ||
|
||
return false | ||
end | ||
|
||
CONNECTING = 0 | ||
OPEN = 1 | ||
CLOSING = 2 | ||
CLOSED = 3 | ||
|
||
attr_reader :env, :url | ||
|
||
def initialize(env, event_target, stream_event_loop) | ||
@env = env | ||
@event_target = event_target | ||
@stream_event_loop = stream_event_loop | ||
|
||
@url = ClientSocket.determine_url(@env) | ||
|
||
@driver = @driver_started = nil | ||
|
||
@ready_state = CONNECTING | ||
|
||
# The driver calls +env+, +url+, and +write+ | ||
@driver = ::WebSocket::Driver.rack(self) | ||
|
||
@driver.on(:open) { |e| open } | ||
@driver.on(:message) { |e| receive_message(e.data) } | ||
@driver.on(:close) { |e| begin_close(e.reason, e.code) } | ||
@driver.on(:error) { |e| emit_error(e.message) } | ||
|
||
@stream = ActionCable::Connection::Stream.new(@stream_event_loop, self) | ||
|
||
if callback = @env['async.callback'] | ||
callback.call([101, {}, @stream]) | ||
end | ||
end | ||
|
||
def start_driver | ||
return if @driver.nil? || @driver_started | ||
@driver_started = true | ||
@driver.start | ||
end | ||
|
||
def rack_response | ||
start_driver | ||
[ -1, {}, [] ] | ||
end | ||
|
||
def write(data) | ||
@stream.write(data) | ||
end | ||
|
||
def transmit(message) | ||
return false if @ready_state > OPEN | ||
case message | ||
when Numeric then @driver.text(message.to_s) | ||
when String then @driver.text(message) | ||
when Array then @driver.binary(message) | ||
else false | ||
end | ||
end | ||
|
||
def close(code = nil, reason = nil) | ||
code ||= 1000 | ||
reason ||= '' | ||
|
||
unless code == 1000 or (code >= 3000 and code <= 4999) | ||
raise ArgumentError, "Failed to execute 'close' on WebSocket: " + | ||
"The code must be either 1000, or between 3000 and 4999. " + | ||
"#{code} is neither." | ||
end | ||
|
||
@ready_state = CLOSING unless @ready_state == CLOSED | ||
@driver.close(reason, code) | ||
end | ||
|
||
def parse(data) | ||
@driver.parse(data) | ||
end | ||
|
||
def client_gone | ||
finalize_close | ||
end | ||
|
||
def alive? | ||
@ready_state == OPEN | ||
end | ||
|
||
private | ||
def open | ||
return unless @ready_state == CONNECTING | ||
@ready_state = OPEN | ||
|
||
@event_target.on_open | ||
end | ||
|
||
def receive_message(data) | ||
return unless @ready_state == OPEN | ||
|
||
@event_target.on_message(data) | ||
end | ||
|
||
def emit_error(message) | ||
return if @ready_state >= CLOSING | ||
|
||
@event_target.on_error(message) | ||
end | ||
|
||
def begin_close(reason, code) | ||
return if @ready_state == CLOSED | ||
@ready_state = CLOSING | ||
@close_params = [reason, code] | ||
|
||
if @stream | ||
@stream.shutdown | ||
else | ||
finalize_close | ||
end | ||
end | ||
|
||
def finalize_close | ||
return if @ready_state == CLOSED | ||
@ready_state = CLOSED | ||
|
||
reason = @close_params ? @close_params[0] : '' | ||
code = @close_params ? @close_params[1] : 1006 | ||
|
||
@event_target.on_close(code, reason) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
module ActionCable | ||
module Connection | ||
#-- | ||
# This class is heavily based on faye-websocket-ruby | ||
# | ||
# Copyright (c) 2010-2015 James Coglan | ||
class Stream | ||
def initialize(event_loop, socket) | ||
@event_loop = event_loop | ||
@socket_object = socket | ||
@stream_send = socket.env['stream.send'] | ||
|
||
@rack_hijack_io = nil | ||
|
||
hijack_rack_socket | ||
end | ||
|
||
def each(&callback) | ||
@stream_send ||= callback | ||
end | ||
|
||
def close | ||
shutdown | ||
@socket_object.client_gone | ||
end | ||
|
||
def shutdown | ||
clean_rack_hijack | ||
end | ||
|
||
def write(data) | ||
return @rack_hijack_io.write(data) if @rack_hijack_io | ||
return @stream_send.call(data) if @stream_send | ||
rescue EOFError | ||
@socket_object.client_gone | ||
end | ||
|
||
def receive(data) | ||
@socket_object.parse(data) | ||
end | ||
|
||
private | ||
def hijack_rack_socket | ||
return unless @socket_object.env['rack.hijack'] | ||
|
||
@socket_object.env['rack.hijack'].call | ||
@rack_hijack_io = @socket_object.env['rack.hijack_io'] | ||
|
||
@event_loop.attach(@rack_hijack_io, self) | ||
end | ||
|
||
def clean_rack_hijack | ||
return unless @rack_hijack_io | ||
@event_loop.detach(@rack_hijack_io, self) | ||
@rack_hijack_io = nil | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.