1/* 2 * JSON-RPC JavaScript client 3 * 4 * $Id: jsonrpc.js,v 1.3 2010/04/29 07:07:10 zhuliang Exp $ 5 * 6 * Copyright (c) 2003-2004 Jan-Klaas Kollhof 7 * Copyright (c) 2005 Michael Clark, Metaparadigm Pte Ltd 8 * 9 * This code is based on Jan-Klaas' JavaScript o lait library (jsolait). 10 * 11 * Licensed under the Apache License, Version 2.0 (the "License"); 12 * you may not use this file except in compliance with the License. 13 * You may obtain a copy of the License at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, software 18 * distributed under the License is distributed on an "AS IS" BASIS, 19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 * See the License for the specific language governing permissions and 21 * limitations under the License. 22 * 23 */ 24 25/* escape a character */ 26 27escapeJSONChar = 28function escapeJSONChar(c) 29{ 30 if(c == "\"" || c == "\\") return "\\" + c; 31 else if (c == "\b") return "\\b"; 32 else if (c == "\f") return "\\f"; 33 else if (c == "\n") return "\\n"; 34 else if (c == "\r") return "\\r"; 35 else if (c == "\t") return "\\t"; 36 var hex = c.charCodeAt(0).toString(16); 37 if(hex.length == 1) return "\\u000" + hex; 38 else if(hex.length == 2) return "\\u00" + hex; 39 else if(hex.length == 3) return "\\u0" + hex; 40 else return "\\u" + hex; 41}; 42 43 44/* encode a string into JSON format */ 45 46escapeJSONString = 47function escapeJSONString(s) 48{ 49 /* The following should suffice but Safari's regex is b0rken 50 (doesn't support callback substitutions) 51 return "\"" + s.replace(/([^\u0020-\u007f]|[\\\"])/g, 52 escapeJSONChar) + "\""; 53 */ 54 55 /* Rather inefficient way to do it */ 56 var parts = s.split(""); 57 for(var i=0; i < parts.length; i++) { 58 var c =parts[i]; 59 if(c == '"' || 60 c == '\\' || 61 c.charCodeAt(0) < 32 || 62 c.charCodeAt(0) >= 128) 63 parts[i] = escapeJSONChar(parts[i]); 64 } 65 return "\"" + parts.join("") + "\""; 66}; 67 68 69/* Marshall objects to JSON format */ 70 71toJSON = function toJSON(o) 72{ 73 if(o == null) { 74 return "null"; 75 } else if(o.constructor == String) { 76 return escapeJSONString(o); 77 } else if(o.constructor == Number) { 78 return o.toString(); 79 } else if(o.constructor == Boolean) { 80 return o.toString(); 81 } else if(o.constructor == Date) { 82 return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}'; 83 } else if(o.constructor == Array) { 84 var v = []; 85 for(var i = 0; i < o.length; i++) v.push(toJSON(o[i])); 86 return "[" + v.join(", ") + "]"; 87 } else { 88 var v = []; 89 for(attr in o) { 90 if(o[attr] == null) v.push("\"" + attr + "\": null"); 91 else if(typeof o[attr] == "function"); /* skip */ 92 else v.push(escapeJSONString(attr) + ": " + toJSON(o[attr])); 93 } 94 return "{" + v.join(", ") + "}"; 95 } 96}; 97 98 99/* JSONRpcClient constructor */ 100 101JSONRpcClient = 102function JSONRpcClient_ctor(serverURL, user, pass, objectID) 103{ 104 this.serverURL = serverURL; 105 this.user = user; 106 this.pass = pass; 107 this.objectID = objectID; 108 109 /* Add standard methods */ 110 if(this.objectID) { 111 this._addMethods(["listMethods"]); 112 var req = this._makeRequest("listMethods", []); 113 } else { 114 this._addMethods(["system.listMethods"]); 115 var req = this._makeRequest("system.listMethods", []); 116 } 117 var m = this._sendRequest(req); 118 this._addMethods(m); 119}; 120 121 122/* JSONRpcCLient.Exception */ 123 124JSONRpcClient.Exception = 125function JSONRpcClient_Exception_ctor(code, message, javaStack) 126{ 127 this.code = code; 128 var name; 129 if(javaStack) { 130 this.javaStack = javaStack; 131 var m = javaStack.match(/^([^:]*)/); 132 if(m) name = m[0]; 133 } 134 if(name) this.name = name; 135 else this.name = "JSONRpcClientException"; 136 this.message = message; 137}; 138 139JSONRpcClient.Exception.CODE_REMOTE_EXCEPTION = 490; 140JSONRpcClient.Exception.CODE_ERR_CLIENT = 550; 141JSONRpcClient.Exception.CODE_ERR_PARSE = 590; 142JSONRpcClient.Exception.CODE_ERR_NOMETHOD = 591; 143JSONRpcClient.Exception.CODE_ERR_UNMARSHALL = 592; 144JSONRpcClient.Exception.CODE_ERR_MARSHALL = 593; 145 146JSONRpcClient.Exception.prototype = new Error(); 147 148JSONRpcClient.Exception.prototype.toString = 149function JSONRpcClient_Exception_toString(code, msg) 150{ 151 return this.name + ": " + this.message; 152}; 153 154 155/* Default top level exception handler */ 156 157JSONRpcClient.default_ex_handler = 158function JSONRpcClient_default_ex_handler(e) { alert(e); }; 159 160 161/* Client settable variables */ 162 163JSONRpcClient.toplevel_ex_handler = JSONRpcClient.default_ex_handler; 164JSONRpcClient.profile_async = false; 165JSONRpcClient.max_req_active = 1; 166JSONRpcClient.requestId = 1; 167 168 169/* JSONRpcClient implementation */ 170 171JSONRpcClient.prototype._createMethod = 172function JSONRpcClient_createMethod(methodName) 173{ 174 var fn=function() 175 { 176 var args = []; 177 var callback = null; 178 for(var i=0;i<arguments.length;i++) args.push(arguments[i]); 179 if(typeof args[0] == "function") callback = args.shift(); 180 var req = fn.client._makeRequest.call(fn.client, fn.methodName, 181 args, callback); 182 if(callback == null) {
183 return fn.client._sendRequest.call(fn.client, req); 184 } else { 185 JSONRpcClient.async_requests.push(req); 186 JSONRpcClient.kick_async(); 187 return req.requestId; 188 } 189 }; 190 fn.client = this; 191 fn.methodName = methodName; 192 return fn; 193}; 194 195JSONRpcClient.prototype._addMethods = 196function JSONRpcClient_addMethods(methodNames) 197{ 198 for(var i=0; i<methodNames.length; i++) { 199 var obj = this; 200 var names = methodNames[i].split("."); 201 for(var n=0; n<names.length-1; n++) { 202 var name = names[n]; 203 if(obj[name]) { 204 obj = obj[name]; 205 } else { 206 obj[name] = new Object(); 207 obj = obj[name]; 208 } 209 } 210 var name = names[names.length-1]; 211 if(!obj[name]) { 212 var method = this._createMethod(methodNames[i]); 213 obj[name] = method; 214 } 215 } 216}; 217 218JSONRpcClient._getCharsetFromHeaders = 219function JSONRpcClient_getCharsetFromHeaders(http) 220{ 221 try { 222 var contentType = http.getResponseHeader("Content-type"); 223 var parts = contentType.split(/\s*;\s*/); 224 for(var i =0; i < parts.length; i++) { 225 if(parts[i].substring(0, 8) == "charset=") 226 return parts[i].substring(8, parts[i].length); 227 } 228 } catch (e) {} 229 return "UTF-8"; /* default */ 230}; 231 232/* Async queue globals */ 233JSONRpcClient.async_requests = []; 234JSONRpcClient.async_inflight = {}; 235JSONRpcClient.async_responses = []; 236JSONRpcClient.async_timeout = null; 237JSONRpcClient.num_req_active = 0; 238 239JSONRpcClient._async_handler = 240function JSONRpcClient_async_handler() 241{ 242 JSONRpcClient.async_timeout = null; 243 244 while(JSONRpcClient.async_responses.length > 0) { 245 var res = JSONRpcClient.async_responses.shift(); 246 if(res.canceled) continue; 247 if(res.profile) res.profile.dispatch = new Date(); 248 try { 249 res.cb(res.result, res.ex, res.profile); 250 } catch(e) { 251 JSONRpcClient.toplevel_ex_handler(e); 252 } 253 } 254 255 while(JSONRpcClient.async_requests.length > 0 && 256 JSONRpcClient.num_req_active < JSONRpcClient.max_req_active) { 257 var req = JSONRpcClient.async_requests.shift(); 258 if(req.canceled) continue; 259 req.client._sendRequest.call(req.client, req); 260 } 261}; 262 263JSONRpcClient.kick_async = 264function JSONRpcClient_kick_async() 265{ 266 if(JSONRpcClient.async_timeout == null) 267 JSONRpcClient.async_timeout = 268 setTimeout(JSONRpcClient._async_handler, 0); 269}; 270 271JSONRpcClient.cancelRequest = 272function JSONRpcClient_cancelRequest(requestId) 273{ 274 /* If it is in flight then mark it as canceled in the inflight map 275 and the XMLHttpRequest callback will discard the reply. */ 276 if(JSONRpcClient.async_inflight[requestId]) { 277 JSONRpcClient.async_inflight[requestId].canceled = true; 278 return true; 279 } 280 281 /* If its not in flight yet then we can just mark it as canceled in 282 the the request queue and it will get discarded before being sent. */ 283 for(var i in JSONRpcClient.async_requests) { 284 if(JSONRpcClient.async_requests[i].requestId == requestId) { 285 JSONRpcClient.async_requests[i].canceled = true; 286 return true; 287 } 288 } 289 290 /* It may have returned from the network and be waiting for its callback 291 to be dispatched, so mark it as canceled in the response queue 292 and the response will get discarded before calling the callback. */ 293 for(var i in JSONRpcClient.async_responses) { 294 if(JSONRpcClient.async_responses[i].requestId == requestId) { 295 JSONRpcClient.async_responses[i].canceled = true; 296 return true; 297 } 298 } 299 300 return false; 301}; 302 303JSONRpcClient.prototype._makeRequest = 304function JSONRpcClient_makeRequest(methodName, args, cb) 305{ 306 var req = {}; 307 req.client = this; 308 req.requestId = JSONRpcClient.requestId++; 309 310 var obj = {}; 311 obj.id = req.requestId; 312 if (this.objectID) 313 obj.method = ".obj#" + this.objectID + "." + methodName; 314 else 315 obj.method = methodName; 316 obj.params = args; 317 318 if (cb) req.cb = cb; 319 if (JSONRpcClient.profile_async) 320 req.profile = { "submit": new Date() }; 321 req.data = toJSON(obj); 322 323 return req; 324}; 325 326JSONRpcClient.prototype._sendRequest = 327function JSONRpcClient_sendRequest(req) 328{ 329 if(req.profile) req.profile.start = new Date(); 330 331 /* Get free http object from the pool */
332 var http = JSONRpcClient.poolGetHTTPRequest(); 333 JSONRpcClient.num_req_active++; 334 335 /* Send the request */ 336 if (typeof(this.user) == "undefined") { 337 http.open("POST", this.serverURL, (req.cb != null)); 338 } else { 339 http.open("POST", this.serverURL, (req.cb != null), this.user, this.pass); 340 } 341 342 /* setRequestHeader is missing in Opera 8 Beta */ 343 try { http.setRequestHeader("Content-type", "text/plain"); } catch(e) {} 344 345 /* Construct call back if we have one */ 346 if(req.cb) { 347 var self = this; 348 http.onreadystatechange = function() { 349 if(http.readyState == 4) { 350 http.onreadystatechange = function () {}; 351 var res = { "cb": req.cb, "result": null, "ex": null}; 352 if (req.profile) { 353 res.profile = req.profile; 354 res.profile.end = new Date(); 355 } 356 try { res.result = self._handleResponse(http); } 357 catch(e) { res.ex = e; } 358 if(!JSONRpcClient.async_inflight[req.requestId].canceled) 359 JSONRpcClient.async_responses.push(res); 360 delete JSONRpcClient.async_inflight[req.requestId]; 361 JSONRpcClient.kick_async(); 362 } 363 }; 364 } else { 365 http.onreadystatechange = function() {}; 366 } 367 368 JSONRpcClient.async_inflight[req.requestId] = req; 369 370 try { 371 http.send(req.data); 372 } catch(e) { 373 JSONRpcClient.poolReturnHTTPRequest(http); 374 JSONRpcClient.num_req_active--; 375 throw new JSONRpcClient.Exception 376 (JSONRpcClient.Exception.CODE_ERR_CLIENT, "Connection failed"); 377 } 378 379 if(!req.cb) return this._handleResponse(http); 380}; 381 382JSONRpcClient.prototype._handleResponse = 383function JSONRpcClient_handleResponse(http) 384{ 385 /* Get the charset */ 386 if(!this.charset) { 387 this.charset = JSONRpcClient._getCharsetFromHeaders(http); 388 } 389 390 /* Get request results */ 391 var status, statusText, data; 392 try { 393 status = http.status; 394 statusText = http.statusText; 395 data = http.responseText; 396 } catch(e) { 397 JSONRpcClient.poolReturnHTTPRequest(http); 398 JSONRpcClient.num_req_active--; 399 JSONRpcClient.kick_async(); 400 throw new JSONRpcClient.Exception 401 (JSONRpcClient.Exception.CODE_ERR_CLIENT, "Connection failed"); 402 } 403 404 /* Return http object to the pool; */ 405 JSONRpcClient.poolReturnHTTPRequest(http); 406 JSONRpcClient.num_req_active--; 407 408 /* Unmarshall the response */ 409 if(status != 200) { 410 throw new JSONRpcClient.Exception(status, statusText); 411 } 412 var obj; 413 try { 414 eval("obj = " + data); 415 } catch(e) { 416 throw new JSONRpcClient.Exception(550, "error parsing result"); 417 } 418 if(obj.error) 419 throw new JSONRpcClient.Exception(obj.error.code, obj.error.msg, 420 obj.error.trace); 421 var res = obj.result; 422 423 /* Handle CallableProxy */ 424 if(res && res.objectID && res.JSONRPCType == "CallableReference") 425 return new JSONRpcClient(this.serverURL, this.user, 426 this.pass, res.objectID); 427 428 return res; 429}; 430 431 432/* XMLHttpRequest wrapper code */ 433 434/* XMLHttpRequest pool globals */ 435JSONRpcClient.http_spare = []; 436JSONRpcClient.http_max_spare = 8; 437 438JSONRpcClient.poolGetHTTPRequest = 439function JSONRpcClient_pool_getHTTPRequest() 440{ 441 if(JSONRpcClient.http_spare.length > 0) { 442 return JSONRpcClient.http_spare.pop(); 443 } 444 return JSONRpcClient.getHTTPRequest(); 445}; 446 447JSONRpcClient.poolReturnHTTPRequest = 448function JSONRpcClient_poolReturnHTTPRequest(http) 449{ 450 if(JSONRpcClient.http_spare.length >= JSONRpcClient.http_max_spare) 451 delete http; 452 else 453 JSONRpcClient.http_spare.push(http); 454}; 455 456JSONRpcClient.msxmlNames = [ "MSXML2.XMLHTTP.5.0", 457 "MSXML2.XMLHTTP.4.0", 458 "MSXML2.XMLHTTP.3.0", 459 "MSXML2.XMLHTTP", 460 "Microsoft.XMLHTTP" ]; 461 462JSONRpcClient.getHTTPRequest = 463function JSONRpcClient_getHTTPRequest() 464{ 465 /* Mozilla XMLHttpRequest */ 466 try { 467 JSONRpcClient.httpObjectName = "XMLHttpRequest"; 468 return new XMLHttpRequest(); 469 } catch(e) {} 470 471 /* Microsoft MSXML ActiveX */ 472 for (var i=0;i < JSONRpcClient.msxmlNames.length; i++) { 473 try { 474 JSONRpcClient.httpObjectName = JSONRpcClient.msxmlNames[i]; 475 return new ActiveXObject(JSONRpcClient.msxmlNames[i]); 476 } catch (e) {} 477 } 478 479 /* None found */ 480 JSONRpcClient.httpObjectName = null;
481 throw new JSONRpcClient.Exception(0, "Can't create XMLHttpRequest object"); 482}; 483 484//å®ä¹jsonrpc对象ï¼å¨æ¤å®ä¹ï¼åªè¦å¼ç¨äºæ¤jsonrpcæä»¶çé½å¯ä½¿ç¨ 485var jsonrpc = new JSONRpcClient("/JSON-RPC");
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.