var Barrister;
if (!Barrister) {
Barrister = {};
}
Create a Barrister namespace
var Barrister;
if (!Barrister) {
Barrister = {};
}
Wrap all client code in function We’ll explicitly export blessed functions at the bottom.
(function() {
Function to create IDs for requests
var rchars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
function randstr(len) {
var s = "";
var i;
for (i = 0; i < len; i++) {
var rnum = Math.floor(Math.random() * rchars.length);
s += rchars.substring(rnum,rnum+1);
}
return s;
}
var jsonRegex = new RegExp('[\\u007f-\\uffff]', 'g');
var jsonRegexReplace = function(c) {
return '\\u'+('0000'+c.charCodeAt(0).toString(16)).slice(-4);
};
JSON_stringify takes a JSON string and escapes unicode characters
Built in JSON.stringify() will return unicode characters that require UTF-8 encoding on the wire. Barrister specifies that all JSON strings be ASCII safe (to minimize surprises). This function will replace unicode characters with their escaped (ASCII-safe) equivalents.
If emit_unicode is true then s is returned unchanged
function JSON_stringify(s, emit_unicode) {
if (s) {
var json = JSON.stringify(s);
if (json) {
return emit_unicode ? json : json.replace(jsonRegex, jsonRegexReplace);
}
else {
return json;
}
}
else {
return s;
}
}
makeRequest returns a JSON-RPC 2.0 compliant request object, setting ‘id’, ‘method’, and ‘params’. A random request ID is generated for the request, which is used to correlate requests and responses for batch mode.
function makeRequest(method, params) {
var req = { "jsonrpc": "2.0", "id": randstr(20), "method": method };
JSON-RPC allows params to be omitted if the method takes no params
if (params !== null && params !== undefined) {
req.params = params;
}
return req;
}
errResp creates a JSON-RPC 2.0 compliant response object for an error.
id
- id of the request. May be null in the case of a malformed request.code
- integer error codemsg
- string that describes the errordata
- optional. additional information about the error. type is application specific.function errResp(id, code, msg, data) {
id = id || null;
return { "jsonrpc": "2.0", "id": id, "error": { "code": code, "message": msg, "data": data } };
}
parseResponse creates a JSON-RPC response object from the raw response body
req
- JSON-RPC request object this response correlates witherror
- string describing a transport related error. should be null if no transport errors occurred. If non null, a JSON-RPC error response will be returned.
body
- Raw response body from the server. Currently should be JSON encoded, but additional serialization formats may be supported in the future.
function parseResponse(req, error, body) {
var resp;
if (error) {
resp = errResp(req.id, -32000, error);
}
else if (body !== undefined && body !== null) {
Some clients (like jQuery) want to parse the body eagerly. Assume that if we have an object, we’ve already been parsed.
if (typeof body === "object") {
resp = body;
}
else {
try {
resp = JSON.parse(body);
}
catch (e) {
resp = errResp(req.id, -32700, "Unable to parse response JSON: " + body);
}
}
}
else {
resp = errResp(req.id, -32603, "Null response body received from server");
}
return resp;
}
barrister will only call this if coercion is required (i.e. impls don’t need to check for expected type matches)
params: expectedType: string. barrister primitive type expected (int, float, string, bool) val: value to coerce
returns: if coercion successful, returns the newly coerced value. if coercion failed, returns val
function defaultCoerce(expectedType, val) {
var x, type;
if (val === null || val === undefined) {
don’t attempt to convert
return val;
}
type = typeof val;
if (type === "boolean" || type === "number") {
if (expectedType === "string") {
return val.toString();
}
}
else if (type === "string") {
if (expectedType === "bool") {
if (val === "true") {
return true;
}
else if (val === "false") {
return false;
}
}
else if (expectedType === "int") {
x = parseInt(val, 10);
if (x.toString() === val && val !== "NaN") {
return x;
}
}
else if (expectedType === "float") {
x = parseFloat(val);
if (x.toString() === val && val !== "NaN") {
return x;
}
}
}
fall through
return val;
}
The Promise class provides a way to register error/success callbacks for a Barrister function call without inlining them on the call itself.
To use this mechanism, simply omit the callback parameter when making a function call. For example:
var promise = myService.someRpcFunction("arg1", "arg2");
promise.error(function(err) { console.log("err:" + err); });
promise.success(function(result) { console.log("success: " + result); });
The Promise constructor is called internally — you don’t create these yourself.
function Promise() {
var me = this;
this.errCallback = null;
this.resultCallback = null;
this.callbackInvoked = false;
this.respReceived = false;
This callback function will be used in place of the callback you would provide inlined on a barrister function call
this.callback = function(err, result) {
me.err = err;
me.result = result;
me.respReceived = true;
me._triggerCallback();
};
}
error() lets you register the callback function to invoke if the RPC call returns a JSON-RPC error. The callback is passed the err object.
The context
param is optional. If provided, the callback
function will be invoked using call(): callback.call(context, err)
This function supports chaining. For example:
promise.error(errorHandler).success(successHandler);
Promise.prototype.error = function(callback, context) {
this.errCallback = callback;
this.errContext = context;
this._triggerCallback();
return this;
};
success() lets you register the callback function to invoke if the RPC call does not return an errror. The callback is passed the result slot from the JSON-RPC response.
The context
param is optional. If provided, the callback
function will be invoked using call(): callback.call(context, result)
This function supports chaining. For example:
promise.error(errorHandler).success(successHandler);
Promise.prototype.success = function(callback, context) {
this.resultCallback = callback;
this.resultContext = context;
this._triggerCallback();
return this;
};
_triggerCallback() is a private function that calls the registered success/error callback once we get a response from the server.
It flips an internal flag so that callbacks are only invoked once.
Promise.prototype._triggerCallback = function() {
if (this.callbackInvoked) {
return;
}
if (this.respReceived && this.err) {
If we receive an error we always want to invoke this branch, as we never want to call the success handler in this case.
if (this.errCallback) {
this.callbackInvoked = true;
if (this.errContext) {
this.errCallback.call(this.errContext, this.err);
}
else {
this.errCallback(this.err);
}
}
}
else if (this.respReceived && this.resultCallback) {
result can be null, so we don’t test for this.result as long as there’s no this.err, we can invoke this branch
this.callbackInvoked = true;
if (this.resultContext) {
this.resultCallback.call(this.resultContext, this.result);
}
else {
this.resultCallback(this.result);
}
}
};
The Contract class represents a single parsed IDL. Contracts contain interfaces, structs, and enums. It also encapsulates the type validation rules.
idl
- Barrister parsed IDL (array of objects)coerce
- optional. function that accepts (expectedType, val), and
return a coerced version of val that matches the expectedType if possible.function Contract(idl, coerce) {
var i, x, e, f;
this.idl = idl;
this.coerce = coerce;
this.interfaces = { };
this.functions = { };
this.structs = { };
this.enums = { };
this.meta = { };
Separate the IDL into interfaces/structs/enums
for (i = 0; i < idl.length; i++) {
e = idl[i];
if (e.type === "interface") {
this.interfaces[e.name] = e;
for (x = 0; x < e.functions.length; x++) {
f = e.functions[x];
this.functions[e.name+"."+f.name] = f;
}
}
else if (e.type === "struct") {
this.structs[e.name] = e;
}
else if (e.type === "enum") {
this.enums[e.name] = e;
}
else if (e.type === "meta") {
for (x in e) {
if (e.hasOwnProperty(x) && x !== "type") {
this.meta[x] = e[x];
}
}
}
}
}
Contract.prototype.coerceRecursive = function(expectedType, isArray, val) {
var me = this;
var t, fields, e, i;
if (me.coerce && val !== null && val !== undefined) {
t = typeof val;
if (isArray === true) {
if (t !== "object" || !val instanceof Array) {
val isn’t an array - bail
return val;
}
Recursively coerce all array members
for (i = 0; i < val.length; i++) {
val[i] = me.coerceRecursive(expectedType, false, val[i]);
}
return val;
}
else if (expectedType === "string" || expectedType === "bool" ||
expectedType === "int" || expectedType === "float") {
return me.coerce(expectedType, val);
}
else if (me.structs[expectedType]) {
we expect a user defined struct. val must be a JS object
if (t !== "object") {
return val;
}
get all fields for this struct, including fields on ancestors
fields = me.getAllStructFields([], me.structs[expectedType]);
for (i = 0; i < fields.length; i++) {
e = fields[i];
recursively validate the field. return on any failure.
val[e.name] = me.coerceRecursive(e.type, e.is_array, val[e.name]);
}
return val;
}
}
fall through
return val;
};
validate takes an expected type and value and returns a two element array that indicates whether the value matches the expected type.
return[0]
- boolean - true if validation passed, false if it failed
return[1]
- string that describes the validation failure. null if validation passed.
Params:
namePrefix
- string to prefix to return[1] on failureexpected
- object that holds the expected type informationisArray
- boolean that indicates whether val should be an arrayval
- value to validateContract.prototype.validate = function(namePrefix, expected, isArray, val) {
var me = this;
var i, e, fields, fieldKeys, valid, isInt;
Returned when validation passes
var okRes = [ true, null ];
namePrefix = namePrefix || "";
if (val === null || val === undefined) {
if type was annotated as [optional], then null vals are OK
if (expected.optional === true) {
return okRes;
}
else {
return [false, namePrefix + " cannot be null"];
}
}
else {
var t = typeof val;
if (isArray === true) {
IDL expects an array. Reject val if it’s not a JS Array
if (t !== "object" || !val instanceof Array) {
return me.validationErr(namePrefix, "[]"+expected.type, t, val);
}
Recursively validate all array members
for (i = 0; i < val.length; i++) {
valid = me.validate(namePrefix + "["+i+"]", expected, false, val[i]);
if (!valid[0]) {
return valid;
}
}
return okRes;
}
else if (expected.type === "string") {
return t === "string" ? okRes : me.validationErr(namePrefix, expected.type, t, val);
}
else if (expected.type === "bool") {
return t === "boolean" ? okRes : me.validationErr(namePrefix, expected.type, t, val);
}
else if (expected.type === "int" || expected.type === "float") {
if (t !== "number") {
return me.validationErr(namePrefix, expected.type, t, val);
}
This is our way of distinguishing floats from integers in JS See: http://bit.ly/zBGvzR
if (expected.type === "int") {
if (val % 1 !== 0) {
return me.validationErr(namePrefix, expected.type, "float", val);
}
}
return okRes;
}
else if (me.structs[expected.type]) {
we expect a user defined struct. val must be a JS object
if (t !== "object") {
return me.validationErr(namePrefix, expected.type, t, val);
}
get all fields for this struct, including fields on ancestors
fields = me.getAllStructFields([], me.structs[expected.type]);
fieldKeys = { };
for (i = 0; i < fields.length; i++) {
e = fields[i];
recursively validate the field. return on any failure.
valid = me.validate(namePrefix+"."+e.name, e, e.is_array, val[e.name]);
if (!valid[0]) {
return valid;
}
keep track of fields on the struct
fieldKeys[e.name] = 1;
}
iterate through all keys in val and validate that they exist on the struct
for (i in val) {
if (val.hasOwnProperty(i) && !fieldKeys[i]) {
return [ false, namePrefix+"." + i + " does not exist in type '" +
expected.type + "'" ];
}
}
return okRes;
}
else if (me.enums[expected.type]) {
enum values should always be JS strings
if (t !== "string") {
return me.validationErr(namePrefix, expected.type, t, val);
}
validate that val is in the enum.values list from the IDL. could be optimized into a map down the road.
e = me.enums[expected.type];
for (i = 0; i < e.values.length; i++) {
if (e.values[i].value === val) {
return okRes;
}
}
didn’t find it
var msg = namePrefix + " value '" + val + "' is not in the enum '" +
e.name + "': " + JSON.stringify(e.values);
return [ false, msg ];
}
else {
this is an unlikely branch and suggests the IDL is invalid
return [ false, namePrefix + " unknown type: " + expected.type ];
}
}
};
validateReq accepts a JSON-RPC request object and checks the req.params array to ensure the length and types match the IDL for the function referenced in req.method
Returns null if the request validates. Returns a JSON-RPC response object with the error property set if the request does not validate.
Contract.prototype.validateReq = function(req) {
special case for IDL request - never validate, as params are ignored by server
if (req.method === "barrister-idl") {
return null;
}
verify req.method exists on IDL
var func = this.functions[req.method];
if (!func) {
return errResp(req.id, -32601, "Method not found: " + req.method);
}
var paramLen = req.params ? req.params.length : 0;
var i, valid, msg;
verify req.params match the expected length for the IDL function
if (paramLen !== func.params.length) {
msg = "Param length: " + paramLen + " != expected length: " + func.params.length;
return errResp(req.id, -32602, msg);
}
verify each req.params type matches the function param’s expected type
for (i = 0; i < func.params.length; i++) {
valid = this.validate(func.params[i].name,
func.params[i],
func.params[i].is_array,
req.params[i]);
if (!valid[0]) {
req.params[i] = this.coerceRecursive(func.params[i].type, func.params[i].is_array, req.params[i]);
valid = this.validate(func.params[i].name,
func.params[i],
func.params[i].is_array,
req.params[i]);
}
if (!valid[0]) {
msg = "Invalid request param["+i+"]: " + valid[1];
return errResp(req.id, -32602, msg);
}
}
valid
return null;
};
Contract.prototype.validateResp = function(req, resp) {
ignore error responses and IDL requests
if (!resp.result || req.method === "barrister-idl") {
return resp;
}
verify req.method exists on IDL
var func = this.functions[req.method];
if (!func) {
return errResp(req.id, -32601, "Method not found: " + req.method);
}
var valid = this.validate("", func.returns, func.returns.is_array, resp.result);
if (!valid[0]) {
var msg = "Invalid response for " + req.method + ": " + valid[1];
if (typeof console !== "undefined" && console.log) {
console.log("ERROR: " + msg);
}
return errResp(req.id, -32001, msg);
}
else {
return resp;
}
};
getAllStructFields returns an array of fields for the given struct and its ancestors. It’s recursive.
Params:
fields
- array of fields to concat struct.fields ontostruct
- struct to concat. if struct[‘extends’] exists, then we recurseContract.prototype.getAllStructFields = function(fields, struct) {
if (struct.fields.length > 0) {
fields = fields.concat(struct.fields);
}
if (struct['extends']) {
return this.getAllStructFields(fields, this.structs[struct['extends']]);
}
else {
return fields;
}
};
validationErr returns a two element array indicating a type validation error.
Used by validate() function
Contract.prototype.validationErr = function(namePrefix, expType, actType, val) {
return [ false, namePrefix + " expects type '" + expType + "' but got type '" +
actType + "' for value: " + val ];
};
The Batch class is used to batch multiple requests against a server in a single roundtrip.
client
- a Client instance to associate with the batch.function Batch(client) {
this.client = client;
this.reqList = [];
}
proxy returns an object for the given interface that can be used to make RPC calls for that interface
Batch.prototype.proxy = function(ifaceName) {
var me = this;
return me.client._proxy(function(method) { return me._functionProxy(method); }, ifaceName);
};
Used by the proxy objects - overrides the Client.request behavior. Instead of making a call to the server, we simply push the request on an array.
Batch.prototype.request = function(method, params) {
this.reqList.push(makeRequest(method, params));
};
Internal function to dispense a function for calling the given method
Batch.prototype._functionProxy = function(method) {
var client = this;
return function() {
unlike Client._functionProxy, don’t pop the last arg since batch invocations don’t supply callbacks
var args = Array.prototype.slice.call(arguments);
client.request(method, args);
};
};
Sends the batch to the server
The callback will be passed two parameters:
err
- Single RPC error - typically only set if a transport error occursresults
- Array of all results in the batch in the same order that the requests were queued on the batch. Results may contain RPC errors as well as successes
results is array of JSON-RPC result objects. test for these keys:
error
- If set, this result is an error. Value if an object with ‘code’, ‘message’, and 'data' (optional) keys.
result
- If set, this result is a success. Value is the return value from the RPC call.Batch.prototype.send = function(callback) {
var me = this;
var i, r, errObj;
map of request ids to response objects
var idToResp = { };
requests to send to server
var reqList = [];
iterate through requests queued on this batch, validate them, and copy them to the errors list or reqList
for (i = 0; i < me.reqList.length; i++) {
r = me.reqList[i];
if (me.client.validateRequest) {
errObj = me.client.contract.validateReq(r);
if (errObj) {
idToResp[r.id] = errObj;
}
else {
reqList.push(r);
}
}
else {
reqList.push(r);
}
}
var genResponseArr = function(reqList, idToResp) {
var respList = [ ];
var respObj;
for (i = 0; i < reqList.length; i++) {
if (reqList[i].id) {
r = idToResp[reqList[i].id];
if (r) {
r = me.wrapResp(reqList[i], r);
if (r.error) {
respObj = { error: r.error };
}
else {
respObj = { result: r.result };
}
}
else {
msg = "No response received for request id: " + reqList[i].id;
respObj = { error: me.wrapResp(reqList[i], errResp(-32603, msg)) };
}
respList.push(me.wrapResp(reqList[i], respObj));
}
}
return respList;
};
We have no valid requests, so hit the callback immediately. This could occur if the batch were empty, or if all requests in the batch failed type validation
if (reqList.length === 0) {
callback(null, genResponseArr(me.reqList, idToResp));
return;
}
Send the valid requests to the server
me.client._send(reqList, function(resp) {
if (resp !== null && resp !== undefined && resp instanceof Array) {
reorder results to match the order of the requests, as server may return them in a different order
var results = [ ];
var i, r, msg;
for (i = 0; i < resp.length; i++) {
r = resp[i];
if (r.id) {
idToResp[r.id] = r;
}
}
iterate through reqList and find the response matching each request id. push onto the errors list or results list depending on whether the response was successful or not.
callback(null, genResponseArr(me.reqList, idToResp));
}
else {
single error - probably a transport related issue we can’t correlate this to any single request, so pass an empty req object to wrapResp
callback(resp, null);
}
});
};
Adds the request id and params to the response so that the batch send() callback
Batch.prototype.wrapResp = function(req, resp) {
resp.method = req.method;
resp.params = req.params;
return resp;
};
The Client class is responsible for making requests to the server using the given transport function.
transport
is a function that accepts a request object and callback function
opts
is an object that has the following keys:
coerce
- set to true to use default type coercion func, or set to a
custom function of signature: function(expectedType, val)function Client(transport, opts) {
this.transport = transport;
this.trace = null;
this.coerce = null;
You may set this to false to disable client side request validation
this.validateRequest = true;
if (opts && opts.coerce) {
if (opts.coerce === true) {
this.coerce = defaultCoerce;
}
else if (typeof opts.coerce === "function") {
this.coerce = opts.coerce;
}
}
}
laodContract requests the IDL from the server and sets a Contract object on the client if the request succeeds.
callback
- function that accepts an error. Will be called when request
completes. If successful, error will be undefined. Otherwise
it will contain a JSON-RPC response with an error slot.
If callback is not passed in, a Promise will be returned.
Client.prototype.loadContract = function(callback) {
var me = this;
var onResponse = null;
var promise = null;
if (!callback) {
promise = new Promise();
callback = promise.callback;
}
me.request("barrister-idl", [], function (err, result) {
if (err) {
callback(err);
}
else {
me.contract = new Contract(result, me.coerce);
callback(null, result);
}
});
return promise;
};
getMeta returns an object of name/value pair metadata for the client’s Contract
Client.prototype.getMeta = function() {
return this.contract.meta;
};
enableTrace turns on request/response logging
logFunc
- function to call with a string. If not provided, console.log will be used.
Client.prototype.enableTrace = function(logFunc) {
if (logFunc && (typeof logFunc === "function")) {
this.trace = logFunc;
}
else {
this.trace = function(s) { console.log(s); };
}
};
disableTrace turns off request/response logging
Client.prototype.disableTrace = function() {
this.trace = null;
};
startBatch returns a new Batch object associated with this Client
Client.prototype.startBatch = function() {
return new Batch(this);
};
proxy returns a new proxy object for the given interface.
If loadContract() has not successfully completed, or no interface exists with the given name, an exception will be thrown.
Client.prototype.proxy = function(ifaceName) {
var me = this;
return me._proxy(function(method) { return me._functionProxy(method); }, ifaceName);
};
Internal function for creating a proxy that is shared by Client and Batch.
funcProxyCreator
- function that returns a proxy function for a given method. Client and Batch provide separate functions so that the proxy behavior can differ
ifaceName
- name of interface on IDL to return proxy object forClient.prototype._proxy = function(funcProxyCreator, ifaceName) {
var me = this;
if (!me.contract) {
throw "Contract.loadContract() has not been called yet!";
}
var iface = me.contract.interfaces[ifaceName];
if (iface) {
var proxy = { };
var i, func;
for (i = 0; i < iface.functions.length; i++) {
func = iface.functions[i];
proxy[func.name] = funcProxyCreator(ifaceName+"."+func.name);
}
return proxy;
}
else {
throw "Interface not found: " + ifaceName;
}
};
Creates a function proxy for Client, which will make a request to the server when called.
This function proxy is what your code actually invokes when you call a RPC function. Pass in the arguments that the RPC function expects, plus an optional callback function. If the callback function is not included, a Promise object is returned.
Client.prototype._functionProxy = function(method) {
var client = this;
Generate the proxy function
return function() {
var callback = null,
lastArg = null,
promise = null,
args = Array.prototype.slice.call(arguments);
if (arguments.length > 0) {
Check to see if the last argument is a function. If so, we pop it from the args array, and use that as the callback function to invoke when the response is received.
lastArg = arguments[arguments.length-1];
if (lastArg !== undefined && lastArg !== null && typeof lastArg === "function") {
callback = args.pop();
}
}
If no callback function was provided, create a Promise object and use that to handle the response. You are then expected to call success() and error() on the promise to register your callbacks.
if (!callback) {
promise = new Promise();
callback = promise.callback;
}
sanity check
if (callback === undefined || callback === null || typeof callback !== "function") {
throw "Last arg to " + method + " must be a callback function!";
}
client.request(method, args, callback);
return promise;
};
};
request makes a single request to the server
Client.prototype.request = function(method, params, callback) {
var me = this;
turn method/params into a JSON-RPC request object
var req = makeRequest(method, params);
optionally validate request
if (me.validateRequest && me.contract) {
var err = me.contract.validateReq(req);
if (err) {
callback(err.error, null);
return;
}
}
send request to server
me._send(req, function(resp) {
check for JSON-RPC error
if (resp.error) {
callback(resp.error, null);
}
else {
Successful response, pass result to callback
callback(null, resp.result);
}
});
};
_send makes the request to the server
Client.prototype._send = function(req, callback) {
var me = this;
log request if trace is enabled
if (me.trace) {
me.trace("Request: " + JSON_stringify(req));
}
make request using transport provided to Client constructor
me.transport(req, function(resp) {
log response if trace is enabled
if (me.trace) {
me.trace("Response: " + JSON_stringify(resp));
}
callback(resp);
});
};
inprocClient returns a Client instance that calls the given Server directly in process. This is useful in cases where you develop separate barrister components as separate packages, but wind up combining them into a single program at runtime. It is also useful for unit testing barrister server implementations because your tests can consume the service as a Barrister client, which will perform all the type checks on requests/response values. This will catch many problems automatically that you’d normally have to write assertions for (e.g. function returned an int, but you expected a bool)
var inprocClient = function(server, opts) {
var transport = function(req, callback) {
server.handle({}, req, callback);
};
return new Client(transport, opts);
};
given a cookie name, returns its value, or null if the cookie is not found.
taken from: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/
var getCookie = function(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
};
Constructs a new httpClient
o may be a string (URL endpoint to access) or a function
If o is a function:
Barrister.parseResponse
helper
function to simplify this. Pass it the original req you were given,
an error string (if the request failed, or null if succeeded), and the raw response body.clientOpts is an optional object that is passed to the Client — see the Client constructor for details
httpOpts is an optional object with callback functions “onSuccess” and “onError” which (if defined) are invoked after each AJAX request and passed the same parameters as the error and success functions jQuery defines plus the parsed JSON-RPC response. This gives you a synchronous hook to intercept the raw response, inspect HTTP headers, etc.
var httpClient = function(o, clientOpts, httpOpts) {
var transport = o;
Assume that o is an URL endpoint
if (typeof o === "string") {
transport = function(req, callback) {
var settings = {
type: "POST",
contentType: "application/json",
data: JSON_stringify(req),
converters: {
"text json" : function(data) {
Parse JSON ourselves to ensure that parse errors are trapped and correct error code returned
return parseResponse(req, null, data);
}
},
error: function(jqXHR, textStatus, errorThrown) {
var resp;
if (jqXHR && jqXHR.status === 0) {
resp = errResp(req.id, -32002, "HTTP request aborted", jqXHR);
}
else {
resp = parseResponse(req, textStatus+" "+errorThrown, null);
}
if (httpOpts && httpOpts.onError) {
httpOpts.onError(jqXHR, textStatus, errorThrown, resp);
}
callback(resp);
},
success: function(data, textStatus, jqXHR) {
var resp = parseResponse(req, null, data);
if (httpOpts && httpOpts.onSuccess) {
httpOpts.onSuccess(data, textStatus, jqXHR, resp);
}
callback(resp);
}
}, xsrfToken = getCookie("Xsrf-Token");
if (xsrfToken) {
settings.headers = {
"X-Xsrf-Token" : xsrfToken
};
}
jQuery.ajax(o, settings);
};
}
return new Client(transport, clientOpts);
};
Export blessed functions to the Barrister namespace
Barrister.httpClient = httpClient;
Barrister.parseResponse = parseResponse;
Barrister.Client = Client;
Barrister.Contract = Contract;
Barrister.Promise = Promise;
Barrister.JSON_stringify = JSON_stringify;
}());