/
websocket.rb
61 lines (48 loc) · 1.65 KB
/
websocket.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
59
60
61
module Cramp
module WebsocketExtension
WEBSOCKET_RECEIVE_CALLBACK = 'websocket.receive_callback'.freeze
def websocket?
@env['HTTP_CONNECTION'] == 'Upgrade' && @env['HTTP_UPGRADE'] == 'WebSocket'
end
def websocket_upgrade_data
location = "ws://#{@env['HTTP_HOST']}#{@env['REQUEST_PATH']}"
upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
upgrade << "Upgrade: WebSocket\r\n"
upgrade << "Connection: Upgrade\r\n"
upgrade << "WebSocket-Origin: #{@env['HTTP_ORIGIN']}\r\n"
upgrade << "WebSocket-Location: #{location}\r\n\r\n"
upgrade
end
end
class Websocket < Abstract
include PeriodicTimer
# TODO : Websockets shouldn't need this in an ideal world
include KeepConnectionAlive
class_inheritable_accessor :on_data_callbacks, :instance_reader => false
self.on_data_callbacks = []
class << self
def backend=(backend)
raise "Websocket backend #{backend} is unknown" unless [:thin, :rainbows].include?(backend.to_sym)
require "cramp/websocket/#{backend}_backend.rb"
end
def on_data(*methods)
self.on_data_callbacks += methods
end
end
def process
@env['websocket.receive_callback'] = method(:_on_data_receive)
super
end
def render(body)
@body.call("\x00#{body}\xff")
end
def _on_data_receive(data)
data = data.split(/\000([^\377]*)\377/).select{|d| !d.empty? }.collect{|d| d.gsub(/^\x00|\xff$/, '') }
self.class.on_data_callbacks.each do |callback|
data.each do |message|
EM.next_tick { send(callback, message) }
end
end
end
end
end