⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cometd.js

📁 js基本操作
💻 JS
📖 第 1 页 / 共 2 页
字号:
/*	Copyright (c) 2004-2006, The Dojo Foundation	All Rights Reserved.	Licensed under the Academic Free License version 2.1 or above OR the	modified BSD license. For more information on Dojo licensing, see:		http://dojotoolkit.org/community/licensing.shtml*/dojo.require("dojo.io.common"); // io/common.js provides setIFrameSrc and the IO moduledojo.provide("dojo.io.cometd");dojo.require("dojo.AdapterRegistry");dojo.require("dojo.json");dojo.require("dojo.io.BrowserIO"); // we need XHR for the handshake, etc.// FIXME: determine if we can use XMLHTTP to make x-domain posts despite not//        being able to hear back about the resultdojo.require("dojo.io.IframeIO");dojo.require("dojo.io.ScriptSrcIO"); // for x-domain long pollingdojo.require("dojo.io.cookie"); // for peeringdojo.require("dojo.event.*");dojo.require("dojo.lang.common");dojo.require("dojo.lang.func");/* * this file defines Comet protocol client. Actual message transport is * deferred to one of several connection type implementations. The default is a * forever-frame implementation. A single global object named "cometd" is * used to mediate for these connection types in order to provide a stable * interface. */// TODO: the auth handling in this file is a *mess*. It should probably live in// the cometd object with the ability to mix in or call down to an auth-handler// object, the prototypical variant of which is a no-opcometd = new function(){	this.initialized = false;	this.connected = false;	this.connectionTypes = new dojo.AdapterRegistry(true);	this.version = 0.1;	this.minimumVersion = 0.1;	this.clientId = null;	this._isXD = false;	this.handshakeReturn = null;	this.currentTransport = null;	this.url = null;	this.lastMessage = null;	this.globalTopicChannels = {};	this.backlog = [];	this.tunnelInit = function(childLocation, childDomain){		// placeholder	}	this.tunnelCollapse = function(){		dojo.debug("tunnel collapsed!");		// placeholder	}	this.init = function(props, root, bargs){		// FIXME: if the root isn't from the same host, we should automatically		// try to select an XD-capable transport		props = props||{};		// go ask the short bus server what we can support		props.version = this.version;		props.minimumVersion = this.minimumVersion;		props.channel = "/meta/handshake";		// FIXME: do we just assume that the props knows		// everything we care about WRT to auth? Should we be trying to		// call back into it for subsequent auth actions? Should we fire		// local auth functions to ask for/get auth data?		// FIXME: what about ScriptSrcIO for x-domain comet?		this.url = root||djConfig["cometdRoot"];		if(!this.url){			dojo.debug("no cometd root specified in djConfig and no root passed");			return;		}				// FIXME: we need to select a way to handle JSONP-style stuff		// generically here. We already know if the server is gonna be on		// another domain (or can know it), so we should select appropriate		// negotiation methods here as well as in final transport type		// selection.		var bindArgs = {			url: this.url,			method: "POST",			mimetype: "text/json",			load: dojo.lang.hitch(this, "finishInit"),			content: { "message": dojo.json.serialize([props]) }		};		// borrowed from dojo.uri.Uri in lieu of fixed host and port properties        var regexp = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$";		var r = (""+window.location).match(new RegExp(regexp));		if(r[4]){			var tmp = r[4].split(":");			var thisHost = tmp[0];			var thisPort = tmp[1]||"80"; // FIXME: match 443			r = this.url.match(new RegExp(regexp));			if(r[4]){				tmp = r[4].split(":");				var urlHost = tmp[0];				var urlPort = tmp[1]||"80";				if(	(urlHost != thisHost)||					(urlPort != thisPort) ){					dojo.debug(thisHost, urlHost);					dojo.debug(thisPort, urlPort);					this._isXD = true;					bindArgs.transport = "ScriptSrcTransport";					bindArgs.jsonParamName = "jsonp";					bindArgs.method = "GET";				}			}		}		if(bargs){			dojo.lang.mixin(bindArgs, bargs);		}		return dojo.io.bind(bindArgs);	}	this.finishInit = function(type, data, evt, request){		data = data[0];		this.handshakeReturn = data;		// pick a transport		if(data["authSuccessful"] == false){			dojo.debug("cometd authentication failed");			return;		}		if(data.version < this.minimumVersion){			dojo.debug("cometd protocol version mismatch. We wanted", this.minimumVersion, "but got", data.version);			return;		}		this.currentTransport = this.connectionTypes.match(			data.supportedConnectionTypes,			data.version,			this._isXD		);		this.currentTransport.version = data.version;		this.clientId = data.clientId;		this.tunnelInit = dojo.lang.hitch(this.currentTransport, "tunnelInit");		this.tunnelCollapse = dojo.lang.hitch(this.currentTransport, "tunnelCollapse");		this.initialized = true;		this.currentTransport.startup(data);		while(this.backlog.length != 0){			var cur = this.backlog.shift();			var fn = cur.shift();			this[fn].apply(this, cur);		}	}	this._getRandStr = function(){		return Math.random().toString().substring(2, 10);	}	// public API functions called by cometd or by the transport classes	this.deliver = function(messages){		dojo.lang.forEach(messages, this._deliver, this);	}	this._deliver = function(message){		// dipatch events along the specified path		if(!message["channel"]){			dojo.debug("cometd error: no channel for message!");			return;		}		if(!this.currentTransport){			this.backlog.push(["deliver", message]);			return;		}		this.lastMessage = message;		// check to see if we got a /meta channel message that we care about		if(	(message.channel.length > 5)&&			(message.channel.substr(0, 5) == "/meta")){			// check for various meta topic actions that we need to respond to			switch(message.channel){				case "/meta/subscribe":					if(!message.successful){						dojo.debug("cometd subscription error for channel", message.channel, ":", message.error);						return;					}					this.subscribed(message.subscription, message);					break;				case "/meta/unsubscribe":					if(!message.successful){						dojo.debug("cometd unsubscription error for channel", message.channel, ":", message.error);						return;					}					this.unsubscribed(message.subscription, message);					break;			}		}		// send the message down for processing by the transport		this.currentTransport.deliver(message);		// dispatch the message to any locally subscribed listeners		var tname = (this.globalTopicChannels[message.channel]) ? message.channel : "/cometd"+message.channel;		dojo.event.topic.publish(tname, message);	}	this.disconnect = function(){		if(!this.currentTransport){			dojo.debug("no current transport to disconnect from");			return;		}		this.currentTransport.disconnect();	}	// public API functions called by end users	this.publish = function(/*string*/channel, /*object*/data, /*object*/properties){		// summary: 		//		publishes the passed message to the cometd server for delivery		//		on the specified topic		// channel:		//		the destination channel for the message		// data:		//		a JSON object containing the message "payload"		// properties:		//		Optional. Other meta-data to be mixed into the top-level of the		//		message		if(!this.currentTransport){			this.backlog.push(["publish", channel, data, properties]);			return;		}		var message = {			data: data,			channel: channel		};		if(properties){			dojo.lang.mixin(message, properties);		}		return this.currentTransport.sendMessage(message);	}	this.subscribe = function(	/*string*/				channel, 								/*boolean, optional*/	useLocalTopics, 								/*object, optional*/	objOrFunc, 								/*string, optional*/	funcName){ // return: boolean		// summary:		//		inform the server of this client's interest in channel		// channel:		//		name of the cometd channel to subscribe to		// useLocalTopics:		//		Determines if up a local event topic subscription to the passed		//		function using the channel name that was passed is constructed,		//		or if the topic name will be prefixed with some other		//		identifier for local message distribution. Setting this to		//		"true" is a good way to hook up server-sent message delivery to		//		pre-existing local topics.		// objOrFunc:		//		an object scope for funcName or the name or reference to a		//		function to be called when messages are delivered to the		//		channel		// funcName:		//		the second half of the objOrFunc/funcName pair for identifying		//		a callback function to notifiy upon channel message delivery		if(!this.currentTransport){			this.backlog.push(["subscribe", channel, useLocalTopics, objOrFunc, funcName]);			return;		}		if(objOrFunc){			var tname = (useLocalTopics) ? channel : "/cometd"+channel;			if(useLocalTopics){				this.globalTopicChannels[channel] = true;			}			dojo.event.topic.subscribe(tname, objOrFunc, funcName);		}		// FIXME: would we handle queuing of the subscription if not connected?		// Or should the transport object?		return this.currentTransport.sendMessage({			channel: "/meta/subscribe",			subscription: channel		});	}	this.subscribed = function(	/*string*/				channel, 								/*obj*/					message){		dojo.debug(channel);		dojo.debugShallow(message);	}	this.unsubscribe = function(/*string*/				channel, 								/*boolean, optional*/	useLocalTopics, 								/*object, optional*/	objOrFunc, 								/*string, optional*/	funcName){ // return: boolean		// summary:		//		inform the server of this client's disinterest in channel		// channel:		//		name of the cometd channel to subscribe to		// useLocalTopics:		//		Determines if up a local event topic subscription to the passed		//		function using the channel name that was passed is destroyed,		//		or if the topic name will be prefixed with some other		//		identifier for stopping message distribution.		// objOrFunc:		//		an object scope for funcName or the name or reference to a		//		function to be called when messages are delivered to the		//		channel		// funcName:		//		the second half of the objOrFunc/funcName pair for identifying		if(!this.currentTransport){			this.backlog.push(["unsubscribe", channel, useLocalTopics, objOrFunc, funcName]);			return;		}		//		a callback function to notifiy upon channel message delivery		if(objOrFunc){			// FIXME: should actual local topic unsubscription be delayed for			// successful unsubcribe notices from the other end? (guessing "no")			// FIXME: if useLocalTopics is false, should we go ahead and			// destroy the local topic?			var tname = (useLocalTopics) ? channel : "/cometd"+channel;			dojo.event.topic.unsubscribe(tname, objOrFunc, funcName);		}		return this.currentTransport.sendMessage({			channel: "/meta/unsubscribe",			subscription: channel		});	}	this.unsubscribed = function(/*string*/				channel, 								/*obj*/					message){		dojo.debug(channel);		dojo.debugShallow(message);	}	// FIXME: add an "addPublisher" function}/*transport objects MUST expose the following methods:	- check	- startup	- sendMessage	- deliver	- disconnectoptional, standard but transport dependent methods are:	- tunnelCollapse	- tunnelInitTransports SHOULD be namespaced under the cometd object and transports MUSTregister themselves with cometd.connectionTypeshere's a stub transport defintion:cometd.blahTransport = new function(){	this.connected = false;	this.connectionId = null;	this.authToken = null;	this.lastTimestamp = null;	this.lastId = null;	this.check = function(types, version, xdomain){		// summary:		//		determines whether or not this transport is suitable given a		//		list of transport types that the server supports		return dojo.lang.inArray(types, "blah");	}	this.startup = function(){		if(this.connected){ return; }		// FIXME: fill in startup routine here		this.connected = true;	}	this.sendMessage = function(message){		// FIXME: fill in message sending logic	}	this.deliver = function(message){		if(message["timestamp"]){			this.lastTimestamp = message.timestamp;		}		if(message["id"]){			this.lastId = message.id;		}		if(	(message.channel.length > 5)&&			(message.channel.substr(0, 5) == "/meta")){			// check for various meta topic actions that we need to respond to			// switch(message.channel){			// 	case "/meta/connect":			//		// FIXME: fill in logic here			//		break;			//	// case ...: ...			//	}		}	}	this.disconnect = function(){		if(!this.connected){ return; }		// FIXME: fill in shutdown routine here		this.connected = false;	}}cometd.connectionTypes.register("blah", cometd.blahTransport.check, cometd.blahTransport);*/cometd.iframeTransport = new function(){	this.connected = false;	this.connectionId = null;	this.rcvNode = null;	this.rcvNodeName = "";	this.phonyForm = null;	this.authToken = null;	this.lastTimestamp = null;	this.lastId = null;	this.backlog = [];	this.check = function(types, version, xdomain){		return ((!xdomain)&&				(!dojo.render.html.safari)&&				(dojo.lang.inArray(types, "iframe")));	}	this.tunnelInit = function(){		// we've gotten our initialization document back in the iframe, so		// now open up a connection and start passing data!		this.postToIframe({			message: dojo.json.serialize([				{					channel:	"/meta/connect",					clientId:	cometd.clientId,					connectionType: "iframe"					// FIXME: auth not passed here!					// "authToken": this.authToken				}			])		});	}	this.tunnelCollapse = function(){		if(this.connected){			// try to restart the tunnel			this.connected = false;			this.postToIframe({				message: dojo.json.serialize([					{						channel:	"/meta/reconnect",						clientId:	cometd.clientId,						connectionId:	this.connectionId,						timestamp:	this.lastTimestamp,						id:			this.lastId						// FIXME: no authToken provision!					}				])			});		}	}	this.deliver = function(message){		// handle delivery details that this transport particularly cares		// about. Most functions of should be handled by the main cometd object		// with only transport-specific details and state being tracked here.		if(message["timestamp"]){			this.lastTimestamp = message.timestamp;		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -