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.
105 106 107 108 |
# File 'plugins/main/main.rb', line 105 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
308 309 310 |
# File 'plugins/main/main.rb', line 308 def delayed_call( msg, params ) get_ses( msg )[:delayed_calls].push( params ) end |
#do_init_ui(msg) ⇒ Object
Enables the init_ui event.
350 351 352 |
# File 'plugins/main/main.rb', line 350 def do_init_ui( msg ) get_ses( msg )[:dont_init_ui] = false end |
#dont_init_ui(msg) ⇒ Object
Disables the init_ui event.
344 345 346 |
# File 'plugins/main/main.rb', line 344 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.
413 414 415 416 417 418 |
# File 'plugins/main/main.rb', line 413 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
356 357 358 359 360 361 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 |
# File 'plugins/main/main.rb', line 356 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.
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'plugins/main/main.rb', line 139 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
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 |
# File 'plugins/main/main.rb', line 429 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
235 236 237 238 239 240 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 |
# File 'plugins/main/main.rb', line 235 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
87 88 89 90 91 92 93 94 95 |
# File 'plugins/main/main.rb', line 87 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.
230 231 232 233 |
# File 'plugins/main/main.rb', line 230 def init_ses( msg ) super restore_ses( msg ) end |
#open ⇒ Object
Opens and renders the index page template
98 99 100 101 102 |
# File 'plugins/main/main.rb', line 98 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
164 165 166 |
# File 'plugins/main/main.rb', line 164 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)
220 221 222 |
# File 'plugins/main/main.rb', line 220 def pound( msg ) get_ses( msg )[:url][1] end |
#render_index_html ⇒ Object
Index page renderer
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'plugins/main/main.rb', line 55 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] ) index_html.gsub!( '__BODY__', @conf[:body] ) return index_html end |
#restore_ses(msg) ⇒ Object
Called once when a session is restored or cloned using the cookie’s ses_key
276 277 278 279 280 281 282 283 284 285 |
# File 'plugins/main/main.rb', line 276 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.
421 422 423 424 425 426 |
# File 'plugins/main/main.rb', line 421 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.
132 133 134 135 136 |
# File 'plugins/main/main.rb', line 132 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)
214 215 216 |
# File 'plugins/main/main.rb', line 214 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.
178 179 180 181 182 183 184 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 |
# File 'plugins/main/main.rb', line 178 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] @plugins.delegate('sign_out',msg) 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 |