lp1102300 speed up staff client login sequence collab/phasefx/lp1102300_speed_up_login
authorJason Etheridge <jason@esilibrary.com>
Mon, 21 Jan 2013 07:41:03 +0000 (02:41 -0500)
committerJason Etheridge <jason@esilibrary.com>
Mon, 21 Jan 2013 08:53:16 +0000 (03:53 -0500)
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 <jason@esilibrary.com>
Open-ILS/xul/staff_client/chrome/content/OpenILS/data.js
Open-ILS/xul/staff_client/chrome/content/util/network.js

index fc17229..71b28a3 100644 (file)
@@ -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 {
index 395e50d..ba68604 100644 (file)
@@ -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);