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
data/README.markdown
CHANGED
@@ -1,63 +1,56 @@
|
|
1
|
-
#em-websocket-server
|
2
|
-
|
3
|
-
* em-websocket-server allows the creation of efficient, evented, websocket services
|
4
|
-
|
5
|
-
##Installation
|
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
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
1
|
+
#em-websocket-server
|
2
|
+
|
3
|
+
* em-websocket-server allows the creation of efficient, evented, websocket services
|
4
|
+
|
5
|
+
##Installation
|
6
|
+
|
7
|
+
gem install em-websocket-server -s http://gemcutter.org
|
8
|
+
|
9
|
+
##Dependencies
|
10
|
+
- eventmachine http://github.com/eventmachine/eventmachine
|
11
|
+
|
12
|
+
##Docs
|
13
|
+
|
14
|
+
Not yet... coming soon
|
15
|
+
|
16
|
+
##Quick Example
|
17
|
+
|
18
|
+
require 'rubygems'
|
19
|
+
require 'em-websocket-server'
|
20
|
+
require 'json'
|
21
|
+
|
22
|
+
#create a channel for pub sub
|
23
|
+
$chatroom = EM::Channel.new
|
24
|
+
|
25
|
+
class ChatServer < WebSocket::Server
|
26
|
+
|
27
|
+
#subscribe to the channel on client connect
|
28
|
+
def on_connect
|
29
|
+
@sid = $chatroom.subscribe do |msg|
|
30
|
+
send_message msg
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#unsubscribe on client disconnect
|
35
|
+
def on_disconnect
|
36
|
+
$chatroom.unsubscribe(@sid)
|
37
|
+
end
|
38
|
+
|
39
|
+
#publish the message to the channel on
|
40
|
+
#client message received
|
41
|
+
def on_receive msg
|
42
|
+
$chatroom.push msg
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
#start the event machine on port 8000 and have
|
48
|
+
#it instantiate ChatServer objects for each
|
49
|
+
#client connection
|
50
|
+
EM.run do
|
51
|
+
EM.start_server "0.0.0.0", 8000, ChatServer
|
52
|
+
end
|
53
|
+
|
54
|
+
##Thanks
|
55
|
+
sidonath
|
56
|
+
TheBreeze
|
data/em-websocket-server.gemspec
CHANGED
@@ -1,25 +1,32 @@
|
|
1
|
-
spec = Gem::Specification.new do |s|
|
2
|
-
s.name = 'em-websocket-server'
|
3
|
-
s.version = '0.
|
4
|
-
s.date = '2009-12-14'
|
5
|
-
s.summary = 'An evented ruby websocket server built on top of EventMachine'
|
6
|
-
s.email = "dan.simpson@gmail.com"
|
7
|
-
s.homepage = "http://github.com/dansimpson/em-websocket-server"
|
8
|
-
s.description = "An evented ruby websocket server built on top of EventMachine"
|
9
|
-
s.has_rdoc = false
|
10
|
-
|
11
|
-
|
12
|
-
s.authors = ["Dan Simpson"]
|
13
|
-
s.add_dependency('eventmachine', '>= 0.12.4')
|
14
|
-
|
15
|
-
|
16
|
-
s.files = [
|
17
|
-
"README.markdown",
|
18
|
-
"em-websocket-server.gemspec",
|
19
|
-
"
|
20
|
-
"
|
21
|
-
"
|
22
|
-
"
|
23
|
-
"
|
24
|
-
|
25
|
-
|
1
|
+
spec = Gem::Specification.new do |s|
|
2
|
+
s.name = 'em-websocket-server'
|
3
|
+
s.version = '0.13'
|
4
|
+
s.date = '2009-12-14'
|
5
|
+
s.summary = 'An evented ruby websocket server built on top of EventMachine'
|
6
|
+
s.email = "dan.simpson@gmail.com"
|
7
|
+
s.homepage = "http://github.com/dansimpson/em-websocket-server"
|
8
|
+
s.description = "An evented ruby websocket server built on top of EventMachine"
|
9
|
+
s.has_rdoc = false
|
10
|
+
|
11
|
+
|
12
|
+
s.authors = ["Dan Simpson"]
|
13
|
+
s.add_dependency('eventmachine', '>= 0.12.4')
|
14
|
+
|
15
|
+
|
16
|
+
s.files = [
|
17
|
+
"README.markdown",
|
18
|
+
"em-websocket-server.gemspec",
|
19
|
+
"examples/chat.rb",
|
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",
|
26
|
+
"lib/web_socket.rb",
|
27
|
+
"lib/web_socket/client.rb",
|
28
|
+
"lib/web_socket/server.rb",
|
29
|
+
"lib/web_socket/frame.rb",
|
30
|
+
"lib/web_socket/util.rb"
|
31
|
+
]
|
32
|
+
end
|
data/examples/chat.html
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>em-websocket-server test</title>
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
|
8
|
+
|
9
|
+
<h1>em-websocket-server chat demo</h1>
|
10
|
+
<div id="chat">connecting....</div>
|
11
|
+
|
12
|
+
<script>
|
13
|
+
|
14
|
+
var webSocket = new WebSocket('ws://localhost:8000/time');
|
15
|
+
|
16
|
+
webSocket.onopen = function(event){
|
17
|
+
document.getElementById('chat').innerHTML = 'connected';
|
18
|
+
};
|
19
|
+
|
20
|
+
webSocket.onmessage = function(event){
|
21
|
+
document.getElementById('chat').innerHTML += "<br/>" + event.data;
|
22
|
+
};
|
23
|
+
|
24
|
+
webSocket.onclose = function(event){
|
25
|
+
document.getElementById('chat').innerHTML = 'socket closed';
|
26
|
+
};
|
27
|
+
|
28
|
+
document.getElementById('chatty').addEventListener("onkeypress", function() {
|
29
|
+
webSocket.send("test");
|
30
|
+
});
|
31
|
+
|
32
|
+
</script>
|
33
|
+
|
34
|
+
<a href="#" onclick="webSocket.send('test')">Send Test</a>
|
35
|
+
|
36
|
+
</body>
|
37
|
+
</html>
|
data/examples/chat.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'web_socket'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
$chatroom = EM::Channel.new
|
8
|
+
$messages = 0
|
9
|
+
|
10
|
+
class ChatServer < WebSocket::Server
|
11
|
+
|
12
|
+
def on_connect
|
13
|
+
puts "Server -> Connect"
|
14
|
+
@sid = $chatroom.subscribe do |msg|
|
15
|
+
send_message msg
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_disconnect
|
20
|
+
puts "Server -> Handle Disconnect"
|
21
|
+
$chatroom.unsubscribe(@sid)
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_receive msg
|
25
|
+
|
26
|
+
$messages += 1
|
27
|
+
if($messages % 100 == 0)
|
28
|
+
puts $messages
|
29
|
+
end
|
30
|
+
|
31
|
+
$chatroom.push(msg)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
class ChatClient < WebSocket::Client
|
37
|
+
|
38
|
+
def initialize *args
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_disconnect
|
43
|
+
puts "Client -> Disconnected"
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_connect
|
47
|
+
|
48
|
+
EM.add_periodic_timer(rand() * 8, EM.Callback(self, :on_timer))
|
49
|
+
|
50
|
+
puts "Client -> connected"
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_timer
|
55
|
+
send_message "x"
|
56
|
+
end
|
57
|
+
|
58
|
+
def on_receive msg
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
EM.kqueue
|
64
|
+
|
65
|
+
EM.run do
|
66
|
+
EM.start_server "0.0.0.0", 8000, ChatServer
|
67
|
+
5.times do
|
68
|
+
EM.connect "localhost", 8000, ChatClient
|
69
|
+
end
|
70
|
+
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://localhost: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();
|