em-websocket-server 0.1.2 → 0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +56 -63
- data/em-websocket-server.gemspec +32 -25
- data/examples/chat.html +37 -0
- data/examples/chat.rb +70 -0
- data/examples/tictactoe/tictactoe.html +51 -0
- data/examples/tictactoe/tictactoe.js +130 -0
- data/examples/tictactoe/tictactoe.rb +213 -0
- data/examples/timesync.html +29 -0
- data/examples/timesync.rb +37 -0
- data/lib/web_socket.rb +12 -10
- data/lib/web_socket/client.rb +70 -68
- data/lib/web_socket/server.rb +201 -145
- data/lib/web_socket/util.rb +32 -27
- metadata +34 -10
@@ -0,0 +1,213 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'web_socket'
|
5
|
+
require 'json'
|
6
|
+
require 'uuid'
|
7
|
+
require 'pp'
|
8
|
+
|
9
|
+
$games = {}
|
10
|
+
$waiting = nil
|
11
|
+
$status = nil
|
12
|
+
|
13
|
+
class StatusChannel < EM::Channel
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
super
|
17
|
+
@count = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def increment
|
21
|
+
@count += 1
|
22
|
+
push @count
|
23
|
+
end
|
24
|
+
|
25
|
+
def decrement
|
26
|
+
@count -= 1
|
27
|
+
push @count
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Game < EM::Channel
|
32
|
+
|
33
|
+
attr_accessor :id, :player1, :player2, :current, :grid
|
34
|
+
|
35
|
+
def initialize player1, player2
|
36
|
+
super()
|
37
|
+
@id = UUID.new
|
38
|
+
@player1 = player1
|
39
|
+
@player2 = player2
|
40
|
+
@grid = Matrix.diagonal(0,0,0)
|
41
|
+
end
|
42
|
+
|
43
|
+
def set_turn p
|
44
|
+
@current = p
|
45
|
+
@current.turn!
|
46
|
+
end
|
47
|
+
|
48
|
+
def start!
|
49
|
+
@current = nil
|
50
|
+
@player1.start!
|
51
|
+
@player2.start!
|
52
|
+
toggle
|
53
|
+
end
|
54
|
+
|
55
|
+
def move p, data
|
56
|
+
if @current == p
|
57
|
+
unless @matrix[data["x"].to_i][data["y"].to_i]
|
58
|
+
@matrix[data["x"].to_i][data["y"].to_i] = p.key
|
59
|
+
|
60
|
+
@player1.send_move(p.key, data)
|
61
|
+
@player2.send_move(p.key, data)
|
62
|
+
|
63
|
+
|
64
|
+
winner = has_winner?
|
65
|
+
full = full?
|
66
|
+
|
67
|
+
if winner || full
|
68
|
+
@player1.send_command("game_over")
|
69
|
+
@player2.send_command("game_over")
|
70
|
+
if winner
|
71
|
+
p.send_command("win")
|
72
|
+
opponent(p).send_command("loss")
|
73
|
+
else full?
|
74
|
+
@player1.send_command("draw")
|
75
|
+
@player2.send_command("draw")
|
76
|
+
end
|
77
|
+
else
|
78
|
+
toggle
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def full?
|
85
|
+
@matrix.each do |row|
|
86
|
+
row.each do |col|
|
87
|
+
return false unless col
|
88
|
+
end
|
89
|
+
end
|
90
|
+
return true
|
91
|
+
end
|
92
|
+
|
93
|
+
def has_winner?
|
94
|
+
return true if @matrix[1][1] && (@matrix[0][0] == @matrix[1][1]) && (@matrix[1][1] == @matrix[2][2])
|
95
|
+
return true if @matrix[1][1] && (@matrix[0][2] == @matrix[1][1]) && (@matrix[1][1] == @matrix[2][0])
|
96
|
+
@matrix.each do |row|
|
97
|
+
return true if row[1] && (row[0] == row[1]) && (row[1] == row[2])
|
98
|
+
end
|
99
|
+
return false
|
100
|
+
end
|
101
|
+
|
102
|
+
def opponent p
|
103
|
+
@player1 == p ? @player2 : @player1
|
104
|
+
end
|
105
|
+
|
106
|
+
def toggle
|
107
|
+
set_turn(@current == @player1 ? @player2 : @player1)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class TickTackToeServer < WebSocket::Server
|
112
|
+
|
113
|
+
attr_accessor :game_id, :key, :status_key
|
114
|
+
|
115
|
+
def on_connect
|
116
|
+
@status_key = $status.subscribe do |c|
|
117
|
+
send_user_count c
|
118
|
+
end
|
119
|
+
$status.increment
|
120
|
+
end
|
121
|
+
|
122
|
+
def on_disconnect
|
123
|
+
$status.unsubscribe @status_key
|
124
|
+
$status.decrement
|
125
|
+
delete_game!
|
126
|
+
end
|
127
|
+
|
128
|
+
def on_receive data
|
129
|
+
|
130
|
+
begin
|
131
|
+
msg = JSON.parse(data)
|
132
|
+
rescue
|
133
|
+
send_command "error"
|
134
|
+
return
|
135
|
+
end
|
136
|
+
|
137
|
+
case msg["msg"]
|
138
|
+
when "join"
|
139
|
+
if $waiting.empty?
|
140
|
+
$waiting.push(self)
|
141
|
+
send_command "queued"
|
142
|
+
else
|
143
|
+
$waiting.pop do |opponent|
|
144
|
+
game = Game.new(self, opponent)
|
145
|
+
self.key = "X"
|
146
|
+
opponent.key = "O"
|
147
|
+
self.game_id = opponent.game_id = game.id
|
148
|
+
game.start!
|
149
|
+
$games[game_id] = game
|
150
|
+
end
|
151
|
+
end
|
152
|
+
when "move"
|
153
|
+
if game
|
154
|
+
game.move self, msg["data"]
|
155
|
+
|
156
|
+
else
|
157
|
+
log "Cannot move on a nil game!"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def delete_game!
|
163
|
+
if $games.key?(game_id)
|
164
|
+
$games.delete(game_id)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def game
|
169
|
+
$games[game_id]
|
170
|
+
end
|
171
|
+
|
172
|
+
def turn!
|
173
|
+
send_command "turn"
|
174
|
+
end
|
175
|
+
|
176
|
+
def game_over!
|
177
|
+
delete_game!
|
178
|
+
send_command "game_over"
|
179
|
+
end
|
180
|
+
|
181
|
+
def start!
|
182
|
+
send_command "start"
|
183
|
+
end
|
184
|
+
|
185
|
+
def send_move key, data
|
186
|
+
send_message({:msg => "move", :key => key, :data => data}.to_json)
|
187
|
+
end
|
188
|
+
|
189
|
+
def send_command cmd
|
190
|
+
send_message({:msg => cmd}.to_json)
|
191
|
+
end
|
192
|
+
|
193
|
+
def send_user_count count
|
194
|
+
send_message({:msg => :user_count, :data => count}.to_json)
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
def send_message msg
|
199
|
+
super msg
|
200
|
+
puts "Sent: #{msg}"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
EM.epoll
|
206
|
+
EM.set_descriptor_table_size(10240)
|
207
|
+
|
208
|
+
EM.run do
|
209
|
+
$waiting = EM::Queue.new
|
210
|
+
$status = StatusChannel.new
|
211
|
+
|
212
|
+
EM.start_server "0.0.0.0", 8000, TickTackToeServer
|
213
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>em-websocket-server test</title>
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
|
8
|
+
<h1>em-websocket-server timesync demo</h1>
|
9
|
+
<h2 id="time">opening socket</h2>
|
10
|
+
|
11
|
+
<script>
|
12
|
+
var webSocket = new WebSocket('ws://localhost:8000/time');
|
13
|
+
|
14
|
+
webSocket.onopen = function(event){
|
15
|
+
document.getElementById('time').innerHTML = 'waiting for socket';
|
16
|
+
};
|
17
|
+
|
18
|
+
webSocket.onmessage = function(event){
|
19
|
+
var object = JSON.parse(event.data);
|
20
|
+
document.getElementById('time').innerHTML = object.time;
|
21
|
+
};
|
22
|
+
|
23
|
+
webSocket.onclose = function(event){
|
24
|
+
document.getElementById('time').innerHTML = 'socket closed';
|
25
|
+
};
|
26
|
+
</script>
|
27
|
+
|
28
|
+
</body>
|
29
|
+
</html>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'web_socket'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
class TimeServer < WebSocket::Server
|
8
|
+
|
9
|
+
def on_connect
|
10
|
+
puts "Connection Accepted"
|
11
|
+
@timer = EM.add_periodic_timer(5, EM.Callback(self, :sync_time))
|
12
|
+
end
|
13
|
+
|
14
|
+
def on_disconnect
|
15
|
+
puts "Connection released"
|
16
|
+
EM.cancel_timer @timer
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_receive msg
|
20
|
+
end
|
21
|
+
|
22
|
+
def sync_time
|
23
|
+
puts "Hi"
|
24
|
+
send_message({ :time => Time.now }.to_json)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
EM.epoll = true if EM.epoll?
|
31
|
+
EM.kqueue = true if EM.kqueue?
|
32
|
+
|
33
|
+
EM.set_descriptor_table_size(10240)
|
34
|
+
|
35
|
+
EM.run do
|
36
|
+
EM.start_server "0.0.0.0", 8000, TimeServer
|
37
|
+
end
|
data/lib/web_socket.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'eventmachine'
|
3
|
-
require '
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
require 'web_socket/
|
1
|
+
require 'rubygems'
|
2
|
+
require 'eventmachine'
|
3
|
+
require 'digest'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
module WebSocket
|
7
|
+
VERSION = 0.13
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'web_socket/util.rb'
|
11
|
+
require 'web_socket/frame.rb'
|
12
|
+
require 'web_socket/server.rb'
|
11
13
|
require 'web_socket/client.rb'
|
data/lib/web_socket/client.rb
CHANGED
@@ -1,69 +1,71 @@
|
|
1
|
-
|
2
|
-
module WebSocket
|
3
|
-
|
4
|
-
class Client < EM::Connection
|
5
|
-
|
6
|
-
def path
|
7
|
-
"/chat"
|
8
|
-
end
|
9
|
-
|
10
|
-
def host
|
11
|
-
"localhost:8000"
|
12
|
-
end
|
13
|
-
|
14
|
-
def origin
|
15
|
-
"localhost"
|
16
|
-
end
|
17
|
-
|
18
|
-
# em override
|
19
|
-
def post_init
|
20
|
-
@connected = false
|
21
|
-
end
|
22
|
-
|
23
|
-
def connection_completed
|
24
|
-
send_headers
|
25
|
-
end
|
26
|
-
|
27
|
-
# em override
|
28
|
-
def unbind
|
29
|
-
on_disconnect
|
30
|
-
end
|
31
|
-
|
32
|
-
def on_disconnect
|
33
|
-
end
|
34
|
-
|
35
|
-
def send_message msg
|
36
|
-
send_data Frame.encode(msg)
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def receive_data data
|
42
|
-
unless @connected
|
43
|
-
handshake data
|
44
|
-
else
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
result
|
62
|
-
result << "
|
63
|
-
result << "
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
1
|
+
|
2
|
+
module WebSocket
|
3
|
+
|
4
|
+
class Client < EM::Connection
|
5
|
+
|
6
|
+
def path
|
7
|
+
"/chat"
|
8
|
+
end
|
9
|
+
|
10
|
+
def host
|
11
|
+
"localhost:8000"
|
12
|
+
end
|
13
|
+
|
14
|
+
def origin
|
15
|
+
"localhost"
|
16
|
+
end
|
17
|
+
|
18
|
+
# em override
|
19
|
+
def post_init
|
20
|
+
@connected = false
|
21
|
+
end
|
22
|
+
|
23
|
+
def connection_completed
|
24
|
+
send_headers
|
25
|
+
end
|
26
|
+
|
27
|
+
# em override
|
28
|
+
def unbind
|
29
|
+
on_disconnect
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_disconnect
|
33
|
+
end
|
34
|
+
|
35
|
+
def send_message msg
|
36
|
+
send_data Frame.encode(msg)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def receive_data data
|
42
|
+
unless @connected
|
43
|
+
handshake data
|
44
|
+
else
|
45
|
+
while msg = data.slice!(/\000([^\377]*)\377/)
|
46
|
+
on_receive Frame.decode(msg)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def handshake data
|
52
|
+
|
53
|
+
#convert the headers to a hash
|
54
|
+
@headers = Util.parse_headers(data)
|
55
|
+
@connected = true
|
56
|
+
|
57
|
+
on_connect
|
58
|
+
end
|
59
|
+
|
60
|
+
def send_headers
|
61
|
+
result = "GET #{path} HTTP/1.1\r\n"
|
62
|
+
result << "Upgrade: WebSocket\r\n"
|
63
|
+
result << "Connection: Upgrade\r\n"
|
64
|
+
result << "Host: #{host}\r\n"
|
65
|
+
result << "Origin: #{origin}\r\n\r\n"
|
66
|
+
|
67
|
+
send_data result
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
69
71
|
end
|
data/lib/web_socket/server.rb
CHANGED
@@ -1,146 +1,202 @@
|
|
1
|
-
module WebSocket
|
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
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
1
|
+
module WebSocket
|
2
|
+
|
3
|
+
class Server < EM::Connection
|
4
|
+
|
5
|
+
@@logger = nil
|
6
|
+
@@num_connections = 0
|
7
|
+
@@callbacks = {}
|
8
|
+
@@accepted_origins = []
|
9
|
+
|
10
|
+
attr_accessor :connected,
|
11
|
+
:headers
|
12
|
+
|
13
|
+
def initialize *args
|
14
|
+
super
|
15
|
+
@connected = false
|
16
|
+
@protocol_version = 75
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid_origin?
|
20
|
+
@@accepted_origins.empty? || @@accepted_origins.include?(origin)
|
21
|
+
end
|
22
|
+
|
23
|
+
#not doing anything with this yet
|
24
|
+
def valid_path?
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def valid_upgrade?
|
29
|
+
@headers[:upgrade] =~ /websocket/i
|
30
|
+
end
|
31
|
+
|
32
|
+
def origin
|
33
|
+
@headers[:origin]
|
34
|
+
end
|
35
|
+
|
36
|
+
def host
|
37
|
+
@headers[:host]
|
38
|
+
end
|
39
|
+
|
40
|
+
def path
|
41
|
+
@headers[:path]
|
42
|
+
end
|
43
|
+
|
44
|
+
def cookies
|
45
|
+
@headers[:cookie]
|
46
|
+
end
|
47
|
+
|
48
|
+
def protocol
|
49
|
+
@headers[:protocol]
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.path name, &block
|
53
|
+
@@callbacks[name] = block
|
54
|
+
end
|
55
|
+
|
56
|
+
#tcp connection established
|
57
|
+
def post_init
|
58
|
+
@@num_connections += 1
|
59
|
+
end
|
60
|
+
|
61
|
+
#must be public for em
|
62
|
+
def unbind
|
63
|
+
@@num_connections -= 1
|
64
|
+
on_disconnect
|
65
|
+
end
|
66
|
+
|
67
|
+
def send_message msg
|
68
|
+
send_data Frame.encode(msg)
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
|
73
|
+
#override this method
|
74
|
+
def on_receive msg
|
75
|
+
log msg
|
76
|
+
end
|
77
|
+
|
78
|
+
#override this method
|
79
|
+
def on_connect
|
80
|
+
log "connected"
|
81
|
+
end
|
82
|
+
|
83
|
+
#override this method
|
84
|
+
def on_disconnect
|
85
|
+
log "disconnected"
|
86
|
+
end
|
87
|
+
|
88
|
+
def log msg
|
89
|
+
if @@logger
|
90
|
+
@@logger.info msg
|
91
|
+
else
|
92
|
+
puts msg
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
# when the connection receives data from the client
|
99
|
+
# we either handshake or handle the message at
|
100
|
+
# the app layer
|
101
|
+
def receive_data data
|
102
|
+
unless @connected
|
103
|
+
handshake data
|
104
|
+
else
|
105
|
+
while msg = data.slice!(/\000([^\377]*)\377/)
|
106
|
+
on_receive Frame.decode(msg)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# parse the headers, validate the origin and path
|
112
|
+
# and respond with appropiate headers for a
|
113
|
+
# healthy relationship with the client
|
114
|
+
def handshake data
|
115
|
+
#convert the headers to a hash
|
116
|
+
@headers, challenge = Util.parse_headers(data)
|
117
|
+
|
118
|
+
if challenge
|
119
|
+
@protocol_version = 76
|
120
|
+
|
121
|
+
key1 = @headers[:'sec-websocket-key1']
|
122
|
+
key2 = @headers[:'sec-websocket-key2']
|
123
|
+
|
124
|
+
part1 = number_from_key(key1)
|
125
|
+
part2 = number_from_key(key2)
|
126
|
+
|
127
|
+
unless part1 && part2
|
128
|
+
close_connection
|
129
|
+
return
|
130
|
+
end
|
131
|
+
|
132
|
+
buffer = []
|
133
|
+
buffer += big_endian_bytes(part1)
|
134
|
+
buffer += big_endian_bytes(part2)
|
135
|
+
buffer += challenge.bytes.to_a
|
136
|
+
|
137
|
+
md5 = Digest::MD5.new
|
138
|
+
hash = md5.digest(buffer.pack('c*'))
|
139
|
+
end
|
140
|
+
|
141
|
+
# close the connection if the connection
|
142
|
+
# originates from an invalid source
|
143
|
+
close_connection unless valid_origin?
|
144
|
+
|
145
|
+
# close the connection if a callback
|
146
|
+
# is not registered for the path
|
147
|
+
close_connection unless valid_path?
|
148
|
+
|
149
|
+
# don't respond to non-websocket HTTP requests
|
150
|
+
close_connection unless valid_upgrade?
|
151
|
+
|
152
|
+
#complete the handshake
|
153
|
+
send_headers(hash)
|
154
|
+
|
155
|
+
@connected = true
|
156
|
+
|
157
|
+
on_connect
|
158
|
+
end
|
159
|
+
|
160
|
+
# send the handshake response headers to
|
161
|
+
# complete the initial com
|
162
|
+
def send_headers(hash)
|
163
|
+
response = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
|
164
|
+
response << "Upgrade: WebSocket\r\n"
|
165
|
+
response << "Connection: Upgrade\r\n"
|
166
|
+
if @protocol_version > 75
|
167
|
+
response << "Sec-WebSocket-Origin: #{origin}\r\n"
|
168
|
+
response << "Sec-WebSocket-Location: ws://#{host}#{path}\r\n"
|
169
|
+
response << "Sec-WebSocket-protocol: ws://#{host}#{path}\r\n"
|
170
|
+
else
|
171
|
+
response << "WebSocket-Origin: #{origin}\r\n"
|
172
|
+
response << "WebSocket-Location: ws://#{host}#{path}\r\n"
|
173
|
+
end
|
174
|
+
response << "\r\n"
|
175
|
+
response << hash if @protocol_version > 75
|
176
|
+
|
177
|
+
|
178
|
+
send_data response
|
179
|
+
end
|
180
|
+
|
181
|
+
def number_from_key(key)
|
182
|
+
digits = key.scan(/\d+/).join.to_i
|
183
|
+
spaces = key.scan(/\s+/).join.length
|
184
|
+
|
185
|
+
if spaces > 0
|
186
|
+
return digits / spaces
|
187
|
+
else
|
188
|
+
return nil
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def big_endian_bytes(num)
|
193
|
+
bytes = []
|
194
|
+
4.times do
|
195
|
+
bytes.unshift(num & 0xff)
|
196
|
+
num >>= 8
|
197
|
+
end
|
198
|
+
bytes
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
146
202
|
end
|