Class: Faye::WebSocket

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
API
Defined in:
lib/faye/websocket.rb,
lib/faye/websocket/api.rb,
lib/faye/websocket/client.rb,
lib/faye/adapters/rainbows.rb,
lib/faye/websocket/adapter.rb,
lib/faye/websocket/hybi_parser.rb,
lib/faye/adapters/rainbows_client.rb,
lib/faye/websocket/draft75_parser.rb,
lib/faye/websocket/draft76_parser.rb,
lib/faye/websocket/hybi_parser/handshake.rb,
lib/faye/websocket/hybi_parser/stream_reader.rb

Defined Under Namespace

Modules: API, Adapter Classes: Client, Draft75Parser, Draft76Parser, HybiParser, RainbowsClient, Stream

Constant Summary collapse

ADAPTERS =
{
  'thin'     => :Thin,
  'rainbows' => :Rainbows,
  'goliath'  => :Goliath
}

Constants included from API::ReadyStates

API::ReadyStates::CLOSED, API::ReadyStates::CLOSING, API::ReadyStates::CONNECTING, API::ReadyStates::OPEN

Instance Attribute Summary collapse

Attributes included from API

#buffered_amount, #ready_state, #url

Attributes included from API::EventTarget

#onclose, #onerror, #onmessage, #onopen

Class Method Summary collapse

Instance Method Summary collapse

Methods included from API

#close, #receive, #send

Methods included from API::EventTarget

#add_event_listener, #dispatch_event, #remove_event_listener

Constructor Details

#initialize(env, supported_protos = nil, options = {}) ⇒ WebSocket



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/faye/websocket.rb', line 127

def initialize(env, supported_protos = nil, options = {})
  @env     = env
  @stream  = Stream.new(self)
  @ping    = options[:ping]
  @ping_id = 0
  
  @url = WebSocket.determine_url(@env)
  @ready_state = CONNECTING
  @buffered_amount = 0
  
  @parser = WebSocket.parser(@env).new(self, :protocols => supported_protos)
  
  @send_buffer = []
  EventMachine.next_tick { open }
  
  @callback = @env['async.callback']
  @callback.call([101, {}, @stream])
  @stream.write(@parser.handshake_response)
  
  @ready_state = OPEN if @parser.open?
  
  if @ping
    @ping_timer = EventMachine.add_periodic_timer(@ping) do
      @ping_id += 1
      ping(@ping_id.to_s)
    end
  end
end

Instance Attribute Details

#envObject (readonly)

Returns the value of attribute env.



124
125
126
# File 'lib/faye/websocket.rb', line 124

def env
  @env
end

Class Method Details

.determine_url(env) ⇒ Object



110
111
112
113
114
115
116
117
118
119
# File 'lib/faye/websocket.rb', line 110

def self.determine_url(env)
  secure = if env.has_key?('HTTP_X_FORWARDED_PROTO')
             env['HTTP_X_FORWARDED_PROTO'] == 'https'
           else
             env['HTTP_ORIGIN'] =~ /^https:/i
           end
  
  scheme = secure ? 'wss:' : 'ws:'
  "#{ scheme }//#{ env['HTTP_HOST'] }#{ env['REQUEST_URI'] }"
end

.encode(string, validate_encoding = false) ⇒ Object



76
77
78
79
80
81
82
# File 'lib/faye/websocket.rb', line 76

def self.encode(string, validate_encoding = false)
  if Array === string
    string = utf8_string(string)
    return nil if validate_encoding and !valid_utf8?(string)
  end
  utf8_string(string)
end

.jruby?Boolean



26
27
28
# File 'lib/faye/websocket.rb', line 26

def self.jruby?
  defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
end

.load_adapter(backend) ⇒ Object



63
64
65
66
67
# File 'lib/faye/websocket.rb', line 63

def self.load_adapter(backend)
  const = Kernel.const_get(ADAPTERS[backend]) rescue nil
  require(backend) unless const
  require File.expand_path("../adapters/#{backend}", __FILE__)
end

.parser(env) ⇒ Object



100
101
102
103
104
105
106
107
108
# File 'lib/faye/websocket.rb', line 100

def self.parser(env)
  if env['HTTP_SEC_WEBSOCKET_VERSION']
    HybiParser
  elsif env['HTTP_SEC_WEBSOCKET_KEY1']
    Draft76Parser
  else
    Draft75Parser
  end
end

.rbx?Boolean



30
31
32
# File 'lib/faye/websocket.rb', line 30

def self.rbx?
  defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
end

.utf8_string(string) ⇒ Object



69
70
71
72
73
74
# File 'lib/faye/websocket.rb', line 69

def self.utf8_string(string)
  string = string.pack('C*') if Array === string
  string.respond_to?(:force_encoding) ?
      string.force_encoding('UTF-8') :
      string
end

.valid_utf8?(byte_array) ⇒ Boolean



84
85
86
87
88
89
90
91
# File 'lib/faye/websocket.rb', line 84

def self.valid_utf8?(byte_array)
  string = utf8_string(byte_array)
  if defined?(UTF8_MATCH)
    UTF8_MATCH =~ string ? true : false
  else
    string.valid_encoding?
  end
end

.websocket?(env) ⇒ Boolean



93
94
95
96
97
98
# File 'lib/faye/websocket.rb', line 93

def self.websocket?(env)
  env['REQUEST_METHOD'] == 'GET' and
  env['HTTP_CONNECTION'] and
  env['HTTP_CONNECTION'].split(/\s*,\s*/).include?('Upgrade') and
  ['WebSocket', 'websocket'].include?(env['HTTP_UPGRADE'])
end

Instance Method Details

#ping(message = '', &callback) ⇒ Object



156
157
158
159
# File 'lib/faye/websocket.rb', line 156

def ping(message = '', &callback)
  return false unless @parser.respond_to?(:ping)
  @parser.ping(message, &callback)
end

#protocolObject



161
162
163
# File 'lib/faye/websocket.rb', line 161

def protocol
  @parser.protocol || ''
end

#rack_responseObject



165
166
167
# File 'lib/faye/websocket.rb', line 165

def rack_response
  [ -1, {}, [] ]
end