angelo 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +24 -2
- data/lib/angelo.rb +2 -0
- data/lib/angelo/base.rb +67 -7
- data/lib/angelo/responder/websocket.rb +11 -0
- data/lib/angelo/rspec/helpers.rb +3 -1
- data/lib/angelo/server.rb +11 -0
- data/lib/angelo/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b034c03ba6c0b50e1d31e5ee1c0bd043b70d8d2e
|
4
|
+
data.tar.gz: b4e9ba5af2b009a7fa292f97d6a8b2a3831ec709
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64b482cc286556b98b03f211134bed314d2c3b3564640aca4b9d2882d4b31d157760d7ef476d7fcb257d3065152f38c4573a24226d3de19f1309136c9a3f8730
|
7
|
+
data.tar.gz: 000d06333538e664c71d40e6f0371d6d946c586efe2f1cb3dd42c08d510cb459faa772cacef57c3135315609f85387c70bc147cd0a26f16e8cb0eb8c62e1c632
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -9,7 +9,8 @@ A [Sinatra](https://github.com/sinatra/sinatra)-esque DSL for [Reel](https://git
|
|
9
9
|
|
10
10
|
* "easy" websocket support via `socket '/path' do |s|` route handler
|
11
11
|
* "easy" websocket stashing via `websockets` helper
|
12
|
-
*
|
12
|
+
* "easy" event handling via `async` helpers
|
13
|
+
* no rack
|
13
14
|
* optional tilt/erb support
|
14
15
|
* optional mustermann support
|
15
16
|
|
@@ -24,6 +25,9 @@ class Foo < Angelo::Base
|
|
24
25
|
|
25
26
|
TEST = {foo: "bar", baz: 123, bat: false}.to_json
|
26
27
|
|
28
|
+
HEART = '<3'
|
29
|
+
@@hearting = false
|
30
|
+
|
27
31
|
def pong; 'pong'; end
|
28
32
|
def foo; params[:foo]; end
|
29
33
|
|
@@ -46,7 +50,7 @@ class Foo < Angelo::Base
|
|
46
50
|
|
47
51
|
socket '/ws' do |ws|
|
48
52
|
websockets[:emit_test] << ws
|
49
|
-
|
53
|
+
ws.on_message do |msg|
|
50
54
|
5.times { ws.write TEST }
|
51
55
|
ws.write foo.to_json
|
52
56
|
end
|
@@ -60,6 +64,24 @@ class Foo < Angelo::Base
|
|
60
64
|
websockets[:other] << ws
|
61
65
|
end
|
62
66
|
|
67
|
+
socket '/hearts' do |ws|
|
68
|
+
|
69
|
+
# this is a call to Base#async, actually calling
|
70
|
+
# the reactor to start the task
|
71
|
+
#
|
72
|
+
async :hearts unless @@hearting
|
73
|
+
|
74
|
+
websockets[:hearts] << ws
|
75
|
+
end
|
76
|
+
|
77
|
+
# this is a call to Base.async, defining the task
|
78
|
+
# to perform on the reactor
|
79
|
+
#
|
80
|
+
async :hearts do
|
81
|
+
@@hearting = true
|
82
|
+
every(10){ websockets[:hearts].each {|ws| ws.write HEART } }
|
83
|
+
end
|
84
|
+
|
63
85
|
end
|
64
86
|
|
65
87
|
Foo.run
|
data/lib/angelo.rb
CHANGED
data/lib/angelo/base.rb
CHANGED
@@ -10,7 +10,9 @@ module Angelo
|
|
10
10
|
@@addr = DEFAULT_ADDR
|
11
11
|
@@port = DEFAULT_PORT
|
12
12
|
|
13
|
-
|
13
|
+
@@ping_time = DEFAULT_PING_TIME
|
14
|
+
|
15
|
+
if ARGV.any? and not Kernel.const_defined?('RSpec')
|
14
16
|
require 'optparse'
|
15
17
|
OptionParser.new { |op|
|
16
18
|
op.on('-p port', 'set the port (default is 4567)') { |val| @@port = Integer(val) }
|
@@ -22,7 +24,7 @@ module Angelo
|
|
22
24
|
|
23
25
|
class << self
|
24
26
|
|
25
|
-
attr_accessor :app_file
|
27
|
+
attr_accessor :app_file, :server
|
26
28
|
|
27
29
|
def inherited subclass
|
28
30
|
subclass.app_file = caller(1).map {|l| l.split(/:(?=|in )/, 3)[0,1]}.flatten[0]
|
@@ -76,8 +78,16 @@ module Angelo
|
|
76
78
|
routes[:socket][path] = WebsocketResponder.new &block
|
77
79
|
end
|
78
80
|
|
81
|
+
def on_pong &block
|
82
|
+
WebsocketResponder.on_pong = block
|
83
|
+
end
|
84
|
+
|
85
|
+
def async name, &block
|
86
|
+
Angelo::Server.define_action name, &block
|
87
|
+
end
|
88
|
+
|
79
89
|
def websockets
|
80
|
-
@websockets ||= WebsocketsArray.new
|
90
|
+
@websockets ||= WebsocketsArray.new server
|
81
91
|
@websockets.reject! &:closed?
|
82
92
|
@websockets
|
83
93
|
end
|
@@ -88,6 +98,7 @@ module Angelo
|
|
88
98
|
|
89
99
|
def run addr = @@addr, port = @@port
|
90
100
|
@server = Angelo::Server.new self, addr, port
|
101
|
+
@server.async.ping_websockets
|
91
102
|
trap "INT" do
|
92
103
|
@server.terminate if @server and @server.alive?
|
93
104
|
exit
|
@@ -97,6 +108,10 @@ module Angelo
|
|
97
108
|
|
98
109
|
end
|
99
110
|
|
111
|
+
def async meth, *args
|
112
|
+
self.class.server.async.__send__ meth, *args
|
113
|
+
end
|
114
|
+
|
100
115
|
def params
|
101
116
|
@params ||= case request.method
|
102
117
|
when GET; parse_query_string
|
@@ -107,22 +122,67 @@ module Angelo
|
|
107
122
|
|
108
123
|
def websockets; self.class.websockets; end
|
109
124
|
|
125
|
+
async :handle_websocket do |ws|
|
126
|
+
begin
|
127
|
+
while !ws.closed? do
|
128
|
+
ws.read
|
129
|
+
end
|
130
|
+
rescue IOError
|
131
|
+
websockets.remove_socket ws
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
async :ping_websockets do
|
136
|
+
every(@@ping_time) do
|
137
|
+
websockets.each do |ws|
|
138
|
+
ws.socket << ::WebSocket::Message.ping.to_data
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
110
143
|
class WebsocketsArray < Array
|
144
|
+
include Celluloid::Logger
|
145
|
+
|
146
|
+
@@peeraddrs = {}
|
147
|
+
@@socket_context = {}
|
148
|
+
|
149
|
+
def initialize server, context = nil
|
150
|
+
@context, @server = context, server
|
151
|
+
super()
|
152
|
+
end
|
153
|
+
|
154
|
+
def << ws
|
155
|
+
@@socket_context[ws] = @context if @context
|
156
|
+
@@peeraddrs[ws] = ws.peeraddr
|
157
|
+
@server.async.handle_websocket ws
|
158
|
+
super ws
|
159
|
+
end
|
111
160
|
|
112
161
|
def each &block
|
113
162
|
super do |ws|
|
114
163
|
begin
|
115
164
|
yield ws
|
116
|
-
rescue Reel::SocketError
|
117
|
-
|
118
|
-
delete ws
|
165
|
+
rescue Reel::SocketError
|
166
|
+
remove_socket ws
|
119
167
|
end
|
120
168
|
end
|
121
169
|
end
|
122
170
|
|
171
|
+
def remove_socket ws
|
172
|
+
if c = @@socket_context[ws]
|
173
|
+
warn "removing socket from context ':#{c}' (#{@@peeraddrs[ws][2]})"
|
174
|
+
self[c].delete ws
|
175
|
+
else
|
176
|
+
warn "removing socket (#{@@peeraddrs[ws][2]})"
|
177
|
+
delete ws
|
178
|
+
end
|
179
|
+
@@peeraddrs.delete ws
|
180
|
+
end
|
181
|
+
|
123
182
|
def [] context
|
183
|
+
raise ArgumentError.new "symbol required" unless Symbol === context
|
124
184
|
@@websockets ||= {}
|
125
|
-
@@websockets[context] ||= self.class.new
|
185
|
+
@@websockets[context] ||= self.class.new @server, context
|
126
186
|
end
|
127
187
|
|
128
188
|
end
|
@@ -2,6 +2,16 @@ module Angelo
|
|
2
2
|
|
3
3
|
class WebsocketResponder < Responder
|
4
4
|
|
5
|
+
class << self
|
6
|
+
|
7
|
+
attr_writer :on_pong
|
8
|
+
|
9
|
+
def on_pong
|
10
|
+
@on_pong ||= ->(e){}
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
5
15
|
def params
|
6
16
|
@params ||= parse_query_string
|
7
17
|
@params
|
@@ -19,6 +29,7 @@ module Angelo
|
|
19
29
|
if @response_handler
|
20
30
|
Angelo.log @connection, @request, @websocket, :switching_protocols
|
21
31
|
@bound_response_handler ||= @response_handler.bind @base
|
32
|
+
@websocket.on_pong &WebsocketResponder.on_pong
|
22
33
|
@bound_response_handler[@websocket]
|
23
34
|
else
|
24
35
|
raise NotImplementedError
|
data/lib/angelo/rspec/helpers.rb
CHANGED
@@ -6,7 +6,6 @@ module Angelo
|
|
6
6
|
module Helpers
|
7
7
|
|
8
8
|
HTTP_URL = 'http://%s:%d'
|
9
|
-
WS_URL = 'ws://%s:%d'
|
10
9
|
|
11
10
|
attr_reader :last_response
|
12
11
|
|
@@ -17,6 +16,7 @@ module Angelo
|
|
17
16
|
app.class_eval { content_type :html } # reset
|
18
17
|
app.class_eval &block
|
19
18
|
@server = Angelo::Server.new app
|
19
|
+
app.server = @server
|
20
20
|
$reactor = Reactor.new unless $reactor.alive?
|
21
21
|
end
|
22
22
|
|
@@ -82,6 +82,8 @@ module Angelo
|
|
82
82
|
def_delegator :@socket, :write
|
83
83
|
def_delegators :@driver, :binary, :close, :text
|
84
84
|
|
85
|
+
WS_URL = 'ws://%s:%d'
|
86
|
+
|
85
87
|
attr_reader :driver, :socket
|
86
88
|
attr_writer :addr, :port, :path, :on_close, :on_message, :on_open
|
87
89
|
|
data/lib/angelo/server.rb
CHANGED
@@ -4,8 +4,11 @@ require 'mime-types'
|
|
4
4
|
module Angelo
|
5
5
|
|
6
6
|
class Server < Reel::Server
|
7
|
+
extend Forwardable
|
7
8
|
include Celluloid::Logger
|
8
9
|
|
10
|
+
def_delegator :@base, :websockets
|
11
|
+
|
9
12
|
def initialize base, host = '127.0.0.1', port = 4567
|
10
13
|
@base = base
|
11
14
|
info "Angelo #{VERSION}"
|
@@ -22,6 +25,14 @@ module Angelo
|
|
22
25
|
# RubyProf.pause
|
23
26
|
end
|
24
27
|
|
28
|
+
def self.define_action name, &action
|
29
|
+
define_method name, &action
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.remove_action name
|
33
|
+
remove_method name
|
34
|
+
end
|
35
|
+
|
25
36
|
private
|
26
37
|
|
27
38
|
def dispatch! meth, connection, request
|
data/lib/angelo/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: angelo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kenichi Nakamura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: reel
|
@@ -113,3 +113,4 @@ test_files:
|
|
113
113
|
- spec/test_app_root/public/what.png
|
114
114
|
- spec/test_app_root/views/index.html.erb
|
115
115
|
- spec/test_app_root/views/layout.html.erb
|
116
|
+
has_rdoc:
|