var rpc_objCode = ''; var rpc_defaultMethod = "GET"; var rpc_queueLock = false; var rpc_lockLock = false; var rpc_currentCalls = new Array(); var rpc_functions = new Array(); var rpc_failed = false; // Calls a remote function on the server function rpc_doCall(name, pArguments) { if (rpc_failed) return; var func = rpc_functions[name]; if (!func) { rpc_alertFunction(name); return; } var args = new Array(); var callback, i; for (i=0;i<pArguments.length-1;i++) args[i] = encodeURIComponent(pArguments[i]); callback = pArguments[i]; if (typeof callback != 'function') { rpc_alertCallback(name, typeof callback, args); return; } rpc_setLock(); var nCall = new rpc_Call(func, args, callback); rpc_currentCalls.push(nCall); rpc_resetLock(); nCall.call(); } // Locks the main RPC lock function rpc_setLock() { while (rpc_queueLock) { while (rpc_lockLock) ; rpc_lockLock = true; if (!rpc_queueLock) { rpc_queueLock = true; rpc_lockLock = false; break; } rpc_lockLock = false; } } // Unlocks the main RPC lock function rpc_resetLock() { while (rpc_lockLock) ; rpc_lockLock = true; rpc_queueLock = false; rpc_lockLock = false; } // Checks the queue of current calls for a specific identifier function rpc_isCalling(id) { var i = rpc_currentCalls.length; while (i>0) { i--; if (rpc_currentCalls[i].id == id) return true; } return false; } // Reads the queue and returns the RPC call identified by the ID passed by the // caller. Returns null if the RPC call cannot be found. function rpc_getCall(id) { for (i=0;i<rpc_currentCalls.length;i++) if (rpc_currentCalls[i].id == id) return rpc_currentCalls[i]; return null; } // Removes a call object from the list of calls in progress. function rpc_removeCall(id) { var n = new Array(); for (i=0;i<rpc_currentCalls.length;i++) if (rpc_currentCalls[i].id != id) n.push(rpc_currentCalls[i]); rpc_currentCalls = n; return; } // Initialises an object that will be able to handle RPC calls function rpc_initObject() { var A; if (rpc_objCode == "E") return null; else if (rpc_objCode != "") eval('A='+rpc_objCode); else { try { A = new ActiveXObject("Msxml2.XMLHTTP"); rpc_objCode = 'new ActiveXObject("Msxml2.XMLHTTP")'; } catch (e) { try { A=new ActiveXObject("Microsoft.XMLHTTP"); rpc_objCode = 'new ActiveXObject("Microsoft.XMLHTTP")'; } catch (oc) { A = null; } } if (!A && typeof XMLHttpRequest != "undefined") { A = new XMLHttpRequest(); rpc_objCode = "new XMLHttpRequest()"; } } if (!A && typeof A == "object" && rpc_objCode != "E") { rpc_objCode = "E"; rpc_alertSupport(); } return A; } //----------------------------------------------------------------- // rpc_Function object //----------------------------------------------------------------- // Initialises the object by specifying the name of the function, // and its calling method. Adds the object to the function list, and // generate the stub. function rpc_Function(name, method) { this.name = name; this.method = method ? method : rpc_defaultMethod; rpc_functions[name] = this; eval('x_'+name+'=function(){rpc_doCall("'+name+'",arguments)}'); } //----------------------------------------------------------------- // rpc_Call object //----------------------------------------------------------------- // Initialises the object using the function object, arguments and // callback passed by the main function. function rpc_Call(func, args, callback) { this.funcObj = func; this.arguments = args; this.callback = callback; var rts = new Date().getTime(); while (rpc_isCalling(rts) || rts == "") rts++; this.id = rts; this.inCall = false; this.retries = 0; this.timeout = null; this.timestamp = 0; this.object = null; this.call = rpc_Call_call; this.retry = rpc_Call_retry; this.send = rpc_Call_send; } // Prepares a RPC call using the data stored within the object function rpc_Call_call() { if (this.inCall) return; this.inCall = true; this.send(); } // Tries re-executing a RPC call function rpc_Call_retry() { if (!this.inCall) return; delete this.object; clearTimeout(this.timeout); if (this.retries == 3) { rpc_failed = true; rpc_showErrorPage(); rpc_resetLock(); return; } this.retries ++; rpc_resetLock(); this.send(); } // Sends a request to the server function rpc_Call_send() { var uri = rpc_pageURI; var postData, mks; var i, obj; mks = 'rs=' + escape(this.funcObj.name); if (this.arguments.length) mks += '&rsargs[]=' + this.arguments.join('&rsargs[]='); mks += '&rsId=' + this.id; if (this.funcObj.method == "GET") { postData = null; uri += '?' + mks; } else postData = mks; obj = rpc_initObject(); if (!obj) { rpc_setLock(); rpc_failed = true; rpc_resetLock(); return; } obj.open(this.funcObj.method, uri, true); if (this.funcObj.method == "POST") { obj.setRequestHeader("Method", "POST " + uri + " HTTP/1.1"); obj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); } eval('obj.onreadystatechange=function(){rpc_Call_returned('+this.id+')}'); this.timeout = setTimeout('rpc_Call_timeout('+this.id+')', 25000); this.object = obj; obj.send(postData); delete obj; } // This function is used as the callback for all RPC functions function rpc_Call_returned(id) { rpc_setLock(); if (rpc_failed) { rpc_resetLock(); return; } var c = rpc_getCall(id); if (!c || !c.inCall) { rpc_failed = true; rpc_resetLock(); rpc_alertCallID(id); return; } var obj = c.object; if (obj.readyState != 4) { rpc_resetLock(); return; } try { if (obj.status != 200) { c.retry(); return; } } catch (e) { c.retry(); return; } var stat = obj.responseText.charAt(0); var data = obj.responseText.substring(2); if (stat == "-") { rpc_failed = true; if (data == "m" || data == "a") { window.location.href=window.location.href; } else if (data.indexOf('f:') == 0) { rpc_alertFatalError(data.substring(2)); } else if (data.indexOf('k:') == 0) { rpc_alertKicked(data.substring(2)); window.location.href=window.location.href; } else { rpc_alertUnknownError(data); rpc_showErrorPage(); } return; } else if (stat != '+') { rpc_failed = true; rpc_alertUnknownStatus(stat.charCodeAt(0) + " " + stat + "\n" + obj.responseText); rpc_showErrorPage(); return; } c.inCall = false; clearTimeout(c.timeout); c.timestamp = new Date().getTime(); rpc_removeCall(c.id); rpc_resetLock(); c.callback(data); } // Timeout function function rpc_Call_timeout(id) { rpc_setLock(); if (rpc_failed) { rpc_resetLock(); return; } var c = rpc_getCall(id); if (!c || !c.inCall || (new Date().getTime()) - c.timestamp < 23000) { rpc_resetLock(); return; } c.object.abort(); c.object = null; c.retry(); }