Browse Source

update jquery.jsonrpcclient.js to 0.7.0

readme-update
Simon Grim 6 years ago
parent
commit
ceb1b32fc0
  1. 467
      js/jquery.jsonrpcclient.js

467
js/jquery.jsonrpcclient.js

@ -1,9 +1,8 @@
/** /**
* This plugin requires JSON to be available * JsonRpcClient
*
* The plan is to make use of websockets if they are available, but work just as well with only
* http if not.
* *
* A JSON RPC Client that uses WebSockets if available otherwise fallbacks to ajax.
* Depends on JSON, if browser lacks native support either use JSON3 or jquery.json.
* Usage example: * Usage example:
* *
* var foo = new $.JsonRpcClient({ ajaxUrl: '/backend/jsonrpc' }); * var foo = new $.JsonRpcClient({ ajaxUrl: '/backend/jsonrpc' });
@ -16,108 +15,143 @@
* More examples are available in README.md * More examples are available in README.md
*/ */
(function($) { (function($) {
/** /**
* @fn new * @fn new
* @memberof $.JsonRpcClient * @memberof JsonRpcClient
* *
* @param options An object stating the backends: * @param {object} options An object stating the backends:
* ajaxUrl A url (relative or absolute) to a http(s) backend. * ajaxUrl A url (relative or absolute) to a http(s) backend.
* headers An object that will be passed along to $.ajax in options.headers
* xhrFields An object that will be passed along to $.ajax in options.xhrFields
* socketUrl A url (relative of absolute) to a ws(s) backend. * socketUrl A url (relative of absolute) to a ws(s) backend.
* onmessage A socket message handler for other messages (non-responses). * onmessage A socket message handler for other messages (non-responses).
* onopen A socket onopen handler. (Not used for custom getSocket.)
* onclose A socket onclose handler. (Not used for custom getSocket.)
* onerror A socket onerror handler. (Not used for custom getSocket.)
* getSocket A function returning a WebSocket or null. * getSocket A function returning a WebSocket or null.
* It must take an onmessage_cb and bind it to the onmessage event * It must take an onmessage_cb and bind it to the onmessage event
* (or chain it before/after some other onmessage handler). * (or chain it before/after some other onmessage handler).
* Or, it could return null if no socket is available. * Or, it could return null if no socket is available.
* The returned instance must have readyState <= 1, and if less than 1, * The returned instance must have readyState <= 1, and if less than 1,
* react to onopen binding. * react to onopen binding.
* timeout (optional) A number of ms to wait before timing out and failing a
* call. If specified a setTimeout will be used to keep track of calls
* made through a websocket.
*/ */
$.JsonRpcClient = function(options) { var JsonRpcClient = function(options) {
var self = this; var self = this;
var noop = function() {};
this.options = $.extend({ this.options = $.extend({
ajaxUrl : null, ajaxUrl : null,
socketUrl : null, ///< The ws-url for default getSocket. headers : {}, ///< Optional additional headers to send in $.ajax request.
onmessage : null, ///< Other onmessage-handler. socketUrl : null, ///< WebSocket URL. (Not used if a custom getSocket is supplied.)
getSocket : function(onmessage_cb) { return self._getSocket(onmessage_cb); } onmessage : noop, ///< Optional onmessage-handler for WebSocket.
onopen : noop, ///< Optional onopen-handler for WebSocket.
onclose : noop, ///< Optional onclose-handler for WebSocket.
onerror : noop, ///< Optional onerror-handler for WebSocket.
/// Custom socket supplier for using an already existing socket
getSocket : function(onmessageCb) { return self._getSocket(onmessageCb); }
}, options); }, options);
// Declare an instance version of the onmessage callback to wrap 'this'. // Declare an instance version of the onmessage callback to wrap 'this'.
this.wsOnMessage = function(event) { self._wsOnMessage(event); }; this.wsOnMessage = function(event) { self._wsOnMessage(event); };
};
/// Holding the WebSocket on default getsocket. /// Holding the WebSocket on default getsocket.
$.JsonRpcClient.prototype._ws_socket = null; this._wsSocket = null;
/// Object <id>: { success_cb: cb, error_cb: cb } /// Object <id>: { success_cb: cb, error_cb: cb }
$.JsonRpcClient.prototype._ws_callbacks = {}; this._wsCallbacks = {};
/// The next JSON-RPC request id. /// The next JSON-RPC request id.
$.JsonRpcClient.prototype._current_id = 1; this._currentId = 1;
//queue for ws request sent *before* ws is open.
this._wsRequestQueue = [];
if (!window.JSON && $ && $.toJSON) {
this.JSON = {
stringify: $.toJSON,
parse: $.parseJSON
};
} else {
this.JSON = JSON;
}
};
/** /**
* @fn call * @fn call
* @memberof $.JsonRpcClient * @memberof JsonRpcClient
* *
* @param method The method to run on JSON-RPC server. * @param {string} method The method to run on JSON-RPC server.
* @param params The params; an array or object. * @param {object|array} params The params; an array or object.
* @param success_cb A callback for successful request. * @param {function} successCb A callback for successful request.
* @param error_cb A callback for error. * @param {function} errorCb A callback for error.
*
* @return {object} Returns the deferred object that $.ajax returns or {null} for websockets
*/ */
$.JsonRpcClient.prototype.call = function(method, params, success_cb, error_cb) { JsonRpcClient.prototype.call = function(method, params, successCb, errorCb) {
successCb = typeof successCb === 'function' ? successCb : function() {};
errorCb = typeof errorCb === 'function' ? errorCb : function() {};
// Construct the JSON-RPC 2.0 request. // Construct the JSON-RPC 2.0 request.
var request = { var request = {
jsonrpc : '2.0', jsonrpc : '2.0',
method : method, method : method,
params : params, params : params,
id : this._current_id++ // Increase the id counter to match request/response id : this._currentId++ // Increase the id counter to match request/response
}; };
// Try making a WebSocket call. // Try making a WebSocket call.
var socket = this.options.getSocket(this.wsOnMessage); var socket = this.options.getSocket(this.wsOnMessage);
if (socket !== null) { if (socket !== null) {
this._wsCall(socket, request, success_cb, error_cb); this._wsCall(socket, request, successCb, errorCb);
return; return null;
} }
// No WebSocket, and no HTTP backend? This won't work. // No WebSocket, and no HTTP backend? This won't work.
if (this.options.ajaxUrl === null) { if (this.options.ajaxUrl === null) {
throw "$.JsonRpcClient.call used with no websocket and no http endpoint."; throw 'JsonRpcClient.call used with no websocket and no http endpoint.';
} }
var options = this.options;
$.ajax({ var self = this;
var deferred = $.ajax({
type : 'POST', type : 'POST',
url : this.options.ajaxUrl, url : this.options.ajaxUrl,
data : JSON.stringify(request), contentType: 'application/json',
data : this.JSON.stringify(request),
dataType : 'json', dataType : 'json',
contentType: "application/json; charset=utf-8",
cache : false, cache : false,
beforeSend: function (xhr) { headers : this.options.headers,
if( options.username != null && options.username != undefined ) { xhrFields : this.options.xhrFields,
xhr.setRequestHeader('Authorization', "Basic " + btoa(options.username + ":" + options.password)); timeout : this.options.timeout,
}
},
success : function(data) { success : function(data) {
if ('error' in data && data.error !== null) { if ('error' in data && data.error !== null) {
errorCb(data.error); errorCb(data.error);
} else { } else {
success_cb(data.result); successCb(data.result);
} }
}, },
// JSON-RPC Server could return non-200 on error // JSON-RPC Server could return non-200 on error
error : function(jqXHR, textStatus, errorThrown) { error : function(jqXHR, textStatus, errorThrown) {
try { try {
var response = JSON.parse(jqXHR.responseText); var response = self.JSON.parse(jqXHR.responseText);
if ('console' in window) console.log(response); if ('console' in window) { console.log(response); }
error_cb(response.error);
errorCb(response.error);
} }
catch (err) { catch (err) {
// Perhaps the responseText wasn't really a jsonrpc-error. // Perhaps the responseText wasn't really a jsonrpc-error.
error_cb({ error: jqXHR.responseText }); errorCb({error: jqXHR.responseText});
} }
} }
}); });
return deferred;
}; };
/** /**
@ -127,12 +161,14 @@
* This is very similar to call, but has no id and no handling of callbacks. * This is very similar to call, but has no id and no handling of callbacks.
* *
* @fn notify * @fn notify
* @memberof $.JsonRpcClient * @memberof JsonRpcClient
*
* @param {string} method The method to run on JSON-RPC server.
* @param {object|array} params The params; an array or object.
* *
* @param method The method to run on JSON-RPC server. * @return {object} Returns the deferred object that $.ajax returns or {null} for websockets
* @param params The params; an array or object.
*/ */
$.JsonRpcClient.prototype.notify = function(method, params) { JsonRpcClient.prototype.notify = function(method, params) {
// Construct the JSON-RPC 2.0 request. // Construct the JSON-RPC 2.0 request.
var request = { var request = {
jsonrpc: '2.0', jsonrpc: '2.0',
@ -144,47 +180,46 @@
var socket = this.options.getSocket(this.wsOnMessage); var socket = this.options.getSocket(this.wsOnMessage);
if (socket !== null) { if (socket !== null) {
this._wsCall(socket, request); this._wsCall(socket, request);
return; return null;
} }
// No WebSocket, and no HTTP backend? This won't work. // No WebSocket, and no HTTP backend? This won't work.
if (this.options.ajaxUrl === null) { if (this.options.ajaxUrl === null) {
throw "$.JsonRpcClient.notify used with no websocket and no http endpoint."; throw 'JsonRpcClient.notify used with no websocket and no http endpoint.';
} }
$.ajax({ var deferred = $.ajax({
type : 'POST', type : 'POST',
url : this.options.ajaxUrl, url : this.options.ajaxUrl,
data : JSON.stringify(request), contentType: 'application/json',
data : this.JSON.stringify(request),
dataType : 'json', dataType : 'json',
contentType: "application/json; charset=utf-8",
cache : false, cache : false,
beforeSend: function (xhr){ headers : this.options.headers,
if( options.username != null && options.username != undefined ) { xhrFields : this.options.xhrFields
xhr.setRequestHeader('Authorization', "Basic " + btoa(options.username + ":" + options.password));
}
},
}); });
return deferred;
}; };
/** /**
* Make a batch-call by using a callback. * Make a batch-call by using a callback.
* *
* The callback will get an object "batch" as only argument. On batch, you can call the methods * The callback will get an object "batch" as only argument. On batch, you can call the methods
* "call" and "notify" just as if it was a normal $.JsonRpcClient object, and all calls will be * "call" and "notify" just as if it was a normal JsonRpcClient object, and all calls will be
* sent as a batch call then the callback is done. * sent as a batch call then the callback is done.
* *
* @fn batch * @fn batch
* @memberof $.JsonRpcClient * @memberof JsonRpcClient
* *
* @param callback The main function which will get a batch handler to run call and notify on. * @param {function} callback This function will get a batch handler to run call and notify on.
* @param all_done_cb A callback function to call after all results have been handled. * @param {function} allDoneCb A callback function to call after all results have been handled.
* @param error_cb A callback function to call if there is an error from the server. * @param {function} errorCb A callback function to call if there is an error from the server.
* Note, that batch calls should always get an overall success, and the * Note, that batch calls should always get an overall success, and the
* only error * only error
*/ */
$.JsonRpcClient.prototype.batch = function(callback, all_done_cb, error_cb) { JsonRpcClient.prototype.batch = function(callback, allDoneCb, errorCb) {
var batch = new $.JsonRpcClient._batchObject(this, all_done_cb, error_cb); var batch = new JsonRpcClient._batchObject(this, allDoneCb, errorCb);
callback(batch); callback(batch);
batch._execute(); batch._execute();
}; };
@ -192,54 +227,92 @@
/** /**
* The default getSocket handler. * The default getSocket handler.
* *
* @param onmessage_cb The callback to be bound to onmessage events on the socket. * @param {function} onmessageCb The callback to be bound to onmessage events on the socket.
* *
* @fn _getSocket * @fn _getSocket
* @memberof $.JsonRpcClient * @memberof JsonRpcClient
*/ */
$.JsonRpcClient.prototype._getSocket = function(onmessage_cb) { JsonRpcClient.prototype._getSocket = function(onmessageCb) {
// If there is no ws url set, we don't have a socket. // If there is no ws url set, we don't have a socket.
// Likewise, if there is no window.WebSocket. // Likewise, if there is no window.WebSocket.
if (this.options.socketUrl === null || !("WebSocket" in window)) return null; if (this.options.socketUrl === null || !('WebSocket' in window)) { return null; }
if (this._wsSocket === null || this._wsSocket.readyState > 1) {
if (this._ws_socket === null || this._ws_socket.readyState > 1) { try {
// No socket, or dying socket, let's get a new one. // No socket, or dying socket, let's get a new one.
this._ws_socket = new WebSocket(this.options.socketUrl); this._wsSocket = new WebSocket(this.options.socketUrl);
} catch (e) {
// This can happen if the server is down, or malconfigured.
return null;
}
// Set up onmessage handler. // Set up onmessage handler.
this._ws_socket.onmessage = onmessage_cb; this._wsSocket.onmessage = onmessageCb;
var that = this;
// Set up onclose handler.
this._wsSocket.onclose = function(ev) { that._wsOnClose(ev); };
// Set up onerror handler.
this._wsSocket.onerror = function(ev) { that._wsOnError(ev); };
} }
return this._ws_socket; return this._wsSocket;
}; };
/** /**
* Internal handler to dispatch a JRON-RPC request through a websocket. * Internal handler to dispatch a JRON-RPC request through a websocket.
* *
* @fn _wsCall * @fn _wsCall
* @memberof $.JsonRpcClient * @memberof JsonRpcClient
*/ */
$.JsonRpcClient.prototype._wsCall = function(socket, request, success_cb, error_cb) { JsonRpcClient.prototype._wsCall = function(socket, request, successCb, errorCb) {
var request_json = JSON.stringify(request); var requestJson = this.JSON.stringify(request);
// Setup callbacks. If there is an id, this is a call and not a notify.
if ('id' in request && typeof successCb !== 'undefined') {
this._wsCallbacks[request.id] = {successCb: successCb, errorCb: errorCb};
}
if (socket.readyState < 1) { if (socket.readyState < 1) {
// Queue request
this._wsRequestQueue.push(requestJson);
if (!socket.onopen) {
// The websocket is not open yet; we have to set sending of the message in onopen. // The websocket is not open yet; we have to set sending of the message in onopen.
self = this; // In closure below, this is set to the WebSocket. Use self instead. var self = this; // In closure below, this is set to the WebSocket. Use self instead.
// Set up sending of message for when the socket is open. // Set up sending of message for when the socket is open.
socket.onopen = function() { socket.onopen = function(event) {
// Send the request. // Hook for extra onopen callback
socket.send(request_json); self.options.onopen(event);
// Send queued requests.
var timeout = self.options.timeout;
var request;
for (var i = 0; i < self._wsRequestQueue.length; i++) {
request = self._wsRequestQueue[i];
// Do we use timeouts, and if so, is it a call?
if (timeout && self._wsCallbacks[request.id]) {
self._wsCallbacks[request.id].timeout = self._createTimeout(request.id);
}
socket.send(request);
}
self._wsRequestQueue = [];
}; };
} }
else { } else {
// We have a socket and it should be ready to send on.
socket.send(request_json); // Do we use timeouts, and if so, is it a call?
if (this.options.timeout && this._wsCallbacks[request.id]) {
this._wsCallbacks[request.id].timeout = this._createTimeout(request.id);
} }
// Setup callbacks. If there is an id, this is a call and not a notify. // We have a socket and it should be ready to send on.
if ('id' in request && typeof success_cb !== 'undefined') { socket.send(requestJson);
this._ws_callbacks[request.id] = { success_cb: success_cb, error_cb: error_cb };
} }
}; };
@ -248,59 +321,111 @@
* response, and if so, tries to couple it with a given callback. Otherwise, it falls back to * response, and if so, tries to couple it with a given callback. Otherwise, it falls back to
* given external onmessage-handler, if any. * given external onmessage-handler, if any.
* *
* @param event The websocket onmessage-event. * @param {event} event The websocket onmessage-event.
*/ */
$.JsonRpcClient.prototype._wsOnMessage = function(event) { JsonRpcClient.prototype._wsOnMessage = function(event) {
// Check if this could be a JSON RPC message. // Check if this could be a JSON RPC message.
var response;
try { try {
var response = JSON.parse(event.data); response = this.JSON.parse(event.data);
} catch (err) {
this.options.onmessage(event);
return;
}
/// @todo Make using the jsonrcp 2.0 check optional, to use this on JSON-RPC 1 backends. /// @todo Make using the jsonrcp 2.0 check optional, to use this on JSON-RPC 1 backends.
if (typeof response === 'object' && response.jsonrpc === '2.0') {
if (typeof response === 'object'
&& 'jsonrpc' in response
&& response.jsonrpc === '2.0') {
/// @todo Handle bad response (without id). /// @todo Handle bad response (without id).
// If this is an object with result, it is a response. // If this is an object with result, it is a response.
if ('result' in response && this._ws_callbacks[response.id]) { if ('result' in response && this._wsCallbacks[response.id]) {
// Get the success callback. // Get the success callback.
var success_cb = this._ws_callbacks[response.id].success_cb; var successCb = this._wsCallbacks[response.id].successCb;
// Clear any timeout
if (this._wsCallbacks[response.id].timeout) {
clearTimeout(this._wsCallbacks[response.id].timeout);
}
// Delete the callback from the storage. // Delete the callback from the storage.
delete this._ws_callbacks[response.id]; delete this._wsCallbacks[response.id];
// Run callback with result as parameter. // Run callback with result as parameter.
success_cb(response.result); successCb(response.result);
return; return;
} }
// If this is an object with error, it is an error response. // If this is an object with error, it is an error response.
else if ('error' in response && this._ws_callbacks[response.id]) { else if ('error' in response && response.error !== null && this._wsCallbacks[response.id]) {
// Get the error callback. // Get the error callback.
var error_cb = this._ws_callbacks[response.id].error_cb; var errorCb = this._wsCallbacks[response.id].errorCb;
// Delete the callback from the storage. // Delete the callback from the storage.
delete this._ws_callbacks[response.id]; delete this._wsCallbacks[response.id];
// Run callback with the error object as parameter. // Run callback with the error object as parameter.
error_cb(response.error); errorCb(response.error);
return; return;
} }
} }
}
catch (err) {
// Probably an error while parsing a non json-string as json. All real JSON-RPC cases are
// handled above, and the fallback method is called below.
}
// This is not a JSON-RPC response. Call the fallback message handler, if given. // If we get here it's an invalid JSON-RPC response, pass to fallback message handler.
if (typeof this.options.onmessage === 'function') {
this.options.onmessage(event); this.options.onmessage(event);
};
/**
* Internal WebSocket error handler.
* Will execute all unresolved calls immideatly.
**/
JsonRpcClient.prototype._wsOnError = function(event) {
this._failAllCalls('Socket errored.');
this.options.onerror(event);
};
/**
* Internal WebSocket close handler.
* Will execute all unresolved calls immideatly.
**/
JsonRpcClient.prototype._wsOnClose = function(event) {
this._failAllCalls('Socket closed.');
this.options.onclose(event);
};
/**
* Execute error handler on all pending calls.
*/
JsonRpcClient.prototype._failAllCalls = function(error) {
for (var key in this._wsCallbacks) {
if (this._wsCallbacks.hasOwnProperty(key)) {
// Get the error callback.
var errorCb = this._wsCallbacks[key].errorCb;
// Run callback with the error object as parameter.
errorCb(error);
} }
}
// Throw 'em away
this._wsCallbacks = {};
}; };
/**
* Create a timeout for this request
*/
JsonRpcClient.prototype._createTimeout = function(id) {
if (this.options.timeout) {
var that = this;
return setTimeout(function() {
if (that._wsCallbacks[id]) {
var errorCb = that._wsCallbacks[id].errorCb;
delete that._wsCallbacks[id];
errorCb('Call timed out.');
}
}, this.options.timeout);
}
};
/************************************************************************************************ /************************************************************************************************
* Batch object with methods * Batch object with methods
@ -309,37 +434,36 @@
/** /**
* Handling object for batch calls. * Handling object for batch calls.
*/ */
$.JsonRpcClient._batchObject = function(jsonrpcclient, all_done_cb, error_cb) { JsonRpcClient._batchObject = function(jsonrpcclient, allDoneCb, errorCb) {
// Array of objects to hold the call and notify requests. Each objects will have the request // Array of objects to hold the call and notify requests. Each objects will have the request
// object, and unless it is a notify, success_cb and error_cb. // object, and unless it is a notify, successCb and errorCb.
this._requests = []; this._requests = [];
this.jsonrpcclient = jsonrpcclient; this.jsonrpcclient = jsonrpcclient;
this.all_done_cb = all_done_cb; this.allDoneCb = allDoneCb;
this.error_cb = typeof error_cb === 'function' ? error_cb : function() {}; this.errorCb = typeof errorCb === 'function' ? errorCb : function() {};
}; };
/** /**
* @sa $.JsonRpcClient.prototype.call * @sa JsonRpcClient.prototype.call
*/ */
$.JsonRpcClient._batchObject.prototype.call = function(method, params, success_cb, error_cb) { JsonRpcClient._batchObject.prototype.call = function(method, params, successCb, errorCb) {
this._requests.push({ this._requests.push({
request : { request : {
jsonrpc : '2.0', jsonrpc : '2.0',
method : method, method : method,
params : params, params : params,
id : this.jsonrpcclient._current_id++ // Use the client's id series. id : this.jsonrpcclient._currentId++ // Use the client's id series.
}, },
success_cb : success_cb, successCb : successCb,
error_cb : error_cb errorCb : errorCb
}); });
}; };
/** /**
* @sa $.JsonRpcClient.prototype.notify * @sa JsonRpcClient.prototype.notify
*/ */
$.JsonRpcClient._batchObject.prototype.notify = function(method, params) { JsonRpcClient._batchObject.prototype.notify = function(method, params) {
this._requests.push({ this._requests.push({
request : { request : {
jsonrpc : '2.0', jsonrpc : '2.0',
@ -351,92 +475,147 @@
/** /**
* Executes the batched up calls. * Executes the batched up calls.
*
* @return {object} Returns the deferred object that $.ajax returns or {null} for websockets
*/ */
$.JsonRpcClient._batchObject.prototype._execute = function() { JsonRpcClient._batchObject.prototype._execute = function() {
var self = this; var self = this;
var deferred = null; // Used to store and return the deffered that $.ajax returns
if (this._requests.length === 0) return; // All done :P if (this._requests.length === 0) { return; } // All done :P
// Collect all request data and sort handlers by request id. // Collect all request data and sort handlers by request id.
var batch_request = []; var batchRequest = [];
var handlers = {};
// If we have a WebSocket, just send the requests individually like normal calls. // If we have a WebSocket, just send the requests individually like normal calls.
var socket = self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage); var socket = self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage);
if (socket !== null) { if (socket !== null) {
// We need to keep track of results for the all done callback
var expectedNrOfCb = 0;
var cbResults = [];
var wrapCb = function(cb) {
if (!self.allDoneCb) { // No all done callback? no need to keep track
return cb;
}
return function(data) {
cb(data);
cbResults.push(data);
expectedNrOfCb--;
if (expectedNrOfCb <= 0) {
// Change order so that it maps to request order
var i;
var resultMap = {};
for (i = 0; i < cbResults.length; i++) {
resultMap[cbResults[i].id] = cbResults[i];
}
var results = [];
for (i = 0; i < self._requests.length; i++) {
if (resultMap[self._requests[i].id]) {
results.push(resultMap[self._requests[i].id]);
}
}
// Call all done!
self.allDoneCb(results);
}
};
};
for (var i = 0; i < this._requests.length; i++) { for (var i = 0; i < this._requests.length; i++) {
var call = this._requests[i]; var call = this._requests[i];
var success_cb = ('success_cb' in call) ? call.success_cb : undefined;
var error_cb = ('error_cb' in call) ? call.error_cb : undefined; if ('id' in call.request) {
this._wsCall(socket, call.request, success_cb, error_cb); // We expect an answer
expectedNrOfCb++;
} }
if (typeof all_done_cb === 'function') all_done_cb(result);
return; self.jsonrpcclient._wsCall(
socket, call.request, wrapCb(call.successCb), wrapCb(call.errorCb)
);
} }
return null;
} else {
// No websocket, let's use ajax
var handlers = {};
for (var i = 0; i < this._requests.length; i++) { for (var i = 0; i < this._requests.length; i++) {
var call = this._requests[i]; var call = this._requests[i];
batch_request.push(call.request); batchRequest.push(call.request);
// If the request has an id, it should handle returns (otherwise it's a notify). // If the request has an id, it should handle returns (otherwise it's a notify).
if ('id' in call.request) { if ('id' in call.request) {
handlers[call.request.id] = { handlers[call.request.id] = {
success_cb : call.success_cb, successCb : call.successCb,
error_cb : call.error_cb errorCb : call.errorCb
}; };
} }
} }
var success_cb = function(data) { self._batchCb(data, handlers, self.all_done_cb); }; var successCb = function(data) { self._batchCb(data, handlers, self.allDoneCb); };
// No WebSocket, and no HTTP backend? This won't work. // No WebSocket, and no HTTP backend? This won't work.
if (self.jsonrpcclient.options.ajaxUrl === null) { if (self.jsonrpcclient.options.ajaxUrl === null) {
throw "$.JsonRpcClient.batch used with no websocket and no http endpoint."; throw 'JsonRpcClient.batch used with no websocket and no http endpoint.';
} }
// Send request // Send request
$.ajax({ deferred = $.ajax({
url : self.jsonrpcclient.options.ajaxUrl, url : self.jsonrpcclient.options.ajaxUrl,
data : JSON.stringify(batch_request), contentType: 'application/json',
data : this.jsonrpcclient.JSON.stringify(batchRequest),
dataType : 'json', dataType : 'json',
contentType: "application/json; charset=utf-8",
cache : false, cache : false,
type : 'POST', type : 'POST',
headers : self.jsonrpcclient.options.headers,
xhrFields : self.jsonrpcclient.options.xhrFields,
// Batch-requests should always return 200 // Batch-requests should always return 200
error : function(jqXHR, textStatus, errorThrown) { error : function(jqXHR, textStatus, errorThrown) {
self.error_cb(jqXHR, textStatus, errorThrown); self.errorCb(jqXHR, textStatus, errorThrown);
}, },
success : success_cb success : successCb
}); });
return deferred;
}
}; };
/** /**
* Internal helper to match the result array from a batch call to their respective callbacks. * Internal helper to match the result array from a batch call to their respective callbacks.
* *
* @fn _batchCb * @fn _batchCb
* @memberof $.JsonRpcClient * @memberof JsonRpcClient
*/ */
$.JsonRpcClient._batchObject.prototype._batchCb = function(result, handlers, all_done_cb) { JsonRpcClient._batchObject.prototype._batchCb = function(result, handlers, allDoneCb) {
for (var i = 0; i < result.length; i++) { for (var i = 0; i < result.length; i++) {
var response = result[i]; var response = result[i];
// Handle error // Handle error
if ('error' in response) { if ('error' in response && response.error !== null) {
if (response.id === null || !(response.id in handlers)) { if (response.id === null || !(response.id in handlers)) {
// An error on a notify? Just log it to the console. // An error on a notify? Just log it to the console.
if ('console' in window) console.log(response); if ('console' in window) { console.log(response); }
} } else {
else handlers[response.id].error_cb(response.error); handlers[response.id].errorCb(response.error);
} }
else { } else {
// Here we should always have a correct id and no error. // Here we should always have a correct id and no error.
if (!(response.id in handlers) && 'console' in window) console.log(response); if (!(response.id in handlers) && 'console' in window) {
else handlers[response.id].success_cb(response.result); console.log(response);
} else {
handlers[response.id].successCb(response.result);
}
} }
} }
if (typeof all_done_cb === 'function') all_done_cb(result); if (typeof allDoneCb === 'function') { allDoneCb(result); }
}; };
})(jQuery); $.JsonRpcClient = JsonRpcClient;
})(this.jQuery);

Loading…
Cancel
Save