angelo 0.1.3 → 0.1.4
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.
- 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:
|