From: pines Date: Sun, 13 May 2007 08:26:31 +0000 (+0000) Subject: cached request method and infrastructure X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=8b329dd923e39097ac5273eca699c3eed9f6b81b;p=Evergreen.git cached request method and infrastructure git-svn-id: svn://svn.open-ils.org/ILS/branches/rel_1_0@7288 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- 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 356229e879..501f73c678 100644 --- a/Open-ILS/xul/staff_client/chrome/content/util/network.js +++ b/Open-ILS/xul/staff_client/chrome/content/util/network.js @@ -15,9 +15,16 @@ util.network.prototype = { 'NETWORK_FAILURE' : null, - 'simple_request' : function(id,params,f,o_params) { - var secure = true; if (typeof api[id].secure != 'undefined') secure = api[id].secure; - return this.request(api[id].app,api[id].method,params,f,o_params,secure); + 'simple_request' : function(method_id,params,f,override_params) { + if (typeof api[method_id] == 'undefined') throw( 'Method not found for ' + 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,params,f,override_params,{ 'secure' : secure, 'method_id' : method_id }); + }, + + 'cached_request' : function(method_id,params,f,override_params) { + if (typeof api[method_id] == 'undefined') throw( 'Method not found for ' + 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,params,f,override_params,{ 'secure' : secure, 'want_cached' : true, 'method_id' : method_id }); }, 'get_result' : function (req) { @@ -40,24 +47,94 @@ util.network.prototype = { return result; }, - 'request' : function (app,name,params,f,o_params,secure) { - var request = this._request(app,name,params,f,o_params,secure); + 'is_cacheable' : function(method_id) { + return (api[method_id].cacheable); + }, + + 'request' : function (app,name,params,f,override_params,_params) { + + var obj = this; + + try { + + if (_params && _params.want_cached) if ( this.is_cacheable(_params.method_id) ) { + JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'}); + var key = (app + '+' + name + '+' + js2JSON(params)).replace(/\./g,'_'); + var x = data.cached_request[key]; + if (x) { + obj.error.sdump('D_CACHE','Cached request found for key = \n' + key + '\n' + js2JSON(x) + '\n'); + switch(x.status) { + case 'pending' : + if ( Number(new Date()) - Number(x.status_time) > 60000 ) break; // if pending request is taking too long + if (f) { // Setup a self-destroying observer on the pending request to handle this request + obj.error.sdump('D_CACHE','Cached request pending, adding watch to handle current asynchronous request. key = \n' + key + '\n'); + var id = data.observers.add('cached_request.'+key+'.status',function(p,o,n) { + obj.error.sdump('D_OBSERVERS','Entering watch function for key = \n' + key + '\np = ' + p + '\no = ' + js2JSON(o) + '\nn = ' + js2JSON(n) + '\nx = ' + js2JSON(x) + '\n'); + if (n == 'complete') { + obj.error.sdump('D_CACHE','Cached request completed for key = \n' + key + '\nNow calling a previous async request watching this one.\n'); + f( { 'getResultObject' : function() { return JSON2js( js2JSON( x.request ) ); } } ); + setTimeout( function() { try { data.observers.remove(id); } catch(E) { alert(E); } }, 0 ); + } + return n; + } + ); + return null; + } else { + obj.error.sdump('D_CACHE','Pending request and synchronous request collision with key = \n' + key + '\nFalling through...\n'); + } + break; + case 'complete' : + if ( Number( new Date() ) < x.expire_time ) { + if (f) { + obj.error.sdump('D_CACHE','Cached request found completed, handling asynchronous request now. key = \n' + key + '\n'); + f( { 'getResultObject' : function() { return JSON2js( js2JSON( x.request ) ); } } ); + return null; + } else { + obj.error.sdump('D_CACHE','Cached request found completed, key = \n' + key + '\nreturning value =\n' + x.request + '\n'); + return JSON2js( js2JSON( x.request ) ); // FIXME -- cloning the object is a workaround, otherwise instanceOf somehow silently fails + } + } else { + obj.error.sdump('D_CACHE','Cached request found completed, however, it has expired. key = \n' + key + '\nFalling through...\n'); + } + break; + } + } else { + obj.error.sdump('D_CACHE','Cached request not found for key = \n' + key + '\n'); + } + } + + var request = this._request(app,name,params,f,override_params,_params); if (request) { return this.get_result(request); } else { return null; } + + } catch(E) { + alert(E); + } }, - '_request' : function (app,name,params,f,o_params,secure) { + '_request' : function (app,name,params,f,override_params,_params) { var obj = this; try { var sparams = js2JSON(params); obj.error.sdump('D_SES','request '+app+' '+name+' '+obj.error.pretty_print(sparams.slice(1,sparams.length-1))+ - '\no_params = ' + o_params + '\nsecure = ' + secure + + '\noverride_params = ' + override_params + '\n_params = ' + _params + '\nResult #' + (++obj.link_id) + ( f ? ' asynced' : ' synced' ) ); + + var key; var x; var data; + if (_params && obj.is_cacheable(_params.method_id)) { + JSAN.use('OpenILS.data'); data = new OpenILS.data(); data.init({'via':'stash'}); + key = (app + '+' + name + '+' + js2JSON(params)).replace(/\./g,'_'); + data.cached_request[key] = { 'test' : 'test', 'status' : 'pending', 'status_time' : Number(new Date()) }; + data.stash('cached_request'); + x = data.cached_request[key]; + obj.error.sdump('D_CACHE','Current request is cacheable, setting pending status for key = \n' + key + '\nUpdating cache with ' + js2JSON(x) + '\n'); + } + var request = new RemoteRequest( app, name ); - if (secure) { + if (_params && _params.secure) { request.setSecure(true); } else { request.setSecure(false); @@ -76,12 +153,18 @@ util.network.prototype = { + (json_string.length > 80 ? obj.error.pretty_print(json_string) : json_string) + '\n\nOriginal Request:\n\n' + 'request '+app+' '+name+' '+ sparams.slice(1,sparams.length-1)); - req = obj.rerequest_on_session_timeout(app,name,params,req,o_params,secure); - req = obj.rerequest_on_perm_failure(app,name,params,req,o_params,secure); - if (o_params) { - req = obj.rerequest_on_override(app,name,params,req,o_params,secure); + req = obj.rerequest_on_session_timeout(app,name,params,req,override_params,_params); + req = obj.rerequest_on_perm_failure(app,name,params,req,override_params,_params); + if (override_params) { + req = obj.rerequest_on_override(app,name,params,req,override_params,_params); + } + req = obj.check_for_offline(app,name,params,req,override_params,_params); + if (_params && obj.is_cacheable(_params.method_id)) { + x.request = obj.get_result(req); + x.status = 'complete'; x.status_time = Number(new Date()); x.expire_time = Number(x.status_time) + api[_params.method_id].ttl; + data.stash('cached_request'); + obj.error.sdump('D_CACHE','Previously pending cached request is now complete for key = \n' + key + '\nUpdating cache with ' + js2JSON(x) + '\n'); } - req = obj.check_for_offline(app,name,params,req,o_params,secure); f(req); obj.NETWORK_FAILURE = null; } catch(E) { @@ -111,13 +194,19 @@ util.network.prototype = { + obj.link_id + '\n\n' + ( json_string.length > 80 ? obj.error.pretty_print(json_string) : json_string ) + '\n\nOriginal Request:\n\n' + 'request '+app+' '+name+' '+ sparams.slice(1,sparams.length-1)); - request = obj.rerequest_on_session_timeout(app,name,params,request,o_params,secure); - request = obj.rerequest_on_perm_failure(app,name,params,request,o_params,secure); - if (o_params) { - request = obj.rerequest_on_override(app,name,params,request,o_params,secure); + request = obj.rerequest_on_session_timeout(app,name,params,request,override_params,_params); + request = obj.rerequest_on_perm_failure(app,name,params,request,override_params,_params); + if (override_params) { + request = obj.rerequest_on_override(app,name,params,request,override_params,_params); } - request = obj.check_for_offline(app,name,params,request,o_params,secure); + request = obj.check_for_offline(app,name,params,request,override_params,_params); obj.NETWORK_FAILURE = null; + if (_params && obj.is_cacheable(_params.method_id)) { + x.request = result; + x.status = 'complete'; x.status_time = Number(new Date()); x.expire_time = Number(x.status_time) + api[_params.method_id].ttl; + data.stash('cached_request'); + obj.error.sdump('D_CACHE','Previously pending cached request is now complete for key = \n' + key + '\nUpdating cache with ' + js2JSON(x) + '\n'); + } return request; } @@ -130,7 +219,7 @@ util.network.prototype = { } }, - 'check_for_offline' : function (app,name,params,req,o_params,secure) { + 'check_for_offline' : function (app,name,params,req,override_params,_params) { var obj = this; var result = obj.get_result(req); if (result != null) return req; @@ -178,7 +267,7 @@ util.network.prototype = { switch(r) { case 0: - req = obj._request(app,name,params,null,o_params,secure); + req = obj._request(app,name,params,null,override_params,_params); if (obj.get_result(req)) proceed = true; /* daily WTF, why am I even doing this? :) */ return req; break; @@ -220,26 +309,34 @@ util.network.prototype = { netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect UniversalBrowserWrite'); var url = urls.XUL_AUTH_SIMPLE; if (typeof xulG != 'undefined' && typeof xulG.url_prefix == 'function') url = xulG.url_prefix( url ); - window.open( - url - + '?login_type=staff' - + '&desc_brief=' + window.escape( text ? 'Session Expired' : 'Operator Change' ) - + '&desc_full=' + window.escape( text ? 'Please enter the credentials for a new login session.' : 'Please enter the credentials for the new login session. Note that the previous session is still active.'), - 'simple_auth' + (new Date()).toString(), - 'chrome,resizable,modal,width=700,height=500' + JSAN.use('util.window'); var win = new util.window(); + var my_xulG = win.open( + url, + //+ '?login_type=staff' + //+ '&desc_brief=' + window.escape( text ? 'Session Expired' : 'Operator Change' ) + //+ '&desc_full=' + window.escape( text ? 'Please enter the credentials for a new login session.' : 'Please enter the credentials for the new login session. Note that the previous session is still active.'), + //'simple_auth' + (new Date()).toString(), + 'Authorize', + 'chrome,resizable,modal,width=700,height=500', + { + 'login_type' : 'staff', + 'desc_brief' : text ? 'Session Expired' : 'Operator Change', + 'desc_full' : text ? 'Please enter the credentials for a new login session.' : 'Please enter the credentials for the new login session. Note that the previous session is still active.', + //'simple_auth' : (new Date()).toString(), + } ); JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'}); - if (typeof data.temporary_session != 'undefined' && data.temporary_session != '') { - data.session.key = data.temporary_session.key; - data.session.authtime = data.temporary_session.authtime; + if (typeof my_xulG.temporary_session != 'undefined' && my_xulG.temporary_session != '') { + data.session.key = my_xulG.temporary_session.key; + data.session.authtime = my_xulG.temporary_session.authtime; data.stash('session'); if (! data.list.au ) data.list.au = []; - data.list.au[0] = JSON2js(data.temporary_session.usr); + data.list.au[0] = JSON2js( my_xulG.temporary_session.usr ); data.stash('list'); obj.reset_titlebars(data); return true; - } + } else { alert('here2'); } return false; } catch(E) { @@ -247,7 +344,7 @@ util.network.prototype = { } }, - 'rerequest_on_session_timeout' : function(app,name,params,req,o_params,secure) { + 'rerequest_on_session_timeout' : function(app,name,params,req,override_params,_params) { try { var obj = this; var robj = obj.get_result(req); @@ -256,7 +353,7 @@ util.network.prototype = { if (obj.get_new_session(name,undefined,true)) { JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'}); params[0] = data.session.key; - req = obj._request(app,name,params,null,o_params,secure); + req = obj._request(app,name,params,null,override_params,_params); } } } catch(E) { @@ -265,7 +362,7 @@ util.network.prototype = { return req; }, - 'rerequest_on_perm_failure' : function(app,name,params,req,o_params,secure) { + 'rerequest_on_perm_failure' : function(app,name,params,req,override_params,_params) { try { var obj = this; var robj = obj.get_result(req); @@ -274,19 +371,27 @@ util.network.prototype = { if (location.href.match(/^chrome/)) { //alert('Permission denied.'); } else { - window.open( - urls.XUL_AUTH_SIMPLE - + '?login_type=temp' - + '&desc_brief=' + window.escape('Permission Denied: ' + robj.ilsperm) - + '&desc_full=' + window.escape('Another staff member with the above permission may authorize this specific action. Please notify your library administrator if you need this permission. If you feel you have received this exception in error, inform your friendly Evergreen developers of the above permission and this debug information: ' + name), - 'simple_auth' + (new Date()).toString(), - 'chrome,resizable,modal,width=700,height=500' + JSAN.use('util.window'); var win = new util.window(); + var my_xulG = win.open( + urls.XUL_AUTH_SIMPLE, + //+ '?login_type=temp' + //+ '&desc_brief=' + window.escape('Permission Denied: ' + robj.ilsperm) + //+ '&desc_full=' + window.escape('Another staff member with the above permission may authorize this specific action. Please notify your library administrator if you need this permission. If you feel you have received this exception in error, inform your friendly Evergreen developers of the above permission and this debug information: ' + name), + //'simple_auth' + (new Date()).toString(), + 'Authorize', + 'chrome,resizable,modal,width=700,height=500', + { + 'login_type' : 'temp', + 'desc_brief' : 'Permission Denied: ' + robj.ilsperm, + 'desc_full' : 'Another staff member with the above permission may authorize this specific action. Please notify your library administrator if you need this permission. If you feel you have received this exception in error, please inform your friendly Evergreen developers or helpdesk staff of the above permission and this debug information: ' + name, + //'simple_auth' : (new Date()).toString(), + } ); JSAN.use('OpenILS.data'); - var data = new OpenILS.data(); data.init({'via':'stash'}); - if (typeof data.temporary_session != 'undefined' && data.temporary_session != '') { - params[0] = data.temporary_session.key; - req = obj._request(app,name,params,null,o_params,secure); + //var data = new OpenILS.data(); data.init({'via':'stash'}); + if (typeof my_xulG.temporary_session != 'undefined' && my_xulG.temporary_session != '') { + params[0] = my_xulG.temporary_session.key; + req = obj._request(app,name,params,null,override_params,_params); } } } @@ -296,10 +401,10 @@ util.network.prototype = { return req; }, - 'rerequest_on_override' : function (app,name,params,req,o_params,secure) { + 'rerequest_on_override' : function (app,name,params,req,override_params,_params) { var obj = this; try { - if (!o_params.text) o_params.text = {}; + if (!override_params.text) override_params.text = {}; function override(r) { try { netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect UniversalBrowserWrite'); @@ -310,7 +415,7 @@ util.network.prototype = { for (var i = 0; i < r.length; i++) { var t1 = String(r[i].ilsevent).replace(/&/g,'&').replace(//g,'>'); var t2 = String(r[i].textcode).replace(/&/g,'&').replace(//g,'>'); - var t3 = String((o_params.text[r[i].ilsevent] ? o_params.text[r[i].ilsevent](r[i]) : '')).replace(/&/g,'&').replace(//g,'>'); + var t3 = String((override_params.text[r[i].ilsevent] ? override_params.text[r[i].ilsevent](r[i]) : '')).replace(/&/g,'&').replace(//g,'>'); var t4 = String(r[i].desc).replace(/&/g,'&').replace(//g,'>'); xml += '' + '' + t2 + '' + @@ -321,17 +426,18 @@ util.network.prototype = { 'Force this action?' + '