sinatra-websocketio 0.0.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/.gitignore +23 -0
- data/Gemfile +4 -0
- data/History.txt +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +165 -0
- data/Rakefile +1 -0
- data/lib/js/event_emitter.js +68 -0
- data/lib/js/websocketio.js +55 -0
- data/lib/sinatra/websocketio.rb +12 -0
- data/lib/sinatra-websocketio/application.rb +27 -0
- data/lib/sinatra-websocketio/version.rb +5 -0
- data/lib/sinatra-websocketio/websocketio.rb +75 -0
- data/lib/sinatra-websocketio.rb +1 -0
- data/sample/Gemfile +13 -0
- data/sample/Gemfile.lock +55 -0
- data/sample/Procfile +1 -0
- data/sample/README.md +34 -0
- data/sample/config.ru +15 -0
- data/sample/main.rb +27 -0
- data/sample/public/js/index.js +34 -0
- data/sample/views/index.haml +26 -0
- data/sample/views/main.scss +15 -0
- data/sinatra-websocketio.gemspec +25 -0
- metadata +180 -0
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
.DS_Store
|
2
|
+
*.tmp
|
3
|
+
*~
|
4
|
+
*#*
|
5
|
+
vendor
|
6
|
+
.sass-cache
|
7
|
+
.bundle
|
8
|
+
config.yml
|
9
|
+
*.gem
|
10
|
+
*.rbc
|
11
|
+
.config
|
12
|
+
.yardoc
|
13
|
+
InstalledFiles
|
14
|
+
_yardoc
|
15
|
+
coverage
|
16
|
+
doc/
|
17
|
+
lib/bundler/man
|
18
|
+
pkg
|
19
|
+
rdoc
|
20
|
+
spec/reports
|
21
|
+
test/tmp
|
22
|
+
test/version_tmp
|
23
|
+
tmp
|
data/Gemfile
ADDED
data/History.txt
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Sho Hashimoto
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
sinatra-websocketio
|
2
|
+
===================
|
3
|
+
|
4
|
+
* Node.js like WebSocket I/O plugin for Sinatra.
|
5
|
+
* http://github.com/shokai/sinatra-websocketio
|
6
|
+
|
7
|
+
|
8
|
+
Installation
|
9
|
+
------------
|
10
|
+
|
11
|
+
% gem install sinatra-websocketio
|
12
|
+
|
13
|
+
|
14
|
+
Requirements
|
15
|
+
------------
|
16
|
+
* Ruby 1.8.7+ or 1.9.2+
|
17
|
+
* Sinatra 1.3.0+
|
18
|
+
* EventMachine
|
19
|
+
* jQuery
|
20
|
+
|
21
|
+
|
22
|
+
Usage
|
23
|
+
-----
|
24
|
+
|
25
|
+
|
26
|
+
### Server --(WebSocket)--> Client
|
27
|
+
|
28
|
+
Server Side
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require 'sinatra'
|
32
|
+
require 'sinatra/websocketio'
|
33
|
+
|
34
|
+
run Sinatra::Application
|
35
|
+
```
|
36
|
+
```ruby
|
37
|
+
WebSocketIO.push :temperature, 35 # to all clients
|
38
|
+
WebSocketIO.push :light, {:value => 150}, {:to => session_id} # to specific client
|
39
|
+
```
|
40
|
+
|
41
|
+
Client Side
|
42
|
+
|
43
|
+
```html
|
44
|
+
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
45
|
+
<script src="<%= websocketio_js %>"></script>
|
46
|
+
```
|
47
|
+
```javascript
|
48
|
+
var io = new WebSocketIO().connect();
|
49
|
+
io.on("temperature", function(value){
|
50
|
+
console.log("server temperature : " + value);
|
51
|
+
}); // => "server temperature : 35"
|
52
|
+
io.on("light", function(data){
|
53
|
+
console.log("server light sensor : " + data.value);
|
54
|
+
}); // => "server light sensor : 150"
|
55
|
+
```
|
56
|
+
|
57
|
+
|
58
|
+
### Client --(WebSocket)--> Server
|
59
|
+
|
60
|
+
Client Side
|
61
|
+
|
62
|
+
```javascript
|
63
|
+
io.push("chat", {name: "shokai", message: "hello"}); // client -> server
|
64
|
+
```
|
65
|
+
|
66
|
+
Server Side
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
WebSocketIO.on :chat do |data, session|
|
70
|
+
puts "#{data['name']} : #{data['message']} <#{session}>"
|
71
|
+
end
|
72
|
+
## => "shokai : hello <12abcde345f6g7h8ijk>"
|
73
|
+
```
|
74
|
+
|
75
|
+
### On "connect" Event
|
76
|
+
|
77
|
+
Client Side
|
78
|
+
|
79
|
+
```javascript
|
80
|
+
io.on("connect", function(session){
|
81
|
+
alert("connect!!");
|
82
|
+
});
|
83
|
+
|
84
|
+
io.on("disconnect", function(){
|
85
|
+
alert("disconnected");
|
86
|
+
});
|
87
|
+
```
|
88
|
+
|
89
|
+
Server Side
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
WebSocketIO.on :connect do |session|
|
93
|
+
puts "new client <#{session}>"
|
94
|
+
end
|
95
|
+
|
96
|
+
WebSocketIO.on :disconnect do |session|
|
97
|
+
puts "client disconnected <#{session}>"
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
101
|
+
### On "error" Event
|
102
|
+
|
103
|
+
Client Side
|
104
|
+
|
105
|
+
```javascript
|
106
|
+
io.on("error", function(err){
|
107
|
+
console.error(err);
|
108
|
+
});
|
109
|
+
```
|
110
|
+
|
111
|
+
Server Side
|
112
|
+
```ruby
|
113
|
+
WebSocketIO.on :error do |e|
|
114
|
+
STDERR.puts e
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
### Remove Event Listener
|
119
|
+
|
120
|
+
Server Side
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
event_id = WebSocketIO.on :chat do |data, from|
|
124
|
+
puts "#{data} - from#{from}"
|
125
|
+
end
|
126
|
+
WebSocketIO.removeListener event_id
|
127
|
+
```
|
128
|
+
|
129
|
+
or
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
WebSocketIO.removeListener :chat # remove all "chat" listener
|
133
|
+
```
|
134
|
+
|
135
|
+
|
136
|
+
Client Side
|
137
|
+
|
138
|
+
```javascript
|
139
|
+
var event_id = io.on("error", function(err){
|
140
|
+
console.error("WebSocketIO error : "err);
|
141
|
+
});
|
142
|
+
io.removeListener(event_id);
|
143
|
+
```
|
144
|
+
|
145
|
+
or
|
146
|
+
|
147
|
+
```javascript
|
148
|
+
io.removeListener("error"); // remove all "error" listener
|
149
|
+
```
|
150
|
+
|
151
|
+
|
152
|
+
Sample App
|
153
|
+
----------
|
154
|
+
chat app
|
155
|
+
|
156
|
+
- https://github.com/shokai/sinatra-websocketio/tree/master/sample
|
157
|
+
|
158
|
+
|
159
|
+
Contributing
|
160
|
+
------------
|
161
|
+
1. Fork it
|
162
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
163
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
164
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
165
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,68 @@
|
|
1
|
+
// event_emitter.js v0.0.5
|
2
|
+
// https://github.com/shokai/EventEmitter.js
|
3
|
+
// (c) 2013 Sho Hashimoto <hashimoto@shokai.org>
|
4
|
+
// The MIT License
|
5
|
+
var EventEmitter = function(){
|
6
|
+
var self = this;
|
7
|
+
this.apply = function(target, prefix){
|
8
|
+
if(!prefix) prefix = "";
|
9
|
+
for(var func in self){
|
10
|
+
if(self.hasOwnProperty(func)){
|
11
|
+
target[prefix+func] = this[func];
|
12
|
+
}
|
13
|
+
}
|
14
|
+
};
|
15
|
+
this.__events = new Array();
|
16
|
+
this.on = function(type, listener, opts){
|
17
|
+
if(typeof listener !== "function") return;
|
18
|
+
var event_id = self.__events.length > 0 ? 1 + self.__events[self.__events.length-1].id : 0
|
19
|
+
var params = {
|
20
|
+
id: event_id,
|
21
|
+
type: type,
|
22
|
+
listener: listener
|
23
|
+
};
|
24
|
+
for(i in opts){
|
25
|
+
if(!params[i]) params[i] = opts[i];
|
26
|
+
};
|
27
|
+
self.__events.push(params);
|
28
|
+
return event_id;
|
29
|
+
};
|
30
|
+
|
31
|
+
this.once = function(type, listener){
|
32
|
+
self.on(type, listener, {once: true});
|
33
|
+
};
|
34
|
+
|
35
|
+
this.emit = function(type, data){
|
36
|
+
for(var i = 0; i < self.__events.length; i++){
|
37
|
+
var e = self.__events[i];
|
38
|
+
switch(e.type){
|
39
|
+
case type:
|
40
|
+
e.listener(data);
|
41
|
+
break
|
42
|
+
case '*':
|
43
|
+
e.listener(type, data);
|
44
|
+
break
|
45
|
+
}
|
46
|
+
if(e.once) self.removeListener(e.id);
|
47
|
+
}
|
48
|
+
};
|
49
|
+
|
50
|
+
this.removeListener = function(id_or_type){
|
51
|
+
for(var i = self.__events.length-1; i >= 0; i--){
|
52
|
+
var e = self.__events[i];
|
53
|
+
switch(typeof id_or_type){
|
54
|
+
case "number":
|
55
|
+
if(e.id == id_or_type) self.__events.splice(i,1);
|
56
|
+
break
|
57
|
+
case "string":
|
58
|
+
if(e.type == id_or_type) self.__events.splice(i,1);
|
59
|
+
break
|
60
|
+
}
|
61
|
+
}
|
62
|
+
};
|
63
|
+
|
64
|
+
};
|
65
|
+
|
66
|
+
if(typeof module !== 'undefined' && typeof module.exports !== 'undefined'){
|
67
|
+
module.exports = EventEmitter;
|
68
|
+
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
var WebSocketIO = function(){
|
2
|
+
new EventEmitter().apply(this);
|
3
|
+
this.url = "<%= websocketio_url %>";
|
4
|
+
this.session = null;
|
5
|
+
this.websocket = null;
|
6
|
+
this.connecting = false;
|
7
|
+
var reconnect_timer_id = null;
|
8
|
+
var running = false;
|
9
|
+
var self = this;
|
10
|
+
|
11
|
+
self.on("__session_id", function(session_id){
|
12
|
+
self.session = session_id;
|
13
|
+
self.emit("connect", self.session);
|
14
|
+
});
|
15
|
+
|
16
|
+
this.connect = function(){
|
17
|
+
if(typeof WebSocket === 'undefined'){
|
18
|
+
self.emit("error", "websocket not exists");
|
19
|
+
return null;
|
20
|
+
}
|
21
|
+
self.running = true;
|
22
|
+
var url = self.session ? self.url+'/session='+self.session : self.url;
|
23
|
+
self.websocket = new WebSocket(url);
|
24
|
+
self.websocket.onmessage = function(e){
|
25
|
+
try{
|
26
|
+
var data_ = JSON.parse(e.data);
|
27
|
+
self.emit(data_.type, data_.data);
|
28
|
+
}
|
29
|
+
catch(e){
|
30
|
+
self.emit("error", "WebSocketIO get error");
|
31
|
+
}
|
32
|
+
};
|
33
|
+
self.websocket.onclose = function(){
|
34
|
+
if(self.connecting) self.emit("disconnect");
|
35
|
+
self.connecting = false;
|
36
|
+
if(self.running){
|
37
|
+
reconnect_timer_id = setTimeout(self.connect, 10000);
|
38
|
+
}
|
39
|
+
};
|
40
|
+
self.websocket.onopen = function(){
|
41
|
+
self.connecting = true;
|
42
|
+
};
|
43
|
+
return self;
|
44
|
+
};
|
45
|
+
|
46
|
+
this.close = function(){
|
47
|
+
clearTimeout(reconnect_timer_id);
|
48
|
+
self.running = false;
|
49
|
+
self.websocket.close();
|
50
|
+
};
|
51
|
+
|
52
|
+
this.push = function(type, data){
|
53
|
+
self.websocket.send(JSON.stringify({type: type, data: data, session: self.session}));
|
54
|
+
};
|
55
|
+
};
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'em-websocket'
|
3
|
+
require 'json'
|
4
|
+
require 'digest/md5'
|
5
|
+
require 'event_emitter'
|
6
|
+
require 'sinatra/streaming'
|
7
|
+
require File.expand_path '../sinatra-websocketio/version', File.dirname(__FILE__)
|
8
|
+
require File.expand_path '../sinatra-websocketio/websocketio', File.dirname(__FILE__)
|
9
|
+
require File.expand_path '../sinatra-websocketio/application', File.dirname(__FILE__)
|
10
|
+
|
11
|
+
Sinatra.register Sinatra::WebSocketIO
|
12
|
+
WebSocketIO.start
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
module Sinatra::WebSocketIO
|
3
|
+
|
4
|
+
helpers do
|
5
|
+
def websocketio_js
|
6
|
+
"#{env['rack.url_scheme']}://#{env['HTTP_HOST']}#{env['SCRIPT_NAME']}/websocketio/websocketio.js"
|
7
|
+
end
|
8
|
+
|
9
|
+
def websocketio_url
|
10
|
+
"ws://#{env['SERVER_NAME']}:#{WebSocketIO.port}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
get '/websocketio/websocketio.js' do
|
15
|
+
content_type 'application/javascript'
|
16
|
+
@js ||= (
|
17
|
+
js = ''
|
18
|
+
Dir.glob(File.expand_path '../js/*.js', File.dirname(__FILE__)).each do |i|
|
19
|
+
File.open(i) do |f|
|
20
|
+
js += f.read
|
21
|
+
end
|
22
|
+
end
|
23
|
+
ERB.new(js).result(binding)
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class WebSocketIO
|
2
|
+
|
3
|
+
def self.port
|
4
|
+
@@port ||= 8080
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.start(port=8080)
|
8
|
+
@@port = port
|
9
|
+
EM::defer do
|
10
|
+
while !EM::reactor_running? do
|
11
|
+
sleep 1
|
12
|
+
end
|
13
|
+
puts "WebSocketIO.start port:#{port}"
|
14
|
+
EM::WebSocket.run :host => "0.0.0.0", :port => port do |ws|
|
15
|
+
ws.onopen do |handshake|
|
16
|
+
params = parse_handshake_params handshake.path
|
17
|
+
session_id = params[:session] || (create_session Socket.unpack_sockaddr_in ws.get_peername)
|
18
|
+
self.sessions[session_id] = {
|
19
|
+
:websocket => ws
|
20
|
+
}
|
21
|
+
ws.onclose do
|
22
|
+
self.emit :disconnect, session_id
|
23
|
+
end
|
24
|
+
ws.onmessage do |msg|
|
25
|
+
begin
|
26
|
+
data = JSON.parse msg
|
27
|
+
rescue => e
|
28
|
+
self.emit :error, e
|
29
|
+
end
|
30
|
+
self.emit data['type'], data['data'], session_id if data
|
31
|
+
end
|
32
|
+
ws.send({:type => :__session_id, :data => session_id}.to_json)
|
33
|
+
self.emit :connect, session_id
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.push(type, data, opt={})
|
40
|
+
session_ids = opt[:to].to_s.empty? ? self.sessions.keys : [opt[:to]]
|
41
|
+
session_ids.each do |id|
|
42
|
+
s = sessions[id]
|
43
|
+
begin
|
44
|
+
s[:websocket].send({:type => type, :data => data}.to_json)
|
45
|
+
rescue
|
46
|
+
next
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.sessions
|
52
|
+
@@sessions ||= Hash.new{|h,session_id|
|
53
|
+
h[session_id] = {
|
54
|
+
:websocket => nil
|
55
|
+
}
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.create_session(ip_addr)
|
60
|
+
Digest::MD5.hexdigest "#{Time.now.to_i}_#{Time.now.usec}_#{ip_addr}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.parse_handshake_params(path)
|
64
|
+
tmp = path.gsub(/^\//,'').split(/\=+/)
|
65
|
+
params = {}
|
66
|
+
while !tmp.empty?
|
67
|
+
params[tmp.shift.to_sym] = tmp.shift
|
68
|
+
end
|
69
|
+
params
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
EventEmitter.apply WebSocketIO
|
74
|
+
|
75
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
require "sinatra-websocketio/version"
|
data/sample/Gemfile
ADDED
data/sample/Gemfile.lock
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
backports (3.0.3)
|
5
|
+
daemons (1.1.9)
|
6
|
+
em-websocket (0.5.0)
|
7
|
+
eventmachine (>= 0.12.9)
|
8
|
+
http_parser.rb (~> 0.5.3)
|
9
|
+
event_emitter (0.2.3)
|
10
|
+
eventmachine (1.0.1)
|
11
|
+
foreman (0.61.0)
|
12
|
+
thor (>= 0.13.6)
|
13
|
+
haml (4.0.0)
|
14
|
+
tilt
|
15
|
+
http_parser.rb (0.5.3)
|
16
|
+
json (1.7.7)
|
17
|
+
rack (1.5.2)
|
18
|
+
rack-protection (1.4.0)
|
19
|
+
rack
|
20
|
+
rack-test (0.6.2)
|
21
|
+
rack (>= 1.0)
|
22
|
+
sass (3.2.6)
|
23
|
+
sinatra (1.3.5)
|
24
|
+
rack (~> 1.4)
|
25
|
+
rack-protection (~> 1.3)
|
26
|
+
tilt (~> 1.3, >= 1.3.3)
|
27
|
+
sinatra-contrib (1.3.2)
|
28
|
+
backports (>= 2.0)
|
29
|
+
eventmachine
|
30
|
+
rack-protection
|
31
|
+
rack-test
|
32
|
+
sinatra (~> 1.3.0)
|
33
|
+
tilt (~> 1.3)
|
34
|
+
thin (1.5.0)
|
35
|
+
daemons (>= 1.0.9)
|
36
|
+
eventmachine (>= 0.12.6)
|
37
|
+
rack (>= 1.0.0)
|
38
|
+
thor (0.17.0)
|
39
|
+
tilt (1.3.4)
|
40
|
+
|
41
|
+
PLATFORMS
|
42
|
+
ruby
|
43
|
+
|
44
|
+
DEPENDENCIES
|
45
|
+
backports (< 3.1.0)
|
46
|
+
em-websocket
|
47
|
+
event_emitter
|
48
|
+
foreman
|
49
|
+
haml
|
50
|
+
json
|
51
|
+
rack
|
52
|
+
sass
|
53
|
+
sinatra
|
54
|
+
sinatra-contrib
|
55
|
+
thin
|
data/sample/Procfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
web: bundle exec rackup config.ru -p $PORT
|
data/sample/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
WebSocket Chat
|
2
|
+
==============
|
3
|
+
|
4
|
+
* Ruby 1.8.7+ or 1.9.2+
|
5
|
+
* sinatra-websocketio with Sinatra1.3+
|
6
|
+
|
7
|
+
|
8
|
+
Install Dependencies
|
9
|
+
--------------------
|
10
|
+
|
11
|
+
% gem install bundler foreman
|
12
|
+
% bundle install
|
13
|
+
|
14
|
+
|
15
|
+
Run
|
16
|
+
---
|
17
|
+
|
18
|
+
% foreman start
|
19
|
+
|
20
|
+
=> http://localhost:5000
|
21
|
+
|
22
|
+
|
23
|
+
Deploy Heroku
|
24
|
+
-------------
|
25
|
+
|
26
|
+
% mkdir ~/websocketio-sample
|
27
|
+
% cp -R ./ ~/websocketio-sample/
|
28
|
+
% cd ~/websocketio-sample
|
29
|
+
% git init
|
30
|
+
% git add ./
|
31
|
+
% git commit -m "first sample chat"
|
32
|
+
% heroku create --stack cedar
|
33
|
+
% git push heroku master
|
34
|
+
% heroku open
|
data/sample/config.ru
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
Bundler.require
|
4
|
+
if development?
|
5
|
+
$stdout.sync = true
|
6
|
+
require 'sinatra/reloader'
|
7
|
+
$:.unshift File.expand_path '../lib', File.dirname(__FILE__)
|
8
|
+
end
|
9
|
+
require 'eventmachine'
|
10
|
+
require 'sinatra/websocketio'
|
11
|
+
require File.dirname(__FILE__)+'/main'
|
12
|
+
|
13
|
+
set :haml, :escape_html => true
|
14
|
+
|
15
|
+
run Sinatra::Application
|
data/sample/main.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
WebSocketIO.on :connect do |session|
|
2
|
+
puts "new client <#{session}>"
|
3
|
+
WebSocketIO.push :chat, {:name => "system", :message => "new client <#{session}>"}
|
4
|
+
WebSocketIO.push :chat, {:name => "system", :message => "welcome <#{session}>"}, {:to => session}
|
5
|
+
end
|
6
|
+
|
7
|
+
WebSocketIO.on :disconnect do |session|
|
8
|
+
puts "disconnect client <#{session}>"
|
9
|
+
WebSocketIO.push :chat, {:name => "system", :message => "bye <#{session}>"}
|
10
|
+
end
|
11
|
+
|
12
|
+
WebSocketIO.on :chat do |data, from|
|
13
|
+
puts "#{data['name']} : #{data['message']} (from:#{from})"
|
14
|
+
WebSocketIO.push :chat, data
|
15
|
+
end
|
16
|
+
|
17
|
+
WebSocketIO.on :error do |err|
|
18
|
+
STDERR.puts "error!! #{err}"
|
19
|
+
end
|
20
|
+
|
21
|
+
get '/' do
|
22
|
+
haml :index
|
23
|
+
end
|
24
|
+
|
25
|
+
get '/:source.css' do
|
26
|
+
scss params[:source].to_sym
|
27
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
var io = new WebSocketIO().connect();
|
2
|
+
|
3
|
+
io.on("chat", function(data){
|
4
|
+
var m = $("<li>").text(data.name + " : " +data.message);
|
5
|
+
$("#chat #timeline").prepend(m);
|
6
|
+
});
|
7
|
+
|
8
|
+
io.on("connect", function(session){
|
9
|
+
console.log("connect!! "+session);
|
10
|
+
$("#chat #btn_send").click(post);
|
11
|
+
$("#chat #message").keydown(function(e){
|
12
|
+
if(e.keyCode == 13) post();
|
13
|
+
});
|
14
|
+
});
|
15
|
+
|
16
|
+
io.on("disconnect", function(session){
|
17
|
+
console.log("disconnect!!");
|
18
|
+
});
|
19
|
+
|
20
|
+
io.on("*", function(event, data){ // catch all events
|
21
|
+
console.log(event + " - " + JSON.stringify(data));
|
22
|
+
});
|
23
|
+
|
24
|
+
io.on("error", function(err){
|
25
|
+
console.error(err);
|
26
|
+
});
|
27
|
+
|
28
|
+
var post = function(){
|
29
|
+
var name = $("#chat #name").val();
|
30
|
+
var message = $("#chat #message").val();
|
31
|
+
if(message.length < 1) return;
|
32
|
+
io.push("chat", {name: name, message: message});
|
33
|
+
$("#chat #message").val("");
|
34
|
+
};
|
@@ -0,0 +1,26 @@
|
|
1
|
+
!!! XHTML
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%meta{'http-equiv' => 'Content-Type', :content => 'text/html', :charset => 'UTF-8'}
|
5
|
+
%title websocket chat
|
6
|
+
%link{:rel => 'stylesheet', :href => "/main.css", :type => 'text/css'}
|
7
|
+
%script{:type => 'text/javascript', :src => "//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"}
|
8
|
+
%script{:type => 'text/javascript', :src => websocketio_js}
|
9
|
+
%script{:type => 'text/javascript', :src => "/js/index.js"}
|
10
|
+
|
11
|
+
%body
|
12
|
+
%div#content
|
13
|
+
%div#header
|
14
|
+
%h1 websocket chat
|
15
|
+
%div#main
|
16
|
+
%div#chat
|
17
|
+
%input{:id => 'name', :value => 'name', :size => 20}
|
18
|
+
%input{:id => 'message', :value => 'hello!!', :size => 80}
|
19
|
+
%input{:id => 'btn_send', :type => 'button', :value => 'post'}
|
20
|
+
%ul#timeline
|
21
|
+
|
22
|
+
%hr
|
23
|
+
%div#footer
|
24
|
+
sinatra-cometio v#{Sinatra::WebSocketIO::VERSION} -
|
25
|
+
- src_url = 'https://github.com/shokai/sinatra-cometio'
|
26
|
+
%a{:href => src_url} #{src_url}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'sinatra-websocketio/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = "sinatra-websocketio"
|
7
|
+
gem.version = Sinatra::WebSocketIO::VERSION
|
8
|
+
gem.authors = ["Sho Hashimoto"]
|
9
|
+
gem.email = ["hashimoto@shokai.org"]
|
10
|
+
gem.description = %q{Node.js like WebSocket I/O plugin for Sinatra.}
|
11
|
+
gem.summary = gem.description
|
12
|
+
gem.homepage = "http://shokai.github.com/sinatra-websocketio"
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split($/).reject{|i| i=="Gemfile.lock" }
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
gem.add_dependency 'rack'
|
19
|
+
gem.add_dependency 'sinatra', '>= 1.3.3'
|
20
|
+
gem.add_dependency 'eventmachine', '>= 1.0.0'
|
21
|
+
gem.add_dependency 'sinatra-contrib', '>= 1.3.2'
|
22
|
+
gem.add_dependency 'json', '>= 1.7.0'
|
23
|
+
gem.add_dependency 'event_emitter', '>= 0.2.0'
|
24
|
+
gem.add_dependency 'em-websocket'
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sinatra-websocketio
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sho Hashimoto
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rack
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: sinatra
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.3.3
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.3.3
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: eventmachine
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.0.0
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.0.0
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: sinatra-contrib
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.3.2
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.3.2
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: json
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.7.0
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.7.0
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: event_emitter
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 0.2.0
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 0.2.0
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: em-websocket
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
description: Node.js like WebSocket I/O plugin for Sinatra.
|
127
|
+
email:
|
128
|
+
- hashimoto@shokai.org
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- .gitignore
|
134
|
+
- Gemfile
|
135
|
+
- History.txt
|
136
|
+
- LICENSE.txt
|
137
|
+
- README.md
|
138
|
+
- Rakefile
|
139
|
+
- lib/js/event_emitter.js
|
140
|
+
- lib/js/websocketio.js
|
141
|
+
- lib/sinatra-websocketio.rb
|
142
|
+
- lib/sinatra-websocketio/application.rb
|
143
|
+
- lib/sinatra-websocketio/version.rb
|
144
|
+
- lib/sinatra-websocketio/websocketio.rb
|
145
|
+
- lib/sinatra/websocketio.rb
|
146
|
+
- sample/Gemfile
|
147
|
+
- sample/Gemfile.lock
|
148
|
+
- sample/Procfile
|
149
|
+
- sample/README.md
|
150
|
+
- sample/config.ru
|
151
|
+
- sample/main.rb
|
152
|
+
- sample/public/js/index.js
|
153
|
+
- sample/views/index.haml
|
154
|
+
- sample/views/main.scss
|
155
|
+
- sinatra-websocketio.gemspec
|
156
|
+
homepage: http://shokai.github.com/sinatra-websocketio
|
157
|
+
licenses: []
|
158
|
+
post_install_message:
|
159
|
+
rdoc_options: []
|
160
|
+
require_paths:
|
161
|
+
- lib
|
162
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
163
|
+
none: false
|
164
|
+
requirements:
|
165
|
+
- - ! '>='
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
requirements: []
|
175
|
+
rubyforge_project:
|
176
|
+
rubygems_version: 1.8.24
|
177
|
+
signing_key:
|
178
|
+
specification_version: 3
|
179
|
+
summary: Node.js like WebSocket I/O plugin for Sinatra.
|
180
|
+
test_files: []
|