Class: MainPlugin
- Inherits:
-
Plugin
- Object
- Plugin
- MainPlugin
- Defined in:
- plugins/main/main.rb
Overview
The MainPlugin is accessible as @plugins.main and just main
from other plugins.
MainPlugin provides mainly client setup and the following services:
-
The root html page, which includes the scripts and sets up client startup variables.
-
The url of the client as a HValue, including the anchor.
-
Accessible via
msg.session[:main][:location_href]
-
-
The local time of the client’s web browser as a HValue, as seconds since epoch.
-
Accessible via
msg.session[:main][:client_time]
-
-
Sequential loading. See #delayed_call
-
Provides the
#init_ui
event for plugins that respond to it.
Instance Method Summary collapse
-
#close ⇒ Object
Frees the ticket resource id of the “loading” gif image.
-
#delayed_call(msg, params) ⇒ nil
Interface for adding delayed calls.
-
#do_init_ui(msg) ⇒ Object
Enables the init_ui event.
-
#dont_init_ui(msg) ⇒ Object
Disables the init_ui event.
-
#end_polling(msg, ses) ⇒ Object
When nothing is delayed and the second poll has been made (init_ui called), sets the client to non-polling-mode, having only value synchronization trigger new requests.
-
#flush_delayed(msg, ses) ⇒ Object
Flushes commands in the :delayed_calls array.
-
#get(req, response, ses) ⇒ Object
Outputs the startup web page.
-
#idle(msg) ⇒ Object
Called on every request of an active, valid session.
- #index_deps_setup(msg) ⇒ Object
-
#init ⇒ Object
Binds configuration data as instance variables.
-
#init_ses(msg) ⇒ Object
New session initialization, called just once per session.
-
#open ⇒ Object
Opens and renders the index page template.
-
#post(req, res, ses) ⇒ Object
Returns the “hello/goodbye” session termination request.
-
#pound(msg) ⇒ Object
Returns pound url of browser (after the ‘#’ sign).
-
#render_index_html ⇒ Object
Index page renderer.
-
#restore_ses(msg) ⇒ Object
Called once when a session is restored or cloned using the cookie’s ses_key.
-
#start_polling(msg, ses) ⇒ Object
Starts polling mode.
-
#support_gzip(header) ⇒ Object
Inspects the http request header to decide if the browser supports gzip compressed responses.
-
#url(msg) ⇒ Object
Returns base url of browser (before the ‘#’ sign).
-
#url_responder(msg, location_href) ⇒ Object
The
#url_responder
gets called whenever the anchor (pound) of location.href changes.
Instance Method Details
#close ⇒ Object
Frees the ticket resource id of the “loading” gif image.
112 113 114 115 |
# File 'plugins/main/main.rb', line 112 def close super @plugins[:ticket].del_rsrc( @loading_gif_id ) end |
#delayed_call(msg, params) ⇒ nil
Interface for adding delayed calls
When adding a delayed call, use an Array to define a plugin/method with optional arguments that will be called on the next request. The client will call back immediately when a delayed call is pending. The first param of the method is a msg
. Don’t include the msg
of the current request in params, it will be inserted automatically for the delayed call.
It can also be used for loading sequences to the client, when using a String as the params
.
Format of params
for plugin callback:
- Array
- plugin_name, method_name, *args
Format of params
for javascript sequences:
- String
-
Javascript to send
Calls will be flushed per request with the following conditions:
-
At most four (4) delayed calls will be processed at a time
-
If the calls use more than 200ms combined, even less will be processed at a time
314 315 316 |
# File 'plugins/main/main.rb', line 314 def delayed_call( msg, params ) get_ses( msg )[:delayed_calls].push( params ) end |
#do_init_ui(msg) ⇒ Object
Enables the init_ui event.
356 357 358 |
# File 'plugins/main/main.rb', line 356 def do_init_ui( msg ) get_ses( msg )[:dont_init_ui] = false end |
#dont_init_ui(msg) ⇒ Object
Disables the init_ui event.
350 351 352 |
# File 'plugins/main/main.rb', line 350 def dont_init_ui( msg ) get_ses( msg )[:dont_init_ui] = true end |
#end_polling(msg, ses) ⇒ Object
When nothing is delayed and the second poll has been made (init_ui called), sets the client to non-polling-mode, having only value synchronization trigger new requests. On the client, SesWatcher forces the change by sending the client time periodically.
419 420 421 422 423 424 |
# File 'plugins/main/main.rb', line 419 def end_polling( msg, ses ) if ses[:poll_mode] == true msg.reply "COMM.Transporter.poll(0);" ses[:poll_mode] = false end end |
#flush_delayed(msg, ses) ⇒ Object
Flushes commands in the :delayed_calls array
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 |
# File 'plugins/main/main.rb', line 362 def flush_delayed( msg, ses ) ## Limits the amount of delayed calls to process to 4. ## Prevents the client from choking even when the server ## load is light. if ses[:delayed_calls].size < 4 call_count = ses[:delayed_calls].size else call_count = 4 end time_start = Time.now.to_f time_taken = 0.0 ## process delayed calls, until: ## - over 200ms of cpu time has been spent ## - the :delayed_calls -array is empty ## - call_count limit is reached until time_taken > 0.2 or ses[:delayed_calls].size == 0 or call_count == 0 # gets the next call delayed_call = ses[:delayed_calls].shift if RSence.args[:debug] puts "delayed_call: #{delayed_call.inspect}" end # strings are always javascript, used for segmenting client load if delayed_call.class == String msg.reply delayed_call # arrays are plugin calls elsif delayed_call.class == Array # ['plugin_name', 'method_name'] pairs call the named plugin:method with just msg if delayed_call.size == 2 (plugin_name,method_name) = delayed_call msg.run(plugin_name,method_name,msg) # if the array contains more items, they are used as additional method params else (plugin_name,method_name) = delayed_call[0..1] method_params = delayed_call[2..-1] msg.run(plugin_name,method_name,msg,*method_params) end end ## calculates time taken time_taken = Time.now.to_f - time_start call_count -= 1 end ## Sets the client into poll mode, unless the :delayed_calls -array is empty if ses[:boot] > 1 if ses[:delayed_calls].empty? end_polling( msg, ses ) else start_polling( msg, ses ) end end end |
#get(req, response, ses) ⇒ Object
Outputs the startup web page.
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'plugins/main/main.rb', line 146 def get( req, response, ses ) index_html = render_index_html response.status = 200 response['Content-Type'] = 'text/html; charset=UTF-8' response['Date'] = httime( Time.now ) response['Server'] = 'RSence' response['Cache-Control'] = 'no-cache' if support_gzip( req.header ) index_gzip = GZString.new('') gzwriter = Zlib::GzipWriter.new( index_gzip, 9 ) gzwriter.write( index_html ) gzwriter.close response['Content-Length'] = index_gzip.bytesize.to_s response['Content-Encoding'] = 'gzip' response.body = index_gzip else response['Content-Length'] = index_html.bytesize.to_s response.body = index_html end end |
#idle(msg) ⇒ Object
Called on every request of an active, valid session
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
# File 'plugins/main/main.rb', line 435 def idle(msg) ses = get_ses( msg ) if ses[:boot] == 0 boot0( msg, ses ) elsif ses[:boot] == 1 boot1( msg, ses ) elsif not ses[:delayed_calls].empty? flush_delayed( msg, ses ) elsif ses[:boot] > 1 end_polling( msg, ses ) end ## Increment the counter forever. ses[:boot] += 1 end |
#index_deps_setup(msg) ⇒ Object
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'plugins/main/main.rb', line 241 def index_deps_setup( msg ) ses = msg.session if not ses.has_key?( :deps ) # make an array of dependencies for this session, if not already done ses[:deps] = [] end compound_pkgs = RSence.config[:client_pkg][:compound_packages] boot_dep = @conf[:boot_lib] unless ses[:deps].include?( boot_dep ) if compound_pkgs.include?( boot_dep ) compound_pkgs[ boot_dep ].each do |pkg_name| ses[:deps].push( pkg_name ) msg.reply(%{jsLoader.loaded("#{pkg_name}");}) end end ses[:deps].push( boot_dep ) begin msg.reply(%{jsLoader.loaded("#{boot_dep}");}) rescue => e warn %{ses_id: #{msg.ses_id} failed to load boot_dep: "#{boot_dep}", because: #{e.inspect}} end if boot_dep == 'rsence' ses[:deps].push( 'std_widgets' ) msg.reply(%{jsLoader.loaded("std_widgets");}) end end @conf[:default_libs].each do |dep_lib| unless ses[:deps].include?( dep_lib ) if compound_pkgs.include?( dep_lib ) compound_pkgs[ dep_lib ].each do |pkg_name| ses[:deps].push( pkg_name ) msg.reply(%{jsLoader.loaded("#{pkg_name}");}) end end ses[:deps].push( dep_lib ) msg.reply(%{jsLoader.loaded("#{dep_lib}");}) end end end |
#init ⇒ Object
Binds configuration data as instance variables
94 95 96 97 98 99 100 101 102 |
# File 'plugins/main/main.rb', line 94 def init super @plugins.register_alias( :main, :index_html ) @randgen = RandGen.new( 40 ) ::RSence.config[:index_html][:instance] = self @conf = ::RSence.config[:index_html] @bconf = ::RSence.config[:broker_urls] @goodbye_uri = File.join(@bconf[:hello],'goodbye') end |
#init_ses(msg) ⇒ Object
New session initialization, called just once per session.
236 237 238 239 |
# File 'plugins/main/main.rb', line 236 def init_ses( msg ) super restore_ses( msg ) end |
#open ⇒ Object
Opens and renders the index page template
105 106 107 108 109 |
# File 'plugins/main/main.rb', line 105 def open super @index_html_src = file_read( ::RSence.config[:index_html][:index_tmpl] ) render_index_html end |
#post(req, res, ses) ⇒ Object
Returns the “hello/goodbye” session termination request
171 172 173 |
# File 'plugins/main/main.rb', line 171 def post( req, res, ses ) @plugins.sessions.expire_ses_by_req( req, res ) end |
#pound(msg) ⇒ Object
Returns pound url of browser (after the ‘#’ sign)
226 227 228 |
# File 'plugins/main/main.rb', line 226 def pound( msg ) get_ses( msg )[:url][1] end |
#render_index_html ⇒ Object
Index page renderer
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'plugins/main/main.rb', line 63 def render_index_html index_html = @index_html_src.clone client_rev = client_pkg.client_cache.client_rev deps_src = '' @conf[:deps].each do |dep| deps_src += %{<script src="#{dep}" type="text/javascript"></script>} end deps_src += %{<script src="__CLIENT_BASE__/js/#{@conf[:boot_lib]}.js"></script>} @conf[:default_libs].each do |dep| deps_src += %{<script src="__CLIENT_BASE__/js/#{dep}.js"></script>} end client_base = File.join(@bconf[:h],client_rev) index_html.gsub!( '__SCRIPT_DEPS__', deps_src ) index_html.gsub!( '__CLIENT_BASE__', client_base ) index_html.gsub!( '__DEFAULT_TITLE__', @conf[:title] ) index_html.gsub!( '__CLIENT_REV__', client_rev ) index_html.gsub!( '__CLIENT_HELLO__', @bconf[:hello] ) index_html.gsub!( '__NOSCRIPT__', @conf[:noscript] ) return index_html end |
#restore_ses(msg) ⇒ Object
Called once when a session is restored or cloned using the cookie’s ses_key
282 283 284 285 286 287 288 289 290 291 |
# File 'plugins/main/main.rb', line 282 def restore_ses( msg ) super index_deps_setup( msg ) ## Resets session data to defaults ses = get_ses( msg ) ses[:boot] = 0 ses[:url] = [nil,nil] ses[:delayed_calls] = [] ses[:poll_mode] = true end |
#start_polling(msg, ses) ⇒ Object
Starts polling mode.
427 428 429 430 431 432 |
# File 'plugins/main/main.rb', line 427 def start_polling( msg, ses ) if ses[:poll_mode] == false msg.reply( "COMM.Transporter.poll(#{::RSence.config[:transporter_conf][:client_poll_priority]});" ) ses[:poll_mode] = true end end |
#support_gzip(header) ⇒ Object
Inspects the http request header to decide if the browser supports gzip compressed responses.
139 140 141 142 143 |
# File 'plugins/main/main.rb', line 139 def support_gzip( header ) return false if not ::RSence.config[:no_gzip] return false if not header.has_key?('accept-encoding') return header['accept-encoding'].include?('gzip') end |
#url(msg) ⇒ Object
Returns base url of browser (before the ‘#’ sign)
220 221 222 |
# File 'plugins/main/main.rb', line 220 def url( msg ) get_ses( msg )[:url][0] end |
#url_responder(msg, location_href) ⇒ Object
The #url_responder
gets called whenever the anchor (pound) of location.href changes. It enables virtual url events for back/forward buttons and bookmarking in browsers whenever utilized.
Client-side support is included in js/url_responder.js
Also allows virtual-host -like behavior if utilized.
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'plugins/main/main.rb', line 185 def url_responder(msg,location_href) ses = get_ses( msg ) # Virtual locations: if location_href.data.include?('#') # split 'http://localhost:8001/#/some_uri' # -> ['http://localhost:8001/','/some_uri'] ses[:url] = location_href.data.split('#') virtual_uri = ses[:url][1] # built-in support for signing out, deletes the # server-side session and reloads the page if virtual_uri == '/sign_out' resp_addr = @conf[:respond_address] msg.expire_session() msg.reply( [ 'COMM.Transporter.stop=true;', "location.href=#{resp_addr.to_json};" ].join('') ) end else ses[:url] = [location_href.data,nil] end # url_responder always accepts locations return true end |