lib/angelo/base.rb in angelo-0.1.3 vs lib/angelo/base.rb in angelo-0.1.4
- old
+ new
@@ -8,11 +8,13 @@
def_delegators :@responder, :content_type, :headers, :request
@@addr = DEFAULT_ADDR
@@port = DEFAULT_PORT
- if ARGV.any?
+ @@ping_time = DEFAULT_PING_TIME
+
+ if ARGV.any? and not Kernel.const_defined?('RSpec')
require 'optparse'
OptionParser.new { |op|
op.on('-p port', 'set the port (default is 4567)') { |val| @@port = Integer(val) }
op.on('-o addr', "set the host (default is #{@@addr})") { |val| @@addr = val }
}.parse!(ARGV.dup)
@@ -20,11 +22,11 @@
attr_accessor :responder
class << self
- attr_accessor :app_file
+ attr_accessor :app_file, :server
def inherited subclass
subclass.app_file = caller(1).map {|l| l.split(/:(?=|in )/, 3)[0,1]}.flatten[0]
def subclass.root
@@ -74,56 +76,114 @@
def socket path, &block
routes[:socket][path] = WebsocketResponder.new &block
end
+ def on_pong &block
+ WebsocketResponder.on_pong = block
+ end
+
+ def async name, &block
+ Angelo::Server.define_action name, &block
+ end
+
def websockets
- @websockets ||= WebsocketsArray.new
+ @websockets ||= WebsocketsArray.new server
@websockets.reject! &:closed?
@websockets
end
def content_type type
Responder.content_type type
end
def run addr = @@addr, port = @@port
@server = Angelo::Server.new self, addr, port
+ @server.async.ping_websockets
trap "INT" do
@server.terminate if @server and @server.alive?
exit
end
sleep
end
end
+ def async meth, *args
+ self.class.server.async.__send__ meth, *args
+ end
+
def params
@params ||= case request.method
when GET; parse_query_string
when POST; parse_post_body
when PUT; parse_post_body
end
end
def websockets; self.class.websockets; end
+ async :handle_websocket do |ws|
+ begin
+ while !ws.closed? do
+ ws.read
+ end
+ rescue IOError
+ websockets.remove_socket ws
+ end
+ end
+
+ async :ping_websockets do
+ every(@@ping_time) do
+ websockets.each do |ws|
+ ws.socket << ::WebSocket::Message.ping.to_data
+ end
+ end
+ end
+
class WebsocketsArray < Array
+ include Celluloid::Logger
+ @@peeraddrs = {}
+ @@socket_context = {}
+
+ def initialize server, context = nil
+ @context, @server = context, server
+ super()
+ end
+
+ def << ws
+ @@socket_context[ws] = @context if @context
+ @@peeraddrs[ws] = ws.peeraddr
+ @server.async.handle_websocket ws
+ super ws
+ end
+
def each &block
super do |ws|
begin
yield ws
- rescue Reel::SocketError => rse
- warn "#{rse.class} - #{rse.message}"
- delete ws
+ rescue Reel::SocketError
+ remove_socket ws
end
end
end
+ def remove_socket ws
+ if c = @@socket_context[ws]
+ warn "removing socket from context ':#{c}' (#{@@peeraddrs[ws][2]})"
+ self[c].delete ws
+ else
+ warn "removing socket (#{@@peeraddrs[ws][2]})"
+ delete ws
+ end
+ @@peeraddrs.delete ws
+ end
+
def [] context
+ raise ArgumentError.new "symbol required" unless Symbol === context
@@websockets ||= {}
- @@websockets[context] ||= self.class.new
+ @@websockets[context] ||= self.class.new @server, context
end
end
end