Class: Strelka::WebSocketServer
- Inherits:
-
Mongrel2::Handler
- Object
- Mongrel2::Handler
- Strelka::WebSocketServer
- Extended by:
- Discovery, MethodUtilities, PluginLoader
- Defined in:
- lib/strelka/websocketserver.rb
Overview
WebSocket (RFC 6455) Server base class.
class ChatServer < Strelka::WebSocketServer
# Set up a Hash for participating users
def initialize( * )
super
@users = {}
end
# Disconnect clients that don't answer a ping
plugin :heartbeat
heartbeat_rate 5.0
idle_timeout 15.0
# When a websocket is set up, add a new user to the table, but without a nick.
def handle_websocket_handshake( request )
@users[ request.socket_id ] = nil
return request.response # accept the connection
end
plugin :routing
# Handle incoming commands, which should be text frames
on_text do |request|
senderid = request.socket_id
data = request.payload.read
# If the input starts with '/', it's a command (e.g., /quit, /nick, etc.)
output = nil
if data.start_with?( '/' )
output = self.command( senderid, data[1..-1] )
else
output = self.say( senderid, data )
end
response = request.response
response.puts( output )
return response
end
end # class ChatServer
Defined Under Namespace
Instance Attribute Summary collapse
-
#connection_times ⇒ Object
readonly
A Hash of [sender ID, connection ID] keys => connection Times.
-
#connections ⇒ Object
readonly
A Hash of sender ID => Set of connection IDs.
Attributes included from PluginLoader
#loaded_plugins, #plugin_path_prefix, #plugins_installed_from
Class Method Summary collapse
-
.default_app_instance ⇒ Object
Return an instance of the App configured for the handler in the currently-loaded Mongrel2 config that corresponds to the #default_appid.
-
.default_appid ⇒ Object
Calculate a default application ID for the class based on either its ID constant or its name and return it.
-
.run(appid = nil) ⇒ Object
Overridden from Mongrel2::Handler – use the value returned from .default_appid if one is not specified.
Instance Method Summary collapse
-
#broadcast(frame, except: nil) ⇒ Object
Send the specified
frameto all current connections, except those listed inexcept. -
#handle_disconnect(request) ⇒ Object
Handle a disconnect notice from Mongrel2 via the given
request. -
#handle_websocket(request) ⇒ Object
Handle a WebSocket frame in
request. -
#handle_websocket_handshake(handshake) ⇒ Object
Handle a WebSocket handshake HTTP
request. -
#initialize ⇒ WebSocketServer
constructor
Dump the application stack when a new instance is created.
-
#last_connection_time(request) ⇒ Object
Return the Time of the last frame from the client associated with the given
request. -
#run ⇒ Object
Run the app – overriden to set the process name to something interesting.
Methods included from Discovery
add_inherited_class, app_discovery_files, discover_data_dirs, discovered_apps, discovered_classes, inherited, load, load_file, loading_file, loading_file, register_app, register_apps
Methods included from MethodUtilities
attr_predicate, attr_predicate_accessor, singleton_attr_accessor, singleton_attr_reader, singleton_attr_writer, singleton_method_alias, singleton_predicate_accessor, singleton_predicate_reader
Methods included from PluginLoader
application_stack, dump_application_stack, extended, inherited, install_plugins, load_plugin, new, plugins, plugins_installed?, register_plugin
Constructor Details
#initialize ⇒ WebSocketServer
Dump the application stack when a new instance is created.
111 112 113 114 115 116 117 118 |
# File 'lib/strelka/websocketserver.rb', line 111 def initialize( * ) self.class.dump_application_stack @connections = Hash.new {|h, k| h[k] = Set.new } @connection_times = Hash.new {|h, k| h[k] = Hash.new } super end |
Instance Attribute Details
#connection_times ⇒ Object (readonly)
A Hash of [sender ID, connection ID] keys => connection Times
131 132 133 |
# File 'lib/strelka/websocketserver.rb', line 131 def connection_times @connection_times end |
#connections ⇒ Object (readonly)
A Hash of sender ID => Set of connection IDs.
127 128 129 |
# File 'lib/strelka/websocketserver.rb', line 127 def connections @connections end |
Class Method Details
.default_app_instance ⇒ Object
Return an instance of the App configured for the handler in the currently-loaded Mongrel2 config that corresponds to the #default_appid.
99 100 101 102 |
# File 'lib/strelka/websocketserver.rb', line 99 def self::default_app_instance appid = self.default_appid return self.app_instance_for( appid ) end |
.default_appid ⇒ Object
Calculate a default application ID for the class based on either its ID constant or its name and return it.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/strelka/websocketserver.rb', line 80 def self::default_appid self.log.info "Looking up appid for %p" % [ self.class ] appid = nil if self.const_defined?( :ID ) appid = self.const_get( :ID ) self.log.info " app has an ID: %p" % [ appid ] else appid = ( self.name || "anonymous#{self.object_id}" ).downcase appid.gsub!( /[^[:alnum:]]+/, '-' ) self.log.info " deriving one from the class name: %p" % [ appid ] end return appid end |
.run(appid = nil) ⇒ Object
Overridden from Mongrel2::Handler – use the value returned from .default_appid if one is not specified.
71 72 73 74 75 |
# File 'lib/strelka/websocketserver.rb', line 71 def self::run( appid=nil ) appid ||= self.default_appid self.log.info "Starting up with appid %p." % [ appid ] super( appid ) end |
Instance Method Details
#broadcast(frame, except: nil) ⇒ Object
Send the specified frame to all current connections, except those listed in except. The except argument is a single [sender_id, conn_id] tuple.
195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/strelka/websocketserver.rb', line 195 def broadcast( frame, except: nil ) self.connections.each do |sender_id, conn_ids| id_list = conn_ids.to_a. reject {|cid| except&.first == sender_id && except&.last == cid } self.log.debug "Broadcasting to %d connections for sender %s" % [ conn_ids.length, sender_id ] self.conn.broadcast( sender_id, id_list, frame.to_s ) end end |
#handle_disconnect(request) ⇒ Object
Handle a disconnect notice from Mongrel2 via the given request. Its return value is ignored.
175 176 177 178 179 180 181 182 |
# File 'lib/strelka/websocketserver.rb', line 175 def handle_disconnect( request ) self.log.info "Connection %d closed." % [ request.conn_id ] self.connection_times[ request.sender_id ].delete( request.conn_id ) self.connections.delete( request.sender_id ) self.log.debug " connections remaining: %p" % [ self.connections ] return nil end |
#handle_websocket(request) ⇒ Object
Handle a WebSocket frame in request. If not overridden, WebSocket connections are closed with a policy error status.
146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/strelka/websocketserver.rb', line 146 def handle_websocket( request ) response = nil self.connection_times[ request.sender_id ][ request.conn_id ] = Time.now # Dispatch the request response = catch( :close_websocket ) do self.log.debug "Incoming WEBSOCKET request (%p):%s" % [ request, request.headers.path ] self.handle_websocket_request( request ) end return response end |
#handle_websocket_handshake(handshake) ⇒ Object
Handle a WebSocket handshake HTTP request. :TODO: Register/check for supported Sec-WebSocket-Protocol.
163 164 165 166 167 168 169 170 |
# File 'lib/strelka/websocketserver.rb', line 163 def handle_websocket_handshake( handshake ) self.log.info "Incoming WEBSOCKET_HANDSHAKE request (%p)" % [ handshake.headers.path ] self.connections[ handshake.sender_id ].add( handshake.conn_id ) self.connection_times[ handshake.sender_id ][ handshake.conn_id ] = Time.now self.log.debug " connections: %p" % [ self.connections ] return handshake.response( handshake.protocols.first ) end |
#last_connection_time(request) ⇒ Object
Return the Time of the last frame from the client associated with the given request.
187 188 189 190 |
# File 'lib/strelka/websocketserver.rb', line 187 def last_connection_time( request ) table = self.connection_times[ request.sender_id ] or return nil return table[ request.conn_id ] end |
#run ⇒ Object
Run the app – overriden to set the process name to something interesting.
136 137 138 139 140 141 |
# File 'lib/strelka/websocketserver.rb', line 136 def run procname = "%s %s: %p %s" % [ RUBY_ENGINE, RUBY_VERSION, self.class, self.conn ] $0 = procname super end |