1 /* -----------------------------------------------------------------------
2 * Copyright (C) 2008 Georgia Public Library Service
3 * Bill Erickson <erickson@esilibrary.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * ----------------------------------------------------------------------- */
16 /* -----------------------------------------------------------------------
17 * Portions of this file are Copyright (c) Jon Nylander
19 * jsTimezoneDetect is released under the MIT License
20 * - http://www.opensource.org/licenses/mit-license.php
22 * For usage and examples, visit: http://pellepim.bitbucket.org/jstz/
23 * ----------------------------------------------------------------------- */
24 (function(e){var t=function(){"use strict";var e="s",n=function(e){var t=-e.getTimezoneOffset();return t!==null?t:0},r=function(e,t,n){var r=new Date;return e!==undefined&&r.setFullYear(e),r.setDate(n),r.setMonth(t),r},i=function(e){return n(r(e,0,2))},s=function(e){return n(r(e,5,2))},o=function(e){var t=e.getMonth()>7?s(e.getFullYear()):i(e.getFullYear()),r=n(e);return t-r!==0},u=function(){var t=i(),n=s(),r=i()-s();return r<0?t+",1":r>0?n+",1,"+e:t+",0"},a=function(){var e=u();return new t.TimeZone(t.olson.timezones[e])},f=function(e){var t=new Date(2010,6,15,1,0,0,0),n={"America/Denver":new Date(2011,2,13,3,0,0,0),"America/Mazatlan":new Date(2011,3,3,3,0,0,0),"America/Chicago":new Date(2011,2,13,3,0,0,0),"America/Mexico_City":new Date(2011,3,3,3,0,0,0),"America/Asuncion":new Date(2012,9,7,3,0,0,0),"America/Santiago":new Date(2012,9,3,3,0,0,0),"America/Campo_Grande":new Date(2012,9,21,5,0,0,0),"America/Montevideo":new Date(2011,9,2,3,0,0,0),"America/Sao_Paulo":new Date(2011,9,16,5,0,0,0),"America/Los_Angeles":new Date(2011,2,13,8,0,0,0),"America/Santa_Isabel":new Date(2011,3,5,8,0,0,0),"America/Havana":new Date(2012,2,10,2,0,0,0),"America/New_York":new Date(2012,2,10,7,0,0,0),"Asia/Beirut":new Date(2011,2,27,1,0,0,0),"Europe/Helsinki":new Date(2011,2,27,4,0,0,0),"Europe/Istanbul":new Date(2011,2,28,5,0,0,0),"Asia/Damascus":new Date(2011,3,1,2,0,0,0),"Asia/Jerusalem":new Date(2011,3,1,6,0,0,0),"Asia/Gaza":new Date(2009,2,28,0,30,0,0),"Africa/Cairo":new Date(2009,3,25,0,30,0,0),"Pacific/Auckland":new Date(2011,8,26,7,0,0,0),"Pacific/Fiji":new Date(2010,11,29,23,0,0,0),"America/Halifax":new Date(2011,2,13,6,0,0,0),"America/Goose_Bay":new Date(2011,2,13,2,1,0,0),"America/Miquelon":new Date(2011,2,13,5,0,0,0),"America/Godthab":new Date(2011,2,27,1,0,0,0),"Europe/Moscow":t,"Asia/Yekaterinburg":t,"Asia/Omsk":t,"Asia/Krasnoyarsk":t,"Asia/Irkutsk":t,"Asia/Yakutsk":t,"Asia/Vladivostok":t,"Asia/Kamchatka":t,"Europe/Minsk":t,"Australia/Perth":new Date(2008,10,1,1,0,0,0)};return n[e]};return{determine:a,date_is_dst:o,dst_start_for:f}}();t.TimeZone=function(e){"use strict";var n={"America/Denver":["America/Denver","America/Mazatlan"],"America/Chicago":["America/Chicago","America/Mexico_City"],"America/Santiago":["America/Santiago","America/Asuncion","America/Campo_Grande"],"America/Montevideo":["America/Montevideo","America/Sao_Paulo"],"Asia/Beirut":["Asia/Beirut","Europe/Helsinki","Europe/Istanbul","Asia/Damascus","Asia/Jerusalem","Asia/Gaza"],"Pacific/Auckland":["Pacific/Auckland","Pacific/Fiji"],"America/Los_Angeles":["America/Los_Angeles","America/Santa_Isabel"],"America/New_York":["America/Havana","America/New_York"],"America/Halifax":["America/Goose_Bay","America/Halifax"],"America/Godthab":["America/Miquelon","America/Godthab"],"Asia/Dubai":["Europe/Moscow"],"Asia/Dhaka":["Asia/Yekaterinburg"],"Asia/Jakarta":["Asia/Omsk"],"Asia/Shanghai":["Asia/Krasnoyarsk","Australia/Perth"],"Asia/Tokyo":["Asia/Irkutsk"],"Australia/Brisbane":["Asia/Yakutsk"],"Pacific/Noumea":["Asia/Vladivostok"],"Pacific/Tarawa":["Asia/Kamchatka"],"Africa/Johannesburg":["Asia/Gaza","Africa/Cairo"],"Asia/Baghdad":["Europe/Minsk"]},r=e,i=function(){var e=n[r],i=e.length,s=0,o=e[0];for(;s<i;s+=1){o=e[s];if(t.date_is_dst(t.dst_start_for(o))){r=o;return}}},s=function(){return typeof n[r]!="undefined"};return s()&&i(),{name:function(){return r}}},t.olson={},t.olson.timezones={"-720,0":"Etc/GMT+12","-660,0":"Pacific/Pago_Pago","-600,1":"America/Adak","-600,0":"Pacific/Honolulu","-570,0":"Pacific/Marquesas","-540,0":"Pacific/Gambier","-540,1":"America/Anchorage","-480,1":"America/Los_Angeles","-480,0":"Pacific/Pitcairn","-420,0":"America/Phoenix","-420,1":"America/Denver","-360,0":"America/Guatemala","-360,1":"America/Chicago","-360,1,s":"Pacific/Easter","-300,0":"America/Bogota","-300,1":"America/New_York","-270,0":"America/Caracas","-240,1":"America/Halifax","-240,0":"America/Santo_Domingo","-240,1,s":"America/Santiago","-210,1":"America/St_Johns","-180,1":"America/Godthab","-180,0":"America/Argentina/Buenos_Aires","-180,1,s":"America/Montevideo","-120,0":"Etc/GMT+2","-120,1":"Etc/GMT+2","-60,1":"Atlantic/Azores","-60,0":"Atlantic/Cape_Verde","0,0":"Etc/UTC","0,1":"Europe/London","60,1":"Europe/Berlin","60,0":"Africa/Lagos","60,1,s":"Africa/Windhoek","120,1":"Asia/Beirut","120,0":"Africa/Johannesburg","180,0":"Asia/Baghdad","180,1":"Europe/Moscow","210,1":"Asia/Tehran","240,0":"Asia/Dubai","240,1":"Asia/Baku","270,0":"Asia/Kabul","300,1":"Asia/Yekaterinburg","300,0":"Asia/Karachi","330,0":"Asia/Kolkata","345,0":"Asia/Kathmandu","360,0":"Asia/Dhaka","360,1":"Asia/Omsk","390,0":"Asia/Rangoon","420,1":"Asia/Krasnoyarsk","420,0":"Asia/Jakarta","480,0":"Asia/Shanghai","480,1":"Asia/Irkutsk","525,0":"Australia/Eucla","525,1,s":"Australia/Eucla","540,1":"Asia/Yakutsk","540,0":"Asia/Tokyo","570,0":"Australia/Darwin","570,1,s":"Australia/Adelaide","600,0":"Australia/Brisbane","600,1":"Asia/Vladivostok","600,1,s":"Australia/Sydney","630,1,s":"Australia/Lord_Howe","660,1":"Asia/Kamchatka","660,0":"Pacific/Noumea","690,0":"Pacific/Norfolk","720,1,s":"Pacific/Auckland","720,0":"Pacific/Tarawa","765,1,s":"Pacific/Chatham","780,0":"Pacific/Tongatapu","780,1,s":"Pacific/Apia","840,0":"Pacific/Kiritimati"},typeof exports!="undefined"?exports.jstz=t:e.jstz=t})(this);
27 var OSRF_APP_SESSION_CONNECTED = 0;
28 var OSRF_APP_SESSION_CONNECTING = 1;
29 var OSRF_APP_SESSION_DISCONNECTED = 2;
31 /* types of transport layers */
32 var OSRF_TRANSPORT_TYPE_XHR = 1;
33 var OSRF_TRANSPORT_TYPE_XMPP = 2;
34 var OSRF_TRANSPORT_TYPE_WS = 3;
35 var OSRF_TRANSPORT_TYPE_WS_SHARED = 4;
38 var OSRF_MESSAGE_TYPE_REQUEST = 'REQUEST';
39 var OSRF_MESSAGE_TYPE_STATUS = 'STATUS';
40 var OSRF_MESSAGE_TYPE_RESULT = 'RESULT';
41 var OSRF_MESSAGE_TYPE_CONNECT = 'CONNECT';
42 var OSRF_MESSAGE_TYPE_DISCONNECT = 'DISCONNECT';
44 /* message statuses */
45 var OSRF_STATUS_CONTINUE = 100;
46 var OSRF_STATUS_OK = 200;
47 var OSRF_STATUS_ACCEPTED = 202;
48 var OSRF_STATUS_NOCONTENT = 204;
49 var OSRF_STATUS_COMPLETE = 205;
50 var OSRF_STATUS_PARTIAL = 206;
51 var OSRF_STATUS_REDIRECTED = 307;
52 var OSRF_STATUS_BADREQUEST = 400;
53 var OSRF_STATUS_UNAUTHORIZED = 401;
54 var OSRF_STATUS_FORBIDDEN = 403;
55 var OSRF_STATUS_NOTFOUND = 404;
56 var OSRF_STATUS_NOTALLOWED = 405;
57 var OSRF_STATUS_TIMEOUT = 408;
58 var OSRF_STATUS_EXPFAILED = 417;
59 var OSRF_STATUS_INTERNALSERVERERROR = 500;
60 var OSRF_STATUS_NOTIMPLEMENTED = 501;
61 var OSRF_STATUS_SERVICEUNAVAILABLE = 503;
62 var OSRF_STATUS_VERSIONNOTSUPPORTED = 505;
64 // TODO: get path from ./configure prefix
65 var SHARED_WORKER_LIB = '/js/dojo/opensrf/opensrf_ws_shared.js';
67 /* The following classes map directly to network-serializable opensrf objects */
69 function osrfMessage(hash) {
72 this.hash.locale = OpenSRF.locale || 'en-US';
74 this.hash.tz = jstz.determine().name()
75 this._encodehash = true;
77 osrfMessage.prototype.threadTrace = function(d) {
78 if(arguments.length == 1)
79 this.hash.threadTrace = d;
80 return this.hash.threadTrace;
82 osrfMessage.prototype.type = function(d) {
83 if(arguments.length == 1)
85 return this.hash.type;
87 osrfMessage.prototype.payload = function(d) {
88 if(arguments.length == 1)
89 this.hash.payload = d;
90 return this.hash.payload;
92 osrfMessage.prototype.locale = function(d) {
93 if(arguments.length == 1)
95 return this.hash.locale;
97 osrfMessage.prototype.tz = function(d) {
98 if(arguments.length == 1)
102 osrfMessage.prototype.api_level = function(d) {
103 if(arguments.length == 1)
104 this.hash.api_level = d;
105 return this.hash.api_level;
107 osrfMessage.prototype.serialize = function() {
111 'threadTrace' : this.hash.threadTrace,
112 'type' : this.hash.type,
113 'payload' : (this.hash.payload) ? this.hash.payload.serialize() : 'null',
114 'locale' : this.hash.locale,
116 'api_level' : this.hash.api_level
121 function osrfMethod(hash) {
123 this._encodehash = true;
125 osrfMethod.prototype.method = function(d) {
126 if(arguments.length == 1)
127 this.hash.method = d;
128 return this.hash.method;
130 osrfMethod.prototype.params = function(d) {
131 if(arguments.length == 1)
132 this.hash.params = d;
133 return this.hash.params;
135 osrfMethod.prototype.serialize = function() {
139 'method' : this.hash.method,
140 'params' : this.hash.params
145 function osrfMethodException(hash) {
147 this._encodehash = true;
149 osrfMethodException.prototype.status = function(d) {
150 if(arguments.length == 1)
151 this.hash.status = d;
152 return this.hash.status;
154 osrfMethodException.prototype.statusCode = function(d) {
155 if(arguments.length == 1)
156 this.hash.statusCode = d;
157 return this.hash.statusCode;
159 function osrfConnectStatus(hash) {
161 this._encodehash = true;
163 osrfConnectStatus.prototype.status = function(d) {
164 if(arguments.length == 1)
165 this.hash.status = d;
166 return this.hash.status;
168 osrfConnectStatus.prototype.statusCode = function(d) {
169 if(arguments.length == 1)
170 this.hash.statusCode = d;
171 return this.hash.statusCode;
173 function osrfResult(hash) {
175 this._encodehash = true;
177 osrfResult.prototype.status = function(d) {
178 if(arguments.length == 1)
179 this.hash.status = d;
180 return this.hash.status;
182 osrfResult.prototype.statusCode = function(d) {
183 if(arguments.length == 1)
184 this.hash.statusCode = d;
185 return this.hash.statusCode;
187 osrfResult.prototype.content = function(d) {
188 if(arguments.length == 1)
189 this.hash.content = d;
190 return this.hash.content;
192 function osrfResultPartial(hash) {
194 this._encodehash = true;
196 osrfResultPartial.prototype.status = function(d) {
197 if(arguments.length == 1)
198 this.hash.status = d;
199 return this.hash.status;
201 osrfResultPartial.prototype.statusCode = function(d) {
202 if(arguments.length == 1)
203 this.hash.statusCode = d;
204 return this.hash.statusCode;
206 osrfResultPartial.prototype.content = function(d) {
207 if(arguments.length == 1)
208 this.hash.content = d;
209 return this.hash.content;
211 function osrfResultPartialComplete(hash) {
213 this._encodehash = true;
215 osrfResultPartialComplete.prototype.status = function(d) {
216 if(arguments.length == 1)
217 this.hash.status = d;
218 return this.hash.status;
220 osrfResultPartialComplete.prototype.statusCode = function(d) {
221 if(arguments.length == 1)
222 this.hash.statusCode = d;
223 return this.hash.statusCode;
225 osrfResultPartialComplete.prototype.content = function(d) {
226 if(arguments.length == 1)
227 this.hash.content = d;
228 return this.hash.content;
231 function osrfServerError(hash) {
233 this._encodehash = true;
235 osrfServerError.prototype.status = function(d) {
236 if(arguments.length == 1)
237 this.hash.status = d;
238 return this.hash.status;
240 osrfServerError.prototype.statusCode = function(d) {
241 if(arguments.length == 1)
242 this.hash.statusCode = d;
243 return this.hash.statusCode;
245 function osrfContinueStatus(hash) {
247 this._encodehash = true;
249 osrfContinueStatus.prototype.status = function(d) {
250 if(arguments.length == 1)
251 this.hash.status = d;
252 return this.hash.status;
254 osrfContinueStatus.prototype.statusCode = function(d) {
255 if(arguments.length == 1)
256 this.hash.statusCode = d;
257 return this.hash.statusCode;
261 OpenSRF.tz = jstz.determine().name();
262 OpenSRF.locale = null;
263 OpenSRF.api_level = 1;
265 /* makes cls a subclass of pcls */
266 OpenSRF.set_subclass = function(cls, pcls) {
267 var str = cls+'.prototype = new '+pcls+'();';
268 str += cls+'.prototype.constructor = '+cls+';';
269 str += cls+'.baseClass = '+pcls+'.prototype.constructor;';
270 str += cls+'.prototype["super"] = '+pcls+'.prototype;';
275 /* general session superclass */
276 OpenSRF.Session = function() {
277 this.remote_id = null;
278 this.state = OSRF_APP_SESSION_DISCONNECTED;
281 OpenSRF.Session.transport = OSRF_TRANSPORT_TYPE_XHR;
282 OpenSRF.Session.cache = {};
284 OpenSRF.Session.find_session = function(thread_trace) {
285 return OpenSRF.Session.cache[thread_trace];
287 OpenSRF.Session.prototype.cleanup = function() {
288 delete OpenSRF.Session.cache[this.thread];
291 OpenSRF.Session.prototype.send = function(osrf_msg, args) {
292 args = (args) ? args : {};
293 switch(OpenSRF.Session.transport) {
294 case OSRF_TRANSPORT_TYPE_WS:
295 return this.send_ws(osrf_msg);
296 case OSRF_TRANSPORT_TYPE_WS_SHARED:
297 return this.send_ws_shared(osrf_msg);
298 case OSRF_TRANSPORT_TYPE_XHR:
299 return this.send_xhr(osrf_msg, args);
300 case OSRF_TRANSPORT_TYPE_XMPP:
301 return this.send_xmpp(osrf_msg, args);
305 OpenSRF.Session.prototype.send_xhr = function(osrf_msg, args) {
306 args.thread = this.thread;
307 args.rcpt = this.remote_id;
308 args.rcpt_service = this.service;
309 new OpenSRF.XHRequest(osrf_msg, args).send();
312 OpenSRF.websocketConnected = function() {
313 return OpenSRF.sharedWebsocketConnected || (
314 OpenSRF.websocketConnection &&
315 OpenSRF.websocketConnection.connected()
319 OpenSRF.Session.prototype.send_ws = function(osrf_msg) {
321 // XXX there appears to be a bug in Chromium where loading the
322 // same page multiple times (without a refresh or cache clear)
323 // causes the SharedWorker to fail to instantiate on
324 // every other page load. Disabling SharedWorker's entirely
326 if (false /* ^-- */ && typeof SharedWorker == 'function'
329 * https://bugzilla.mozilla.org/show_bug.cgi?id=504553#c73
330 * Firefox does not yet support WebSockets in worker threads
332 && !navigator.userAgent.match(/Firefox/)
334 // vanilla websockets requested, but this browser supports
335 // shared workers, so use those instead.
336 return this.send_ws_shared(osrf_msg);
339 // otherwise, use a per-tab connection
341 if (!OpenSRF.websocketConnection) {
342 this.setup_single_ws();
346 service : this.service,
347 thread : this.thread,
348 osrf_msg : [osrf_msg.serialize()]
351 OpenSRF.websocketConnection.send(json);
354 OpenSRF.Session.prototype.setup_single_ws = function() {
355 OpenSRF.websocketConnection = new OpenSRF.WebSocket();
357 OpenSRF.websocketConnection.onmessage = function(msg) {
359 var msg = JSON2js(msg);
362 "Error parsing JSON in shared WS response: " + msg);
366 if (msg.transport_error) {
367 // Websockets gateway returns bounced messages (e.g. for
368 // requets to unavailable services) with a transport_error
371 'Websocket request failed with a transport error', msg);
373 var ses = OpenSRF.Session.find_session(msg.thread);
375 if (msg.osrf_msg && msg.osrf_msg[0]) {
376 var req = ses.find_request(msg.osrf_msg[0].threadTrace());
378 var handler = req.ontransporterror || req.onerror;
380 handler('Service ' + ses.service + ' unavailable');
385 return; // No viable error handlers
389 new OpenSRF.NetMessage(
390 null, null, msg.thread, null, msg.osrf_msg)
397 OpenSRF.Session.setup_shared_ws = function() {
398 OpenSRF.Session.transport = OSRF_TRANSPORT_TYPE_WS_SHARED;
400 OpenSRF.sharedWSWorker = new SharedWorker(SHARED_WORKER_LIB);
402 OpenSRF.sharedWSWorker.port.addEventListener('message', function(e) {
405 if (data.action == 'message') {
406 // pass all inbound message up the opensrf stack
408 OpenSRF.sharedWebsocketConnected = true;
411 msg = JSON2js(data.message);
414 "Error parsing JSON in shared WS response: " + msg);
418 new OpenSRF.NetMessage(
419 null, null, msg.thread, null, msg.osrf_msg)
426 if (data.action == 'event') {
427 if (data.type.match(/onclose|onerror/)) {
428 OpenSRF.sharedWebsocketConnected = false;
429 if (OpenSRF.onWebSocketClosed)
430 OpenSRF.onWebSocketClosed();
431 if (data.type.match(/onerror/))
432 throw new Error(data.message);
437 OpenSRF.sharedWSWorker.port.start();
440 OpenSRF.Session.prototype.send_ws_shared = function(message) {
442 if (!OpenSRF.sharedWSWorker)
443 OpenSRF.Session.setup_shared_ws();
446 service : this.service,
447 thread : this.thread,
448 osrf_msg : [message.serialize()]
451 OpenSRF.sharedWSWorker.port.postMessage({
453 // pass the thread additionally as a stand-alone value so the
454 // worker can more efficiently inspect it.
455 thread : this.thread,
461 OpenSRF.Session.prototype.send_xmpp = function(osrf_msg, args) {
462 alert('xmpp transport not implemented');
466 /* client sessions make requests */
467 OpenSRF.ClientSession = function(service) {
468 this.service = service;
469 this.remote_id = null;
470 this.locale = OpenSRF.locale || 'en-US';
471 this.tz = OpenSRF.tz;
474 this.onconnect = null;
475 this.thread = Math.random() + '' + new Date().getTime();
476 OpenSRF.Session.cache[this.thread] = this;
478 OpenSRF.set_subclass('OpenSRF.ClientSession', 'OpenSRF.Session');
481 OpenSRF.ClientSession.prototype.connect = function(args) {
482 args = (args) ? args : {};
483 this.remote_id = null;
485 if (this.state == OSRF_APP_SESSION_CONNECTED) {
486 if (args.onconnect) args.onconnect();
491 this.onconnect = args.onconnect;
494 /* if no handler is provided, make this a synchronous call */
495 this.timeout = (args.timeout) ? args.timeout : 5;
498 message = new osrfMessage({
499 'threadTrace' : this.last_id++,
500 'type' : OSRF_MESSAGE_TYPE_CONNECT
503 this.send(message, {'timeout' : this.timeout});
505 if(this.onconnect || this.state == OSRF_APP_SESSION_CONNECTED)
511 OpenSRF.ClientSession.prototype.disconnect = function(args) {
513 if (this.state == OSRF_APP_SESSION_CONNECTED) {
516 'threadTrace' : this.last_id++,
517 'type' : OSRF_MESSAGE_TYPE_DISCONNECT
522 this.remote_id = null;
523 this.state = OSRF_APP_SESSION_DISCONNECTED;
527 OpenSRF.ClientSession.prototype.request = function(args) {
529 if(this.state != OSRF_APP_SESSION_CONNECTED)
530 this.remote_id = null;
532 if(typeof args == 'string') {
534 for(var i = 1; i < arguments.length; i++)
535 params.push(arguments[i]);
542 if(typeof args == 'undefined')
546 var req = new OpenSRF.Request(this, this.last_id++, args);
547 this.requests.push(req);
551 OpenSRF.ClientSession.prototype.find_request = function(reqid) {
552 for(var i = 0; i < this.requests.length; i++) {
553 var req = this.requests[i];
554 if(req.reqid == reqid)
560 OpenSRF.Request = function(session, reqid, args) {
561 this.session = session;
565 this.onresponse = args.onresponse;
566 this.oncomplete = args.oncomplete;
567 this.onerror = args.onerror;
568 this.onmethoderror = args.onmethoderror;
569 this.ontransporterror = args.ontransporterror;
571 this.method = args.method;
572 this.params = args.params;
573 this.timeout = args.timeout;
574 this.api_level = args.api_level || OpenSRF.api_level;
575 this.response_queue = [];
576 this.part_response_buffer = '';
577 this.complete = false;
580 OpenSRF.Request.prototype.peek_last = function(timeout) {
581 if(this.response_queue.length > 0) {
582 var x = this.response_queue.pop();
583 this.response_queue.push(x);
589 OpenSRF.Request.prototype.peek = function(timeout) {
590 if(this.response_queue.length > 0)
591 return this.response_queue[0];
595 OpenSRF.Request.prototype.recv = function(timeout) {
596 if(this.response_queue.length > 0)
597 return this.response_queue.shift();
601 OpenSRF.Request.prototype.send = function() {
602 method = new osrfMethod({'method':this.method, 'params':this.params});
603 message = new osrfMessage({
604 'threadTrace' : this.reqid,
605 'type' : OSRF_MESSAGE_TYPE_REQUEST,
607 'locale' : this.session.locale,
608 'tz' : this.session.tz,
609 'api_level' : this.api_level
612 this.session.send(message, {
613 'timeout' : this.timeout,
614 'onresponse' : this.onresponse,
615 'oncomplete' : this.oncomplete,
616 'onerror' : this.onerror,
617 'onmethoderror' : this.onmethoderror,
618 'ontransporterror' : this.ontransporterror
622 OpenSRF.NetMessage = function(to, from, thread, body, osrf_msg) {
625 this.thread = thread;
627 this.osrf_msg = osrf_msg;
630 OpenSRF.Stack = function() {
633 // global inbound message queue
634 OpenSRF.Stack.queue = [];
639 dump(msg + '\n'); // xulrunner
645 // ses may be passed to us by the network handler
646 OpenSRF.Stack.push = function(net_msg, callbacks) {
647 var ses = OpenSRF.Session.find_session(net_msg.thread);
649 ses.remote_id = net_msg.from;
651 // NetMessage's from websocket connections are parsed before they get here
652 osrf_msgs = net_msg.osrf_msg;
657 osrf_msgs = JSON2js(net_msg.body);
659 // TODO: pretty sure we don't need this..
660 if (OpenSRF.Session.transport == OSRF_TRANSPORT_TYPE_WS) {
661 // WebSocketRequests wrap the content
662 osrf_msgs = osrf_msgs.osrf_msg;
666 log('Error parsing OpenSRF message body as JSON: ' + net_msg.body + '\n' + E);
669 * For unknown reasons, the Content-Type header will occasionally
670 * be included in the XHR.responseText for multipart/mixed messages.
671 * When this happens, strip the header and newlines from the message
674 net_msg.body = net_msg.body.replace(/^.*\n\n/, '');
675 log('Cleaning up and retrying...');
678 osrf_msgs = JSON2js(net_msg.body);
680 log('Unable to clean up message, giving up: ' + net_msg.body);
686 // push the latest responses onto the end of the inbound message queue
687 for(var i = 0; i < osrf_msgs.length; i++)
688 OpenSRF.Stack.queue.push({msg : osrf_msgs[i], ses : ses});
690 // continue processing responses, oldest to newest
691 while(OpenSRF.Stack.queue.length) {
692 var data = OpenSRF.Stack.queue.shift();
693 OpenSRF.Stack.handle_message(data.ses, data.msg);
697 OpenSRF.Stack.handle_message = function(ses, osrf_msg) {
699 var req = ses.find_request(osrf_msg.threadTrace());
701 var payload = osrf_msg.payload();
702 var status = payload.statusCode();
703 var status_text = payload.status();
705 if(osrf_msg.type() == OSRF_MESSAGE_TYPE_STATUS) {
708 if(status == OSRF_STATUS_COMPLETE) {
711 if(req.oncomplete && !req.oncomplete_called) {
712 req.oncomplete_called = true;
713 return req.oncomplete(req);
718 if(status == OSRF_STATUS_OK) {
719 ses.state = OSRF_APP_SESSION_CONNECTED;
721 /* call the connect callback */
722 if(ses.onconnect && !ses.onconnect_called) {
723 ses.onconnect_called = true;
724 return ses.onconnect();
728 // capture all 400's and 500's as method errors
729 if ((status+'').match(/^4/) || (status+'').match(/^5/)) {
730 if(req && req.onmethoderror)
731 return req.onmethoderror(req, status, status_text);
735 if(osrf_msg.type() == OSRF_MESSAGE_TYPE_RESULT) {
736 req = ses.find_request(osrf_msg.threadTrace());
738 if (status == OSRF_STATUS_PARTIAL) {
739 req.part_response_buffer += payload.content()
740 return; // we're just collecting a big chunked payload
741 } else if (status == OSRF_STATUS_NOCONTENT) {
742 payload.content( JSON2js(req.part_response_buffer) );
743 payload.statusCode( OSRF_STATUS_OK );
744 req.part_response_buffer = '';
746 req.response_queue.push(payload);
748 return req.onresponse(req);