em-websocket-server 0.1 → 0.1.1
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 +63 -0
- data/em-websocket-server.gemspec +6 -1
- data/examples/chat.html +28 -26
- data/examples/chat.rb +11 -10
- data/examples/tictactoe/tictactoe.html +51 -0
- data/examples/tictactoe/tictactoe.js +130 -0
- data/examples/tictactoe/tictactoe.rb +215 -0
- data/examples/timesync.html +29 -0
- data/examples/timesync.rb +35 -0
- data/lib/em-websocket-server.rb +6 -12
- metadata +6 -1
data/README.markdown
CHANGED
@@ -0,0 +1,63 @@
|
|
1
|
+
#em-websocket-server
|
2
|
+
|
3
|
+
* em-websocket-server allows the creation of efficient, evented, websocket services
|
4
|
+
|
5
|
+
##Installation
|
6
|
+
|
7
|
+
If you don't have gemcutter
|
8
|
+
|
9
|
+
gem install gemcutter
|
10
|
+
gem tumble
|
11
|
+
|
12
|
+
Otherwise
|
13
|
+
|
14
|
+
gem install em-websocket-server
|
15
|
+
|
16
|
+
Or
|
17
|
+
|
18
|
+
gem install em-websocket-server -s http://gemcutter.org
|
19
|
+
|
20
|
+
##Dependencies
|
21
|
+
- eventmachine http://github.com/eventmachine/eventmachine
|
22
|
+
|
23
|
+
##Docs
|
24
|
+
|
25
|
+
Not yet... coming soon
|
26
|
+
|
27
|
+
##Quick Example
|
28
|
+
|
29
|
+
require 'rubygems'
|
30
|
+
require 'em-websocket-server'
|
31
|
+
require 'json'
|
32
|
+
|
33
|
+
#create a channel for pub sub
|
34
|
+
$chatroom = EM::Channel.new
|
35
|
+
|
36
|
+
class ChatServer < WebSocketServer
|
37
|
+
|
38
|
+
#subscribe to the channel on client connect
|
39
|
+
def on_connect
|
40
|
+
@sid = $chatroom.subscribe do |msg|
|
41
|
+
send_message msg
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
#unsubscribe on client disconnect
|
46
|
+
def on_disconnect
|
47
|
+
$chatroom.unsubscribe(@sid)
|
48
|
+
end
|
49
|
+
|
50
|
+
#publish the message to the channel on
|
51
|
+
#client message received
|
52
|
+
def on_receive msg
|
53
|
+
$chatroom.push msg
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
#start the event machine on port 8000 and have
|
59
|
+
#it instantiate ChatServer objects for each
|
60
|
+
#client connection
|
61
|
+
EM.run do
|
62
|
+
EM.start_server "0.0.0.0", 8000, ChatServer
|
63
|
+
end
|
data/em-websocket-server.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
spec = Gem::Specification.new do |s|
|
2
2
|
s.name = 'em-websocket-server'
|
3
|
-
s.version = '0.1'
|
3
|
+
s.version = '0.1.1'
|
4
4
|
s.date = '2009-12-14'
|
5
5
|
s.summary = 'An evented ruby websocket server built on top of EventMachine'
|
6
6
|
s.email = "dan.simpson@gmail.com"
|
@@ -18,6 +18,11 @@ spec = Gem::Specification.new do |s|
|
|
18
18
|
"em-websocket-server.gemspec",
|
19
19
|
"examples/chat.rb",
|
20
20
|
"examples/chat.html",
|
21
|
+
"examples/timesync.html",
|
22
|
+
"examples/timesync.rb",
|
23
|
+
"examples/tictactoe/tictactoe.html",
|
24
|
+
"examples/tictactoe/tictactoe.js",
|
25
|
+
"examples/tictactoe/tictactoe.rb",
|
21
26
|
"lib/em-websocket-server.rb"
|
22
27
|
]
|
23
28
|
end
|
data/examples/chat.html
CHANGED
@@ -1,38 +1,40 @@
|
|
1
1
|
<!doctype html>
|
2
2
|
<html>
|
3
|
-
|
4
|
-
<title>
|
3
|
+
<head>
|
4
|
+
<title>em-websocket-server test</title>
|
5
|
+
</head>
|
6
|
+
<body>
|
5
7
|
|
6
|
-
<style type="text/css" media="screen">
|
7
|
-
#time { background: #ccc; }
|
8
|
-
</style>
|
9
|
-
</head>
|
10
|
-
<body>
|
11
8
|
|
12
|
-
|
9
|
+
<h1>em-websocket-server chat demo</h1>
|
10
|
+
<div id="chat">connecting....</div>
|
13
11
|
|
14
|
-
<h2>The time is <span id="time">opening socket</span></h2>
|
15
|
-
<p>The information for the time is provided by the server. No Date() or intervals here!</p>
|
16
12
|
|
17
|
-
<script>
|
18
|
-
var webSocket = new WebSocket('ws://192.168.0.2:8000/time');
|
19
13
|
|
20
|
-
|
21
|
-
document.getElementById('time').innerHTML = 'waiting for socket';
|
22
|
-
webSocket.send('start');
|
23
|
-
};
|
14
|
+
<script>
|
24
15
|
|
25
|
-
|
26
|
-
console.log(event);
|
27
|
-
var object = JSON.parse(event.data);
|
28
|
-
document.getElementById('time').innerHTML = object.time;
|
29
|
-
};
|
16
|
+
var webSocket = new WebSocket('ws://192.168.0.2:8000/time');
|
30
17
|
|
31
|
-
|
32
|
-
|
33
|
-
|
18
|
+
webSocket.onopen = function(event){
|
19
|
+
document.getElementById('chat').innerHTML = 'connected';
|
20
|
+
};
|
34
21
|
|
35
|
-
|
22
|
+
webSocket.onmessage = function(event){
|
23
|
+
var object = JSON.parse(event.data);
|
24
|
+
document.getElementById('chat').innerHTML += "<b>" + object.user + "</b>" + object.message;
|
25
|
+
};
|
36
26
|
|
37
|
-
|
27
|
+
webSocket.onclose = function(event){
|
28
|
+
document.getElementById('chat').innerHTML = 'socket closed';
|
29
|
+
};
|
30
|
+
|
31
|
+
document.getElementById('chatty').addEventListener("onkeypress", function() {
|
32
|
+
alert("X")
|
33
|
+
});
|
34
|
+
|
35
|
+
</script>
|
36
|
+
|
37
|
+
<input type="text" onkeypress="webSocket.send('hi');" />
|
38
|
+
|
39
|
+
</body>
|
38
40
|
</html>
|
data/examples/chat.rb
CHANGED
@@ -1,24 +1,25 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
+
|
1
3
|
require 'rubygems'
|
4
|
+
require 'em-websocket-server'
|
2
5
|
require 'json'
|
3
6
|
|
4
|
-
|
7
|
+
$chatroom = EM::Channel.new
|
8
|
+
|
9
|
+
class ChatServer < WebSocketServer
|
5
10
|
|
6
11
|
def on_connect
|
7
|
-
@
|
8
|
-
|
12
|
+
@sid = $chatroom.subscribe do |msg|
|
13
|
+
send_message msg
|
9
14
|
end
|
10
15
|
end
|
11
16
|
|
12
17
|
def on_disconnect
|
13
|
-
@
|
18
|
+
$chatroom.unsubscribe(@sid)
|
14
19
|
end
|
15
20
|
|
16
21
|
def on_receive msg
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
def sync_time
|
21
|
-
send_message({ :time => Time.now }.to_json)
|
22
|
+
$chatroom.push msg
|
22
23
|
end
|
23
24
|
|
24
25
|
end
|
@@ -28,5 +29,5 @@ EM.epoll
|
|
28
29
|
EM.set_descriptor_table_size(10240)
|
29
30
|
|
30
31
|
EM.run do
|
31
|
-
EM.start_server "0.0.0.0", 8000,
|
32
|
+
EM.start_server "0.0.0.0", 8000, ChatServer
|
32
33
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
|
3
|
+
<html>
|
4
|
+
<head>
|
5
|
+
<title>Tic Tac Toe</title>
|
6
|
+
<meta name="author" content="Jordan Fowler (TheBreeze)">
|
7
|
+
|
8
|
+
<style type="text/css" media="screen">
|
9
|
+
#navigation ul {
|
10
|
+
list-style-type: none;
|
11
|
+
padding: 0;
|
12
|
+
margin: 25px 0px;
|
13
|
+
}
|
14
|
+
|
15
|
+
#navigation ul li {
|
16
|
+
display: inline;
|
17
|
+
padding: 0;
|
18
|
+
margin: 0;
|
19
|
+
margin-right: 10px;
|
20
|
+
}
|
21
|
+
|
22
|
+
#game-board .cell {
|
23
|
+
width: 100px;
|
24
|
+
height: 100px;
|
25
|
+
padding: 5px;
|
26
|
+
background: #000;
|
27
|
+
color: #FFF;
|
28
|
+
font-size: 100px;
|
29
|
+
text-align: center;
|
30
|
+
vertical-align: middle;
|
31
|
+
}
|
32
|
+
</style>
|
33
|
+
</head>
|
34
|
+
<body>
|
35
|
+
|
36
|
+
<h1>Tic Tac Toe</h1>
|
37
|
+
|
38
|
+
<div id="user-count"></div>
|
39
|
+
<div id="game-stats"></div>
|
40
|
+
<div id="status"></div>
|
41
|
+
|
42
|
+
<table id="game-board">
|
43
|
+
<tr><td id="cell-0-0" class="cell"></td><td id="cell-1-0" class="cell"></td><td id="cell-2-0" class="cell"></td></tr>
|
44
|
+
<tr><td id="cell-0-1" class="cell"></td><td id="cell-1-1" class="cell"></td><td id="cell-2-1" class="cell"></td></tr>
|
45
|
+
<tr><td id="cell-0-2" class="cell"></td><td id="cell-1-2" class="cell"></td><td id="cell-2-2" class="cell"></td></tr>
|
46
|
+
</table>
|
47
|
+
|
48
|
+
<script type="text/javascript" charset="utf-8" src="mootools-1.2.4-core-nc.js"></script>
|
49
|
+
<script type="text/javascript" charset="utf-8" src="tictactoe.js"></script>
|
50
|
+
</body>
|
51
|
+
</html>
|
@@ -0,0 +1,130 @@
|
|
1
|
+
// Author: Jordan Fowler (TheBreeze)
|
2
|
+
|
3
|
+
var TicTacToe = new Class({
|
4
|
+
wins: 0,
|
5
|
+
loses: 0,
|
6
|
+
draws: 0,
|
7
|
+
methodMap: {
|
8
|
+
'queued': 'onQueued',
|
9
|
+
'start': 'onStart',
|
10
|
+
'turn': 'onTurn',
|
11
|
+
'move': 'onMove',
|
12
|
+
'game_over': 'onGameOver',
|
13
|
+
'win': 'onWin',
|
14
|
+
'loss': 'onLoss',
|
15
|
+
'draw': 'onDraw',
|
16
|
+
'user_count': 'onUserCount'
|
17
|
+
},
|
18
|
+
|
19
|
+
initialize: function() {
|
20
|
+
if (TicTacToe.connection == null) {
|
21
|
+
TicTacToe.connection = new WebSocket('ws://192.168.0.2:8000/tictactoe');
|
22
|
+
};
|
23
|
+
|
24
|
+
TicTacToe.connection.onopen = this.join.bind(this);
|
25
|
+
TicTacToe.connection.onmessage = this.onMessage.bind(this);
|
26
|
+
TicTacToe.connection.onclose = this.onGameOver.bind(this);
|
27
|
+
|
28
|
+
this.setGameStats();
|
29
|
+
},
|
30
|
+
|
31
|
+
onMessage: function(event) {
|
32
|
+
var command = JSON.decode(event.data);
|
33
|
+
|
34
|
+
console.log('[RCV] ' + command.msg);
|
35
|
+
|
36
|
+
this[this.methodMap[command.msg]].call(this, command);
|
37
|
+
},
|
38
|
+
|
39
|
+
message: function(msg, options) {
|
40
|
+
var command = JSON.encode({msg: msg, data: options});
|
41
|
+
|
42
|
+
console.log('[SENT] ' + msg);
|
43
|
+
|
44
|
+
TicTacToe.connection.send(command);
|
45
|
+
},
|
46
|
+
|
47
|
+
setStatus: function(status) {
|
48
|
+
$('status').set('text', status);
|
49
|
+
},
|
50
|
+
|
51
|
+
setGameStats: function() {
|
52
|
+
$('game-stats').set('text', 'Wins: '+this.wins+' / Losses: '+this.wins+' / Draws: '+this.draws);
|
53
|
+
},
|
54
|
+
|
55
|
+
setUserCount: function(userCount) {
|
56
|
+
$('user-count').set('text', 'Number of players: ' + userCount);
|
57
|
+
},
|
58
|
+
|
59
|
+
join: function(event) {
|
60
|
+
this.message('join');
|
61
|
+
|
62
|
+
this.setStatus('Connecting you to a game...');
|
63
|
+
},
|
64
|
+
|
65
|
+
reset: function() {
|
66
|
+
$$('.cell').set('text', '');
|
67
|
+
|
68
|
+
this.join();
|
69
|
+
},
|
70
|
+
|
71
|
+
onQueued: function(command) {
|
72
|
+
this.setStatus('Waiting for another player...');
|
73
|
+
},
|
74
|
+
|
75
|
+
onStart: function(command) {
|
76
|
+
this.setStatus('Game found! Their turn first...');
|
77
|
+
},
|
78
|
+
|
79
|
+
onTurn: function(command) {
|
80
|
+
this.setStatus('Your turn...');
|
81
|
+
},
|
82
|
+
|
83
|
+
onMove: function(command) {
|
84
|
+
$('cell-'+command.data.x+'-'+command.data.y).set('text', command.key);
|
85
|
+
|
86
|
+
this.setStatus('Their turn...');
|
87
|
+
},
|
88
|
+
|
89
|
+
move: function(x, y) {
|
90
|
+
this.message('move', {x: x, y: y});
|
91
|
+
},
|
92
|
+
|
93
|
+
onGameOver: function(command) {
|
94
|
+
this.setStatus('Game over.');
|
95
|
+
this.setGameStats();
|
96
|
+
this.reset();
|
97
|
+
},
|
98
|
+
|
99
|
+
onWin: function(command) {
|
100
|
+
this.wins += 1;
|
101
|
+
this.setStatus('Game over. You win!');
|
102
|
+
this.setGameStats();
|
103
|
+
},
|
104
|
+
|
105
|
+
onLoss: function(command) {
|
106
|
+
this.losses += 1;
|
107
|
+
this.setStatus('Game over. You lose!');
|
108
|
+
this.setGameStats();
|
109
|
+
},
|
110
|
+
|
111
|
+
onDraw: function(command) {
|
112
|
+
this.draws += 1;
|
113
|
+
this.setStatus('Game over. It was a draw!');
|
114
|
+
this.setGameStats();
|
115
|
+
},
|
116
|
+
|
117
|
+
onUserCount: function(command) {
|
118
|
+
this.setUserCount(command.data);
|
119
|
+
}
|
120
|
+
});
|
121
|
+
|
122
|
+
$$('.cell').addEvent('click', function(event) {
|
123
|
+
try {
|
124
|
+
currentGame.move($(this).get('id').split('-')[1], $(this).get('id').split('-')[2]);
|
125
|
+
} catch(error) {
|
126
|
+
alert('Please wait while we connect you to a game...');
|
127
|
+
}
|
128
|
+
});
|
129
|
+
|
130
|
+
currentGame = new TicTacToe();
|
@@ -0,0 +1,215 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'em-websocket-server'
|
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, :matrix
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
def initialize player1, player2
|
38
|
+
super()
|
39
|
+
@id = UUID.new
|
40
|
+
@player1 = player1
|
41
|
+
@player2 = player2
|
42
|
+
@matrix = (0..2).collect { [false, false, false] }
|
43
|
+
end
|
44
|
+
|
45
|
+
def set_turn p
|
46
|
+
@current = p
|
47
|
+
@current.turn!
|
48
|
+
end
|
49
|
+
|
50
|
+
def start!
|
51
|
+
@current = nil
|
52
|
+
@player1.start!
|
53
|
+
@player2.start!
|
54
|
+
toggle
|
55
|
+
end
|
56
|
+
|
57
|
+
def move p, data
|
58
|
+
if @current == p
|
59
|
+
unless @matrix[data["x"].to_i][data["y"].to_i]
|
60
|
+
@matrix[data["x"].to_i][data["y"].to_i] = p.key
|
61
|
+
|
62
|
+
@player1.send_move(p.key, data)
|
63
|
+
@player2.send_move(p.key, data)
|
64
|
+
|
65
|
+
|
66
|
+
winner = has_winner?
|
67
|
+
full = full?
|
68
|
+
|
69
|
+
if winner || full
|
70
|
+
@player1.send_command("game_over")
|
71
|
+
@player2.send_command("game_over")
|
72
|
+
if winner
|
73
|
+
p.send_command("win")
|
74
|
+
opponent(p).send_command("loss")
|
75
|
+
else full?
|
76
|
+
@player1.send_command("draw")
|
77
|
+
@player2.send_command("draw")
|
78
|
+
end
|
79
|
+
else
|
80
|
+
toggle
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def full?
|
87
|
+
@matrix.each do |row|
|
88
|
+
row.each do |col|
|
89
|
+
return false unless col
|
90
|
+
end
|
91
|
+
end
|
92
|
+
return true
|
93
|
+
end
|
94
|
+
|
95
|
+
def has_winner?
|
96
|
+
return true if @matrix[1][1] && (@matrix[0][0] == @matrix[1][1]) && (@matrix[1][1] == @matrix[2][2])
|
97
|
+
return true if @matrix[1][1] && (@matrix[0][2] == @matrix[1][1]) && (@matrix[1][1] == @matrix[2][0])
|
98
|
+
@matrix.each do |row|
|
99
|
+
return true if row[1] && (row[0] == row[1]) && (row[1] == row[2])
|
100
|
+
end
|
101
|
+
return false
|
102
|
+
end
|
103
|
+
|
104
|
+
def opponent p
|
105
|
+
@player1 == p ? @player2 : @player1
|
106
|
+
end
|
107
|
+
|
108
|
+
def toggle
|
109
|
+
set_turn(@current == @player1 ? @player2 : @player1)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class TickTackToeServer < WebSocketServer
|
114
|
+
|
115
|
+
attr_accessor :game_id, :key, :status_key
|
116
|
+
|
117
|
+
def on_connect
|
118
|
+
@status_key = $status.subscribe do |c|
|
119
|
+
send_user_count c
|
120
|
+
end
|
121
|
+
$status.increment
|
122
|
+
end
|
123
|
+
|
124
|
+
def on_disconnect
|
125
|
+
$status.unsubscribe @status_key
|
126
|
+
$status.decrement
|
127
|
+
delete_game!
|
128
|
+
end
|
129
|
+
|
130
|
+
def on_receive data
|
131
|
+
|
132
|
+
begin
|
133
|
+
msg = JSON.parse(data)
|
134
|
+
rescue
|
135
|
+
send_command "error"
|
136
|
+
return
|
137
|
+
end
|
138
|
+
|
139
|
+
case msg["msg"]
|
140
|
+
when "join"
|
141
|
+
if $waiting.empty?
|
142
|
+
$waiting.push(self)
|
143
|
+
send_command "queued"
|
144
|
+
else
|
145
|
+
$waiting.pop do |opponent|
|
146
|
+
game = Game.new(self, opponent)
|
147
|
+
self.key = "X"
|
148
|
+
opponent.key = "O"
|
149
|
+
self.game_id = opponent.game_id = game.id
|
150
|
+
game.start!
|
151
|
+
$games[game_id] = game
|
152
|
+
end
|
153
|
+
end
|
154
|
+
when "move"
|
155
|
+
if game
|
156
|
+
game.move self, msg["data"]
|
157
|
+
|
158
|
+
else
|
159
|
+
log "Cannot move on a nil game!"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def delete_game!
|
165
|
+
if $games.key?(game_id)
|
166
|
+
$games.delete(game_id)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def game
|
171
|
+
$games[game_id]
|
172
|
+
end
|
173
|
+
|
174
|
+
def turn!
|
175
|
+
send_command "turn"
|
176
|
+
end
|
177
|
+
|
178
|
+
def game_over!
|
179
|
+
delete_game!
|
180
|
+
send_command "game_over"
|
181
|
+
end
|
182
|
+
|
183
|
+
def start!
|
184
|
+
send_command "start"
|
185
|
+
end
|
186
|
+
|
187
|
+
def send_move key, data
|
188
|
+
send_message({:msg => "move", :key => key, :data => data}.to_json)
|
189
|
+
end
|
190
|
+
|
191
|
+
def send_command cmd
|
192
|
+
send_message({:msg => cmd}.to_json)
|
193
|
+
end
|
194
|
+
|
195
|
+
def send_user_count count
|
196
|
+
send_message({:msg => :user_count, :data => count}.to_json)
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
def send_message msg
|
201
|
+
super msg
|
202
|
+
puts "Sent: #{msg}"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
EM.epoll
|
208
|
+
EM.set_descriptor_table_size(10240)
|
209
|
+
|
210
|
+
EM.run do
|
211
|
+
$waiting = EM::Queue.new
|
212
|
+
$status = StatusChannel.new
|
213
|
+
|
214
|
+
EM.start_server "0.0.0.0", 8000, TickTackToeServer
|
215
|
+
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://192.168.0.2: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,35 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'em-websocket-server'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
class TimeServer < WebSocketServer
|
8
|
+
|
9
|
+
def on_connect
|
10
|
+
@timer = EM.add_periodic_timer(5) do
|
11
|
+
sync_time
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def on_disconnect
|
16
|
+
@timer
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_receive msg
|
20
|
+
puts "msg rcv"
|
21
|
+
end
|
22
|
+
|
23
|
+
def sync_time
|
24
|
+
send_message({ :time => Time.now }.to_json)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
EM.epoll
|
31
|
+
EM.set_descriptor_table_size(10240)
|
32
|
+
|
33
|
+
EM.run do
|
34
|
+
EM.start_server "0.0.0.0", 8000, TimeServer
|
35
|
+
end
|
data/lib/em-websocket-server.rb
CHANGED
@@ -20,18 +20,16 @@ class WebSocketServer < EM::Connection
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def valid_origin?
|
23
|
-
|
24
|
-
#@@accepted_origins.include?(@headers["Origin"])
|
23
|
+
@@accepted_origins.empty? || @@accepted_origins.include?(origin)
|
25
24
|
end
|
26
25
|
|
26
|
+
#not doing anything with this yet
|
27
27
|
def valid_path?
|
28
28
|
true
|
29
|
-
#@@callbacks.key?(@path)
|
30
29
|
end
|
31
30
|
|
32
31
|
def valid_upgrade?
|
33
|
-
|
34
|
-
#@headers["Upgrade"] =~ /websocket/i
|
32
|
+
@headers["Upgrade"] =~ /websocket/i
|
35
33
|
end
|
36
34
|
|
37
35
|
def origin
|
@@ -99,13 +97,7 @@ class WebSocketServer < EM::Connection
|
|
99
97
|
unless @connected
|
100
98
|
handshake data
|
101
99
|
else
|
102
|
-
|
103
|
-
|
104
|
-
if msg == "start"
|
105
|
-
on_connect
|
106
|
-
else
|
107
|
-
on_receive msg
|
108
|
-
end
|
100
|
+
on_receive data.gsub(/^(\x00)|(\xff)$/, "")
|
109
101
|
end
|
110
102
|
end
|
111
103
|
|
@@ -132,6 +124,8 @@ class WebSocketServer < EM::Connection
|
|
132
124
|
send_headers
|
133
125
|
|
134
126
|
@connected = true
|
127
|
+
|
128
|
+
on_connect
|
135
129
|
end
|
136
130
|
|
137
131
|
# send the handshake response headers to
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-websocket-server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Simpson
|
@@ -35,6 +35,11 @@ files:
|
|
35
35
|
- em-websocket-server.gemspec
|
36
36
|
- examples/chat.rb
|
37
37
|
- examples/chat.html
|
38
|
+
- examples/timesync.html
|
39
|
+
- examples/timesync.rb
|
40
|
+
- examples/tictactoe/tictactoe.html
|
41
|
+
- examples/tictactoe/tictactoe.js
|
42
|
+
- examples/tictactoe/tictactoe.rb
|
38
43
|
- lib/em-websocket-server.rb
|
39
44
|
has_rdoc: true
|
40
45
|
homepage: http://github.com/dansimpson/em-websocket-server
|