diff options
Diffstat (limited to '')
| -rw-r--r-- | js/dojo-1.6/dojox/xmpp/TransportSession.js | 518 |
1 files changed, 518 insertions, 0 deletions
diff --git a/js/dojo-1.6/dojox/xmpp/TransportSession.js b/js/dojo-1.6/dojox/xmpp/TransportSession.js new file mode 100644 index 0000000..417829f --- /dev/null +++ b/js/dojo-1.6/dojox/xmpp/TransportSession.js @@ -0,0 +1,518 @@ +/*
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
+ Available via Academic Free License >= 2.1 OR the modified BSD license.
+ see: http://dojotoolkit.org/license for details
+*/
+
+
+if(!dojo._hasResource["dojox.xmpp.TransportSession"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.xmpp.TransportSession"] = true;
+dojo.provide("dojox.xmpp.TransportSession");
+dojo.require("dojox.xmpp.bosh");
+dojo.require("dojox.xmpp.util");
+dojo.require("dojox.data.dom");
+
+dojox.xmpp.TransportSession = function(props) {
+ // we have to set this here because "this" doesn't work
+ // in the dojo.extend call.
+ this.sendTimeout = (this.wait+20)*1000;
+
+ //mixin any options that we want to provide to this service
+ if (props && dojo.isObject(props)) {
+ dojo.mixin(this, props);
+ if(this.useScriptSrcTransport){
+ this.transportIframes = [];
+ }
+ }
+
+};
+
+dojo.extend(dojox.xmpp.TransportSession, {
+
+ /* options/defaults */
+ rid: 0,
+ hold: 1,
+ polling:1000,
+ secure: false,
+ wait: 60,
+ lang: 'en',
+ submitContentType: 'text/xml; charset=utf=8',
+ serviceUrl: '/httpbind',
+ defaultResource: "dojoIm",
+ domain: 'imserver.com',
+ sendTimeout: 0, //(this.wait+20)*1000
+
+ useScriptSrcTransport:false,
+
+
+ keepAliveTimer:null,
+
+ //status
+ state: "NotReady",
+ transmitState: "Idle",
+
+ protocolPacketQueue: [],
+ outboundQueue: [],
+ outboundRequests: {},
+ inboundQueue: [],
+ deferredRequests: {},
+ matchTypeIdAttribute: {},
+
+ open: function() {
+ this.status = "notReady";
+ this.rid = Math.round(Math.random() * 1000000000);
+ this.protocolPacketQueue = [];
+ this.outboundQueue = [];
+ this.outboundRequests = {};
+ this.inboundQueue = [];
+ this.deferredRequests = {};
+ this.matchTypeIdAttribute = {};
+
+
+ this.keepAliveTimer = setTimeout(dojo.hitch(this, "_keepAlive"), 10000);
+
+ if(this.useScriptSrcTransport){
+ dojox.xmpp.bosh.initialize({
+ iframes: this.hold+1,
+ load: dojo.hitch(this, function(){
+ this._sendLogin();
+ })
+ });
+ } else {
+ this._sendLogin();
+ }
+ },
+
+ _sendLogin: function() {
+ var rid = this.rid++;
+ var req = {
+ content: this.submitContentType,
+ hold: this.hold,
+ rid: rid,
+ to: this.domain,
+ secure: this.secure,
+ wait: this.wait,
+ "xml:lang": this.lang,
+ "xmpp:version": "1.0",
+ xmlns: dojox.xmpp.xmpp.BODY_NS,
+ "xmlns:xmpp": "urn:xmpp:xbosh"
+ };
+
+ var msg = dojox.xmpp.util.createElement("body", req, true);
+ this.addToOutboundQueue(msg, rid);
+ },
+
+ _sendRestart: function(){
+ var rid = this.rid++;
+ var req = {
+ rid: rid,
+ sid: this.sid,
+ to: this.domain,
+ "xmpp:restart": "true",
+ "xml:lang": this.lang,
+ xmlns: dojox.xmpp.xmpp.BODY_NS,
+ "xmlns:xmpp": "urn:xmpp:xbosh"
+ };
+
+ var msg = dojox.xmpp.util.createElement("body", req, true);
+ this.addToOutboundQueue(msg, rid);
+ },
+
+ processScriptSrc: function(msg, rid) {
+ //console.log("processScriptSrc::", rid, msg);
+ // var msgDom = dojox.xml.DomParser.parse(msg);
+ var msgDom = dojox.xml.parser.parse(msg, "text/xml");
+ //console.log("parsed mgs", msgDom);
+ //console.log("Queue", this.outboundQueue);
+ if(msgDom) {
+ this.processDocument(msgDom, rid);
+ } else {
+ //console.log("Recived bad document from server",msg);
+ }
+ },
+
+ _keepAlive: function(){
+ if (this.state=="wait" || this.isTerminated()) {
+ return;
+ }
+ this._dispatchPacket();
+ this.keepAliveTimer = setTimeout(dojo.hitch(this, "_keepAlive"), 10000);
+ },
+
+
+ close: function(protocolMsg){
+
+
+ var rid = this.rid++;
+ var req = {
+
+ sid: this.sid,
+ rid: rid,
+ type: "terminate"
+ };
+ var envelope = null;
+
+ if (protocolMsg) {
+ envelope = new dojox.string.Builder(dojox.xmpp.util.createElement("body", req, false));
+ envelope.append(protocolMsg);
+ envelope.append("</body>");
+ } else {
+ envelope = new dojox.string.Builder(dojox.xmpp.util.createElement("body", req, false));
+ }
+
+ // this.sendXml(envelope,rid);
+ this.addToOutboundQueue(envelope.toString(), rid);
+ this.state=="Terminate";
+ },
+
+ dispatchPacket: function(msg, protocolMatchType, matchId, matchProperty){
+ // summary
+ // Main Packet dispatcher, most calls should be made with this other
+ // than a few setup calls which use add items to the queue directly
+ //protocolMatchType, matchId, and matchProperty are optional params
+ //that allow a deferred to be tied to a protocol response instad of the whole
+ //rid
+
+ // //console.log("In dispatchPacket ", msg, protocolMatchType, matchId, matchProperty);
+ if (msg){
+ this.protocolPacketQueue.push(msg);
+ }
+
+ var def = new dojo.Deferred();
+ //def.rid = req.rid;
+
+ if (protocolMatchType && matchId){
+ def.protocolMatchType = protocolMatchType;
+ def.matchId = matchId;
+ def.matchProperty = matchProperty || "id";
+ if(def.matchProperty != "id") {
+ this.matchTypeIdAttribute[protocolMatchType] = def.matchProperty;
+ }
+ }
+
+ this.deferredRequests[def.protocolMatchType + "-" +def.matchId]=def;
+ if(!this.dispatchTimer) {
+ this.dispatchTimer = setTimeout(dojo.hitch(this, "_dispatchPacket"), 600);
+ }
+ return def;
+ },
+
+ _dispatchPacket: function(){
+
+ clearTimeout(this.dispatchTimer);
+ delete this.dispatchTimer;
+
+ if (!this.sid){
+ console.debug("TransportSession::dispatchPacket() No SID, packet dropped.")
+ return;
+ }
+
+ if (!this.authId){
+ //FIXME according to original nodes, this should wait a little while and try
+ // again up to three times to see if we get this data.
+ console.debug("TransportSession::dispatchPacket() No authId, packet dropped [FIXME]")
+ return;
+ }
+
+
+
+ //if there is a pending request with the server, don't poll
+ if (this.transmitState != "error" && (this.protocolPacketQueue.length == 0) && (this.outboundQueue.length > 0)) {
+ return;
+ }
+
+ if (this.state=="wait" || this.isTerminated()) {
+ return;
+ }
+
+ var req = {
+ sid: this.sid,
+ xmlns: dojox.xmpp.xmpp.BODY_NS
+ }
+
+ var envelope
+ if (this.protocolPacketQueue.length > 0){
+ req.rid= this.rid++;
+ envelope = new dojox.string.Builder(dojox.xmpp.util.createElement("body", req, false));
+ envelope.append(this.processProtocolPacketQueue());
+ envelope.append("</body>");
+ delete this.lastPollTime;
+ } else {
+ //console.log("Nothing to send, I'm just polling.");
+ if(this.lastPollTime) {
+ var now = new Date().getTime();
+ if(now - this.lastPollTime < this.polling) {
+ //console.log("Waiting to poll ", this.polling - (now - this.lastPollTime)+10);
+ this.dispatchTimer = setTimeout(dojo.hitch(this, "_dispatchPacket"), this.polling - (now - this.lastPollTime)+10);
+ return;
+ }
+
+ }
+ req.rid= this.rid++;
+ this.lastPollTime = new Date().getTime();
+ envelope = new dojox.string.Builder(dojox.xmpp.util.createElement("body", req, true));
+
+ }
+
+
+ this.addToOutboundQueue(envelope.toString(),req.rid);
+
+ },
+
+ redispatchPacket: function(rid){
+ var env = this.outboundRequests[rid];
+ this.sendXml(env, rid);
+ },
+
+ addToOutboundQueue: function(msg, rid){
+ this.outboundQueue.push({msg: msg,rid: rid});
+ this.outboundRequests[rid]=msg;
+ this.sendXml(msg, rid);
+ },
+
+ removeFromOutboundQueue: function(rid){
+ for(var i=0; i<this.outboundQueue.length;i++){
+ if (rid == this.outboundQueue[i]["rid"]){
+ this.outboundQueue.splice(i, 1);
+ break;
+ }
+ }
+ delete this.outboundRequests[rid];
+ },
+
+ processProtocolPacketQueue: function(){
+ var packets = new dojox.string.Builder();
+ for(var i=0; i<this.protocolPacketQueue.length;i++){
+ packets.append(this.protocolPacketQueue[i]);
+ }
+ this.protocolPacketQueue=[];
+ return packets.toString();
+ },
+
+ sendXml: function(message, rid){
+ if(this.isTerminated()) {
+ return false;
+ }
+ //console.log("TransportSession::sendXml()"+ new Date().getTime() + " RID: ", rid, " MSG: ", message);
+ this.transmitState = "transmitting";
+ var def = null;
+ if(this.useScriptSrcTransport) {
+ //console.log("using script src to transmit");
+ def = dojox.xmpp.bosh.get({
+ rid: rid,
+ url: this.serviceUrl+'?'+encodeURIComponent(message),
+ error: dojo.hitch(this, function(res, io){
+ this.setState("Terminate", "error");
+ return false;
+ }),
+ timeout: this.sendTimeout
+ });
+ } else {
+ def = dojo.rawXhrPost({
+ contentType: "text/xml",
+ url: this.serviceUrl,
+ postData: message,
+ handleAs: "xml",
+ error: dojo.hitch(this, function(res, io) {
+ ////console.log("foo", res, io.xhr.responseXML, io.xhr.status);
+ return this.processError(io.xhr.responseXML, io.xhr.status , rid);
+ }),
+ timeout: this.sendTimeout
+ });
+ }
+ //process the result document
+ def.addCallback(this, function(res){
+ return this.processDocument(res, rid);
+ });
+ return def;
+ },
+
+ processDocument: function(doc, rid){
+ if(this.isTerminated() || !doc.firstChild) {
+ return false;
+ }
+ //console.log("TransportSession:processDocument() ", doc, rid);
+ this.transmitState = "idle";
+
+ var body = doc.firstChild;
+ if (body.nodeName != 'body'){
+ //console.log("TransportSession::processDocument() firstChild is not <body> element ", doc, " RID: ", rid);
+ }
+
+ if (this.outboundQueue.length<1){return false;}
+
+ var expectedId = this.outboundQueue[0]["rid"];
+ //console.log("expectedId", expectedId);
+ if (rid==expectedId){
+ this.removeFromOutboundQueue(rid);
+ this.processResponse(body, rid);
+ this.processInboundQueue();
+ }else{
+ //console.log("TransportSession::processDocument() rid: ", rid, " expected: ", expectedId);
+ var gap = rid-expectedId;
+
+ if (gap < this.hold + 2){
+ this.addToInboundQueue(doc,rid);
+ }else{
+ //console.log("TransportSession::processDocument() RID is outside of the expected response window");
+ }
+ }
+ return doc;
+ },
+
+ processInboundQueue: function(){
+ while (this.inboundQueue.length > 0) {
+ var item = this.inboundQueue.shift();
+ this.processDocument(item["doc"], item["rid"]);
+ }
+ },
+
+ addToInboundQueue: function(doc,rid){
+ for (var i=0; i<this.inboundQueue.length;i++){
+ if (rid < this.inboundQueue[i]["rid"]){continue;}
+ this.inboundQueue.splice(i,0,{doc: doc, rid: rid});
+ }
+ },
+
+ processResponse: function(body,rid){
+ ////console.log("TransportSession:processResponse() ", body, " RID: ", rid);
+
+ if (body.getAttribute("type")=='terminate'){
+ var reasonNode = body.firstChild.firstChild;
+ var errorMessage = "";
+ if(reasonNode.nodeName == "conflict") {
+ errorMessage = "conflict"
+ }
+ this.setState("Terminate", errorMessage);
+
+ return;
+ }
+
+ if ((this.state != 'Ready')&&(this.state != 'Terminate')) {
+ var sid=body.getAttribute("sid");
+ if (sid){
+ this.sid=sid;
+ } else {
+ throw new Error("No sid returned during xmpp session startup");
+ }
+
+ this.authId = body.getAttribute("authid");
+ if (this.authId == "") {
+ if (this.authRetries-- < 1) {
+ console.error("Unable to obtain Authorization ID");
+ this.terminateSession();
+ }
+ }
+ this.wait= body.getAttribute("wait");
+ if( body.getAttribute("polling")){
+ this.polling= parseInt(body.getAttribute("polling"))*1000;
+ }
+
+ //console.log("Polling value ", this.polling);
+ this.inactivity = body.getAttribute("inactivity");
+ this.setState("Ready");
+ }
+
+ dojo.forEach(body.childNodes, function(node){
+ this.processProtocolResponse(node, rid);
+ }, this);
+
+ //need to make sure, since if you use sendXml directly instead of using
+ //dispatch packets, there wont' be a call back function here
+ //normally the deferred will get fired by a child message at the protocol level
+ //but if it hasn't fired by now, go ahead and fire it with the full body
+ /*if (this.deferredRequests[rid] && this.deferredRequests[rid].fired==-1){
+ this.deferredRequests[rid].callback(body);
+ }*/
+
+ //delete from the list of outstanding requests
+ //delete this.deferredRequests[rid];
+
+ if (this.transmitState == "idle"){
+ this.dispatchPacket();
+ }
+ },
+
+
+ processProtocolResponse: function(msg, rid){
+ //summary
+ //process the individual protocol messages and if there
+ //is a matching set of protocolMatchType, matchId, and matchPropery
+ //fire off the deferred
+
+ this.onProcessProtocolResponse(msg);
+ var key = msg.nodeName + "-" +msg.getAttribute("id");
+ var def = this.deferredRequests[key];
+ if (def){
+ def.callback(msg);
+ delete this.deferredRequests[key];
+ }
+ },
+
+ setState: function(state, message){
+ if (this.state != state) {
+ if (this["on"+state]){
+ this["on"+state](state, this.state, message);
+ }
+ this.state=state;
+ }
+ },
+
+ isTerminated: function() {
+
+ return this.state=="Terminate";
+ },
+
+ processError: function(err, httpStatusCode,rid){
+ //console.log("Processing server error ", err, httpStatusCode,rid);
+ if(this.isTerminated()) {
+ return false;
+ }
+
+
+ if(httpStatusCode != 200) {
+ if(httpStatusCode >= 400 && httpStatusCode < 500){
+ /* Any status code between 400 and 500 should terminate
+ * the connection */
+ this.setState("Terminate", errorMessage);
+ return false;
+ }else{
+ this.removeFromOutboundQueue(rid);
+ setTimeout(dojo.hitch(this, function(){ this.dispatchPacket(); }), 200);
+ return true;
+ }
+ return false;
+ }
+
+ if (err && err.dojoType && err.dojoType=="timeout"){
+ //console.log("Wait timeout");
+ }
+
+ this.removeFromOutboundQueue(rid);
+ //FIXME conditional processing if request will be needed based on type of error.
+ if(err && err.firstChild) {
+ //console.log("Error ", err.firstChild.getAttribute("type") + " status code " + httpStatusCode);
+
+ if (err.firstChild.getAttribute("type")=='terminate'){
+ var reasonNode = err.firstChild.firstChild;
+ var errorMessage = "";
+ if(reasonNode && reasonNode.nodeName == "conflict") {
+ errorMessage = "conflict"
+ }
+ this.setState("Terminate", errorMessage);
+ return false;
+ }
+ }
+ this.transmitState = "error";
+ setTimeout(dojo.hitch(this, function(){ this.dispatchPacket(); }), 200);
+ //console.log("Error: ", arguments);
+ return true;
+ },
+
+ //events
+ onTerminate: function(newState, oldState, message){ },
+ onProcessProtocolResponse: function(msg){},
+ onReady: function(newState, oldState){}
+});
+
+}
|
