From 82dbd5484d58a8af1f41697925d1305d5ffe73fe Mon Sep 17 00:00:00 2001 From: Jason Etheridge Date: Mon, 21 Jan 2013 02:41:03 -0500 Subject: [PATCH] lp1102300 speed up staff client login sequence This code caches some data to the file system during the staff client login sequence and will load that data from the file system on subsequent logins instead of from the network, unless the data goes stale, in which case, new data will be cached. It relies on changes to OpenSRF to provide .md5 variants of methods. I've done this on the Perl side with collab/phasefx/auto_md5_method @ working/OpenSRF.git, but if someone were to do the same on the C (and Python) sides, then we can cache even more data during the login sequence. The Perl side might could also benefit from a better implementation. This code potentially creates some security vulnerabilities, for if the data is stored in the user profile directory, then that directory is probably not as protected as the application itself. But this is true for the data we already store there. In the long run, we'lll probably want to MD5 the data on the client side to compare to the remote MD5, instead of caching remote MD5's. Signed-off-by: Jason Etheridge --- .../staff_client/chrome/content/OpenILS/data.js | 34 +++---- .../staff_client/chrome/content/util/network.js | 104 +++++++++++++++++++++ 2 files changed, 115 insertions(+), 23 deletions(-) diff --git a/Open-ILS/xul/staff_client/chrome/content/OpenILS/data.js b/Open-ILS/xul/staff_client/chrome/content/OpenILS/data.js index fc17229959..71b28a3bf7 100644 --- a/Open-ILS/xul/staff_client/chrome/content/OpenILS/data.js +++ b/Open-ILS/xul/staff_client/chrome/content/OpenILS/data.js @@ -549,7 +549,9 @@ OpenILS.data.prototype = { var level = obj.error.sdump_levels.D_SES_RESULT; if (classname == 'aou' || classname == 'my_aou') obj.error.sdump_levels.D_SES_RESULT = false; - var robj = obj.network.request( app, method, params); + var robj = cacheable + ? obj.network.cached_request( app, method, params) + : obj.network.request( app, method, params); if (robj != null && typeof robj.ilsevent != 'undefined') { obj.error.standard_unexpected_error_alert('The staff client failed to retrieve expected data from this call, "' + method + '"',robj); throw(robj); @@ -560,21 +562,7 @@ OpenILS.data.prototype = { obj.data_progress('Retrieved list for ' + classname + ' objects. '); } catch(E) { - // if cacheable, try offline - if (cacheable) { - /* FIXME -- we're going to revisit caching and do it differently - try { - var file = new util.file( classname ); - obj.list[classname] = file.get_object(); file.close(); - convert(); - } catch(E) { - throw(E); - } - */ - throw(E); // for now - } else { - throw(E); // for now - } + throw(E); // for now } } } @@ -587,7 +575,7 @@ OpenILS.data.prototype = { this.chain.push( function() { try { - var robj = obj.network.simple_request('CIRC_MODIFIER_LIST',[{'full':true}]); + var robj = obj.network.cached_simple_request('CIRC_MODIFIER_LIST',[{'full':true}]); if (typeof robj.ilsevent != 'undefined') throw(robj); obj.list.ccm = robj == null ? [] : robj; obj.hash.ccm = util.functional.convert_object_list_to_hash( obj.list.ccm ); @@ -609,7 +597,7 @@ OpenILS.data.prototype = { api.FM_CNAL_RETRIEVE.app, api.FM_CNAL_RETRIEVE.method, [ obj.session.key ], - false + true ] ); try { @@ -813,7 +801,7 @@ OpenILS.data.prototype = { this.chain.push( function() { try { - var robj = obj.network.simple_request('FM_AOUS_RETRIEVE',[ obj.session.key, obj.list.au[0].ws_ou() ]); + var robj = obj.network.cached_simple_request('FM_AOUS_RETRIEVE',[ obj.session.key, obj.list.au[0].ws_ou() ]); if (typeof robj.ilsevent != 'undefined') throw(robj); obj.hash.aous = robj; obj.data_progress('Retrieved org unit settings. '); @@ -879,7 +867,7 @@ OpenILS.data.prototype = { api.FM_CNCT_RETRIEVE.app, api.FM_CNCT_RETRIEVE.method, [ obj.list.au[0].ws_ou() ], - false + true ] ); try { @@ -900,7 +888,7 @@ OpenILS.data.prototype = { api.FM_CNCT_RETRIEVE.app, api.FM_CNCT_RETRIEVE.method, [ obj.list.au[0].ws_ou() ], - false + true ] ); try { @@ -921,7 +909,7 @@ OpenILS.data.prototype = { api.FM_ACPL_RETRIEVE.app, api.FM_ACPL_RETRIEVE.method, [ obj.list.au[0].ws_ou() ], - false + true ] ); try { @@ -1041,7 +1029,7 @@ OpenILS.data.prototype = { api.FM_CBT_RETRIEVE.app, api.FM_CBT_RETRIEVE.method, [ obj.session.key, obj.list.au[0].ws_ou() ], - false + true ] ); try { diff --git a/Open-ILS/xul/staff_client/chrome/content/util/network.js b/Open-ILS/xul/staff_client/chrome/content/util/network.js index 395e50d0b2..ba68604676 100644 --- a/Open-ILS/xul/staff_client/chrome/content/util/network.js +++ b/Open-ILS/xul/staff_client/chrome/content/util/network.js @@ -29,6 +29,110 @@ util.network.prototype = { 'NETWORK_FAILURE' : null, + 'cached_request' : function(app,name,params /* not now: ,f,override_params,_params */) { + try { + var robj_md5 = this.md5_request2(app,name,params); + var x_md5 = "won't match me"; + try { + JSAN.use('util.file'); var file = new util.file(app+'.'+name+'.md5'); + if (file._file.exists()) { + x_md5 = file.get_object(); + } else { + throw('expected .md5 file but not found'); + } + + if (robj_md5 != x_md5) { + throw('stale .md5 file'); + } + } catch(E) { + file.set_object(robj_md5); + } + file.close(); + + var robj; + + try { + JSAN.use('util.file'); file = new util.file(app+'.'+name+'.data'); + if (robj_md5 == x_md5) { + if (file._file.exists()) { + robj = file.get_object(); + } else { + throw('expected .data file but not found'); + } + } else { + throw('stale .data file'); + } + } catch(E) { + robj = this.request(app,name,params); + file.set_object(robj); + } + file.close(); + + return robj; + } catch(E) { + alert('Error in cached_request('+app+','+name+','+js2JSON(params)+'): ' + E); + return null; + } + }, + + 'cached_simple_request' : function(method_id,params /* not now: ,f,override_params,_params */) { + try { + var robj_md5 = this.md5_request(method_id,params); + var x_md5 = "won't match me"; + try { + JSAN.use('util.file'); var file = new util.file(method_id+'.md5'); + if (file._file.exists()) { + x_md5 = file.get_object(); + } else { + throw('expected .md5 file but not found'); + } + + if (robj_md5 != x_md5) { + throw('stale .md5 file'); + } + } catch(E) { + file.set_object(robj_md5); + } + file.close(); + + var robj; + + try { + JSAN.use('util.file'); file = new util.file(method_id+'.data'); + if (robj_md5 == x_md5) { + if (file._file.exists()) { + robj = file.get_object(); + } else { + throw('expected .data file but not found'); + } + } else { + throw('stale .data file'); + } + } catch(E) { + robj = this.simple_request(method_id,params); + file.set_object(robj); + } + file.close(); + + return robj; + } catch(E) { + alert('Error in cached_simple_request('+method_id+','+js2JSON(params)+'): ' + E); + return null; + } + }, + + 'md5_request' : function(method_id,params,f,override_params) { + if (typeof api[method_id] == 'undefined') { + throw( offlineStrings.getFormattedString('network.method_not_found.error', [method_id]) ); + } + var secure = true; if (typeof api[method_id].secure != 'undefined') secure = api[method_id].secure; + return this.request(api[method_id].app,api[method_id].method+'.md5',params,f,override_params,{ 'secure' : secure, 'method_id' : method_id }); + }, + + 'md5_request2' : function(app,name,params,f,override_params) { + return this.request(app,name+'.md5',params,f,override_params,{ 'secure' : true }); + }, + 'simple_request' : function(method_id,params,f,override_params) { //var obj = this; //var sparams = js2JSON(params); -- 2.11.0