diff options
author | Egil Moeller <egil.moller@freecode.no> | 2010-03-22 00:16:53 +0100 |
---|---|---|
committer | Egil Moeller <egil.moller@freecode.no> | 2010-03-22 00:16:53 +0100 |
commit | fc00cfedd6c25d1634a1e0d28a7b7bc5f42e1cd7 (patch) | |
tree | 928419d6bfe794865e4b8f0634bd792f795c4b8a /trunk/infrastructure/net.appjet.ajstdlib/streaming-client.js | |
parent | 0fdab3db005c4fa31fb8306b573c0b35073d3e56 (diff) | |
parent | d56b9b3b82cdebcaeb00eec0fcb4326ad21adaa8 (diff) | |
download | etherpad-fc00cfedd6c25d1634a1e0d28a7b7bc5f42e1cd7.tar.gz etherpad-fc00cfedd6c25d1634a1e0d28a7b7bc5f42e1cd7.tar.xz etherpad-fc00cfedd6c25d1634a1e0d28a7b7bc5f42e1cd7.zip |
Merge branch 'master' into plugin-framework
Diffstat (limited to 'trunk/infrastructure/net.appjet.ajstdlib/streaming-client.js')
-rw-r--r-- | trunk/infrastructure/net.appjet.ajstdlib/streaming-client.js | 920 |
1 files changed, 0 insertions, 920 deletions
diff --git a/trunk/infrastructure/net.appjet.ajstdlib/streaming-client.js b/trunk/infrastructure/net.appjet.ajstdlib/streaming-client.js deleted file mode 100644 index 3bfa227..0000000 --- a/trunk/infrastructure/net.appjet.ajstdlib/streaming-client.js +++ /dev/null @@ -1,920 +0,0 @@ -/** - * Copyright 2009 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS-IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var host = window.location.host; - -function WebSocket(id) { - var self = this; - var socket = this; - var version = 2; - - var timeouts = {}; - - this.onopen = function() { } - this.onclosed = function() { } - this.onmessage = function() { } - this.onhiccup = function() { } - this.onlogmessage = function() { } - this.CONNECTING = 0; - this.OPEN = 1; - this.CLOSED = 2; - this.readyState = -1; - - var hiccupsLastMinute = 0; - var hiccupResetInterval = setInterval(function() { - hiccupsLastMinute = 0; - if (self.readyState == self.CLOSED) - clearInterval(hiccupResetInterval); - }, 60*1000); - - var isHiccuping = false; - function hiccup(channel) { - if (channel != officialChannel && channel != self) return; - if (isHiccuping) return; - log("hiccup: "+channel.name); - if (hiccupsLastMinute++ > 10) { - doDisconnect({reconnect: true, reason: "Too many hiccups!"}); - return; - } - closeAllChannels(); - timeout(timeouts, "hiccup", 15000, function() { - isHiccuping = false; - doDisconnect({reconnect: false, reason: "Couldn't contact server to hiccup."}); - }); - isHiccuping = true; - function tryHiccup() { - if (! isHiccuping) return; - self.onhiccup({connected: false}); - log("trying hiccup"); - timeout(timeouts, "singleHiccup", 5000, function() { - tryHiccup(); - }); - simpleXhr('post', postPath(), true, [{key: "oob", value: "hiccup"}], function(sc, msg) { - if (! isHiccuping) return; - if (msg.substring(0, "restart-fail".length) == "restart-fail") { - doDisconnect({reconnect: true, reason: "Server restarted or socket timed out on server."}); - } else if (sc != 200 || msg.substring(0, 2) != "ok") { - log("Failed to hiccup with error: "+sc+" / "+msg); - setTimeout(tryHiccup, 500); - } else { - isHiccuping = false; - timeouts.singleHiccup(); - timeouts.hiccup(); - doConnect(); - } - }); - } - tryHiccup(); - } - function closeAllChannels() { - for (var i in activeChannels) { - if (activeChannels.hasOwnProperty(i)) { - activeChannels[i].disconnect(); - } - } - officialChannel = undefined; - } - - function doDisconnect(obj, silent, sync) { - log("disconnected: "+obj.reason+" / "+(obj.data !== undefined ? "data: "+obj.data : "")); - logAll(); - closeAllChannels(); - if (longPollingIFrame && longPollingIFrame.div) { - longPollingIFrame.div.innerHTML = ""; - } - if (self.readyState != self.CLOSED) { - self.readyState = self.CLOSED; - if (! silent) { - postSingleMessageNow(true, "kill:"+obj.reason, sync, true); - } - self.onclosed(obj); - } - } - - this.disconnect = function(sync) { - doDisconnect({reason: "Closed by client."}, false, sync); - } - - - function doBasicConnect() { - var type = getBasicChannel(); - log("basic connect on type: "+type); - var channel = activeChannels[type] = new channelConstructors[type](); - channel.connect(); - } - - function doOtherConnect() { - var channels = getOtherChannels(); - var channel; var type; - for (var i = 0; i < channels.length; ++i) { - type = channels[i]; - log("other connect on type: "+type); - channel = activeChannels[type] = new channelConstructors[type](); - channel.connect(); - } - } - function doConnect() { - log("doing connect!"); - timeout(timeouts, "connect", 15000, function() { - doDisconnect({reconnect: false, reason: "Timeout connecting to server: no channel type was able to connect."}); - }); - doBasicConnect(); - } - - this.connect = function() { - log("socket connecting: "+id); - doConnect(); - } - - // util - function nicetime() { return Math.floor((new Date()).valueOf() / 100) % 10000000; } - function log(s) { self.onlogmessage("(comet @t: "+nicetime()+") "+s); } - function logAll() { - log(self.describe()) - } - this.describe = function() { - function describeChannels() { - out = []; - for (var i in activeChannels) { - if (activeChannels.hasOwnProperty(i)) { - out.push(i+": "+activeChannels[i].describe()); - } - } - return "[ "+out.join(", ")+" ]"; - } - return ("socket state: { id: "+id+", readyState: "+self.readyState+", isHiccuping: "+isHiccuping+", timeouts: "+describeTimeouts(timeouts)+", officialChannel: "+(officialChannel?officialChannel.name:"none")+", channels: "+describeChannels()+", isPosting: "+isPosting+", lastReceivedSeqNumber: "+lastReceivedSeqNumber+", lastPost: "+lastPost+", postTimeouts: "+describeTimeouts(postTimeouts)+", channelSeq: "+channelSeq+" }"); - } - - function wrapMethod(obj, method) { - return function() { - var arr = []; - for (var i=0; i < arguments.length; i++) { - arr.push(arguments[i]); - } - method.apply(obj, arr); - } - } - var _wm = wrapMethod; - - // cb should take statusCode, responseText, and optionally request - function simpleXhr(method, uri, async, params, cb, makeXhr) { -// log("making simple Xhr: "+[method, uri, async, params].join(", ")); - var request = (makeXhr || newRequestObject)(); - request.open(method, uri, async); - if (async) { - request.onreadystatechange = function() { - if (request.readyState != 4) return; - var status; - var responseText; - try { - status = request.status; - responseText = request.responseText; - } catch (e) { /* absorb ff error accessing request properties */ } - cb(status, responseText, request); - } - } - var data = null; - if (params) { - data = []; - for (var i = 0; i < params.length; ++i) { - data.push(encodeURIComponent(params[i].key)+"="+encodeURIComponent(params[i].value)); - } - data = data.join("&"); - request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); - } - try { - request.send(data); - } catch (e) { request.abort(); cb(500, "Error sending data!", request); } - if (! async) { - var status; - var responseText; - try { - status = request.status; - responseText = request.responseText; - } catch (e) { /* absorb ff error accessing request properties */ } - cb(status, responseText, request); - } - return request; - } - - var timeout_noop = function() { } - function timeout(timeoutObject, timeoutName, millis, timeoutCallback) { - function clearIt(timeoutObject, timeoutName) { - if (timeoutObject[timeoutName]) { - timeoutObject[timeoutName](); - timeoutObject[timeoutName] = timeout_noop; - } - } - var timeoutId = setTimeout(function() { clearIt(timeoutObject, timeoutName); timeoutCallback(); }, millis); - var f = function() { - clearTimeout(timeoutId); - } - clearIt(timeoutObject, timeoutName); - timeoutObject[timeoutName] = f; - return f; - } - - // handling messages - var lastReceivedSeqNumber = 0; - - function dataHandler(msg) { - if (msg.seqNumber > lastReceivedSeqNumber+1) { - log("bad sequence number. expecting: "+(lastReceivedSeqNumber+1)+", got: "+msg.seqNumber); - hiccup(self); - return false; - } - if (msg.seqNumber < lastReceivedSeqNumber+1) return true; - lastReceivedSeqNumber = msg.seqNumber; - if (! msg.isControl) { - self.onmessage({ data: msg.content }); - return true; - } else { - if (msg.content == "kill") { - doDisconnect({reconnect: false, reason: "Killed by server."}); - return false; - } - } - } - - // client-server comm - var postPath = function() { - return "%contextPath%/post?r="+randomVar()+"&v="+version+"&id="+id+"&seq="+lastReceivedSeqNumber; - } - - function SimpleQueue() { - var base = []; - var head = 0; - var tail = 0; - this.offer = function(data) { - base[tail++] = data; - } - this.poll = function() { - if (this.length() > 0) { - var n = base[head]; - delete base[head++]; - return n; - } - } - this.clear = function() { - head = 0; - tail = 0; - var oldBase = base; - base = []; - return oldBase; - } - this.length = function() { - return tail - head; - } - } - var outgoingMessageQueue = new SimpleQueue(); - var isPosting = false; - var postTimeouts = {}; - var lastPost; - - function postSingleMessageNow(isControl, data, sync, force, cb) { - doPostMessages([{oob: isControl, data: data, cb: cb}], sync, force) - } - - function doPostMessages(messages, sync, force, cb) { - if (! force && self.readyState == self.CLOSED) return; - if (messages.length == 0) { - if (cb) cb(); - return; - } - var data = []; - var callbacks = []; - for (var i = 0; i < messages.length; ++i) { - data.push({key: (messages[i].oob ? "oob" : "m"), - value: messages[i].data}); - if (messages[i].cb) - callbacks.push(messages[i].cb); - } - function postFailed(sc, msg, req, src) { - var str = ""; - try { - str = sc + ": "+req.statusText+" - "+msg+" ("+src+")"; - } catch (e) { /* absorb potential Firefox error accessing req */ } - doDisconnect({reconnect: true, reason: "Posting message failed.", data: str}); - for (var i = 0; i < callbacks.length; ++i) { - callbacks[i](false, str); - } - } - function postCallback(sc, msg, request) { - postTimeouts.post(); - if (sc != 200 || msg.substring(0, 2) != "ok") { - postFailed(sc, msg, request, "1"); - } else { - for (var i = 0; i < callbacks.length; ++i) { - callbacks[i](true); - } - if (cb) cb(); - } - } - timeout(postTimeouts, "post", 15000, function() { - doDisconnect({reconnect: true, reason: "Posting message timed out."}); - }); - simpleXhr('post', postPath(), ! sync, data, postCallback); - } - - function postPendingMessages() { - if (isPosting == true) - return; - var messages = outgoingMessageQueue.clear(); - if (messages.length == 0) { - return; - } - isPosting = true; - doPostMessages(messages, false, false, function() { isPosting = false; setTimeout(postPendingMessages, 0); }); - lastPost = nicetime(); - } - this.postMessage = function(data, cb) { - if (self.readyState != self.OPEN) { - return; - } - outgoingMessageQueue.offer({data: data, cb: cb}); - setTimeout(function() { postPendingMessages() }, 0); - } - - // transports - function getValidChannels() { - var channels = []; - for (var i = 0; i < validChannels.length; ++i) { - var type = validChannels[i]; - if (window.location.hash.length > 0) { - if (window.location.hash != "#"+type) { - continue; - } - } - if ($ && $.browser.opera && type != 'shortpolling' && type != 'streaming') { - continue; - } - channels.push(type); - } - return channels; - } - function getBasicChannel() { - return getValidChannels()[0]; - } - - function getOtherChannels() { - return getValidChannels().slice(1); - } - - var officialChannel; - this.getTransportType = function() { - return (officialChannel ? officialChannel.name : "none"); - } - var validChannels = "%acceptableChannelTypes%"; - var canUseSubdomains = "%canUseSubdomains%"; - var activeChannels = {}; - var channelConstructors = { - shortpolling: ShortPollingChannel, - longpolling: LongPollingChannel, - streaming: StreamingChannel - } - - function describeTimeouts(timeouts) { - var out = []; - for (var i in timeouts) { - if (timeouts.hasOwnProperty(i)) { - out.push(i+": "+(timeouts[i] == timeout_noop ? "unset" : "set")); - } - } - return "{ "+out.join(", ")+" }"; - } - - var channelSeq = 1; - function notifyConnect(channel) { - timeouts.connect(); - if (! officialChannel || channel.weight > officialChannel.weight) { - log("switching to use channel: "+channel.name); - var oldChannel = officialChannel; - officialChannel = channel; - setTimeout(function() { - postSingleMessageNow(true, "useChannel:"+(channelSeq++)+":"+channel.name, false, false, function(success, msg) { - if (success) { - if (oldChannel) { - oldChannel.disconnect(); - } else { - // there was no old channel, so try connecting the other channels. - doOtherConnect(); - } - if (self.readyState != self.OPEN) { - self.readyState = self.OPEN; - self.onopen({}); - } else { - self.onhiccup({connected: true}); - } - } else { - doDisconnect({reconnect: true, reason: "Failed to select channel on server.", data: msg}); - } - }); - }, 0); - return true; - } else { - return false; - } - } - - function randomVar() { - return String(Math.round(Math.random()*1e12)); - } - - function channelPath() { - return "%contextPath%/channel?v="+version+"&r="+randomVar()+"&id="+id; - } - - function newRequestObject() { - var xmlhttp=false; - try { - xmlhttp = (window.ActiveXObject && new ActiveXObject("Msxml2.XMLHTTP")) - } catch (e) { - try { - xmlhttp = (window.ActiveXObject && new ActiveXObject("Microsoft.XMLHTTP")); - } catch (E) { - xmlhttp = false; - } - } - if (!xmlhttp && typeof XMLHttpRequest!='undefined') { - try { - xmlhttp = new XMLHttpRequest(); - } catch (e) { - xmlhttp=false; - } - } - if (!xmlhttp && window.createRequest) { - try { - xmlhttp = window.createRequest(); - } catch (e) { - xmlhttp=false; - } - } - return xmlhttp - } - - function DataFormatError(message) { - this.message = message; - } - - function readMessage(data, startIndex) { - if (! startIndex) startIndex = 0; - var sep = data.indexOf(":", startIndex); - if (sep < 0) return; // don't have all the bytes for this yet. - var chars = Number(data.substring(startIndex, sep)); - if (isNaN(chars)) - throw new DataFormatError("Bad length: "+data.substring(startIndex, sep)); - if (data.length < sep+1+chars) return; // don't have all the bytes for this yet. - var msg = data.substr(sep+1, chars); - return { message: msg, lastConsumedChar: sep+1+chars } - } - - function iframeReader(data, startIndex) { - if (startIndex == 0) - return { message: data, lastConsumedChar: data.length } - } - - function parseWireFormat(data, startIndex, reader) { - if (! startIndex) startIndex = 0; - var msgs = []; - var readThroughIndex = startIndex; - while (true) { - var msgObj = (reader || readMessage)(data, readThroughIndex) - if (! msgObj) break; - readThroughIndex = msgObj.lastConsumedChar; - var msg = msgObj.message; - var split = msg.split(":"); - if (split[0] == 'oob') { - msgs.push({oob: split.slice(1).join(":")}); - continue; - } - var seq = Number(split[0]); - if (isNaN(seq)) - throw new DataFormatError("Bad sequence number: "+split[0]); - var control = Number(split[1]); - if (isNaN(control)) - throw new DataFormatError("Bad control: "+split[1]); - var msgContent = split.slice(2).join(":"); - msgs.push({seqNumber: seq, isControl: (control == 1), content: msgContent}); - } - return { messages: msgs, lastConsumedChar: readThroughIndex } - } - - function handleMessages(data, cursor, channel, reader) { - try { - messages = parseWireFormat(data, cursor, reader); - } catch (e) { - if (e instanceof DataFormatError) { - log("Data format error: "+e.message); - hiccup(channel); - return; - } else { - log(e.toString()+" on line: "+e.lineNumber); - } - } - for (var i=0; i < messages.messages.length; i++) { - var oob = messages.messages[i].oob; - if (oob) { - if (oob == "restart-fail") { - doDisconnect({reconnect: true, reason: "Server restarted or socket timed out on server."}); - return; - } - } else { - if (! dataHandler(messages.messages[i])) - break; - } - } - return messages.lastConsumedChar; - } - - function ShortPollingChannel() { - this.weight = 0; - this.name = "shortpolling"; - - this.isConnected = false; - this.isClosed = false; - this.request; - this.clearRequest = function() { - if (this.request) { - this.request.abort(); - this.request = null; - } - } - this.timeouts = {}; - - this.describe = function() { - return "{ isConnected: "+this.isConnected+", isClosed: "+this.isClosed+", timeouts: "+describeTimeouts(this.timeouts)+", request: "+(this.request?"set":"not set")+" }" - } - - this.pollDataHandler = function(sc, response, request) { - if (request.readyState != 4) return; - if (this.timeouts.poll) this.timeouts.poll(); - var messages; - if (! this.isConnected) { - this.timeouts.connectAttempt(); - if (sc != 200) { - log(this.name+" connect failed: "+sc+" / "+response); - setTimeout(_wm(this, this.attemptConnect), 500); - return; - } - var msg = (response ? readMessage(response) : undefined); - if (msg && msg.message == "oob:ok") { - this.timeouts.initialConnect(); - this.isConnected = true; - log(this.name+" transport connected!"); - if (! notifyConnect(this)) { - // there are better options connected. - log(this.name+" transport not chosen for activation."); - this.disconnect(); - return; - } - this.doPoll(); - return; - } else { - log(this.name+" connect didn't get ok: "+sc+" / "+response); - setTimeout(_wm(this, this.attemptConnect), 500); - return; - } - } - var chars = handleMessages(request.responseText, 0, this); - if (sc != 200 || ((! chars) && this.emptyResponseBad)) { - hiccup(this); - } - setTimeout(_wm(this, this.doPoll), this.pollDelay); - this.clearRequest(); - } - - this.keepRetryingConnection = true; - this.cancelConnect = function() { - this.clearRequest(); - this.keepRetryingConnection = false; - } - this.cancelPoll = function() { - this.clearRequest(); - log("poll timed out."); - hiccup(this); - } - - this.doPoll = function() { - if (this.isClosed) return; - timeout(this.timeouts, "poll", this.pollTimeout, _wm(this, this.cancelPoll)); - this.request = - simpleXhr('GET', - channelPath()+"&channel="+this.name+"&seq="+lastReceivedSeqNumber+this.pollParams(), - true, undefined, _wm(this, this.pollDataHandler), this.xhrGenerator); - } - - this.pollParams = function() { - return ""; - } - this.pollTimeout = 5000; - this.pollDelay = 500; - - this.attemptConnect = function() { - if (! this.keepRetryingConnection) return; - log(this.name+" attempting connect"); - this.clearRequest(); - timeout(this.timeouts, "connectAttempt", 5000, _wm(this, this.attemptConnect)); - this.request = simpleXhr('GET', channelPath()+"&channel="+this.name+"&new=yes&create="+(socket.readyState == socket.OPEN ? "no" : "yes")+"&seq="+lastReceivedSeqNumber, - true, undefined, _wm(this, this.pollDataHandler), this.xhrGenerator); - } - this.connect = function() { - this.attemptConnect(); - timeout(this.timeouts, "initialConnect", 15000, _wm(this, this.cancelConnect)); - } - this.disconnect = function() { - log(this.name+" disconnected"); - this.isClosed = true; - this.clearRequest(); - } - } - - function StreamingChannel() { - this.weight = 2; - this.name = "streaming"; - var self = this; - - var isConnected = false; - var request; - function clearRequest() { - if (request) { - request.abort(); - request = null; - if (theStream) theStream = null; - if (ifrDiv) { - ifrDiv.innerHTML = ""; - ifrDiv = null; - } - } - } - var isClosed = false; - var timeouts = {}; - var cursor = 0; - - this.describe = function() { - return "{ isConnected: "+isConnected+", isClosed: "+isClosed+", timeouts: "+describeTimeouts(timeouts)+", request: "+(request?"set":"not set")+", cursor: "+cursor+" }"; - }; - - function connectOk() { - isConnected = true; - timeouts.initialConnect(); - if (! notifyConnect(self)) { - log("streaming transport not chosen for activation"); - self.disconnect(); - return; - } - } - - function streamDataHandler() { - if (timeouts.data) timeouts.data(); - if (isClosed) return; - try { - if (! request.responseText) return; - } catch (e) { return; } - if (! isConnected) { - var msg = readMessage(request.responseText, cursor); - if (! msg) return; - cursor = msg.lastReceivedSeqNumber; - if (msg.message == "oob:ok") { - connectOk(); - } else { - log("stream: incorrect channel connect message:"+msg.message); - self.disconnect(); - return; - } - } else { - cursor = handleMessages(request.responseText, cursor, self); - } - if (! request || request.readyState == 4) { - clearRequest(); - if (isConnected) { - log("stream connection unexpectedly closed."); - hiccup(self); - return; - } - } - timeout(timeouts, "data", 60*1000, function() { hiccup(self); }); - } - - function iframeDataHandler(data) { - if (isClosed) return; - if (! isConnected) { - if (data == "oob:ok") { - connectOk(); - } else { - log("iframe stream: unexpected data on connect - "+data); - } - } else { - handleMessages(data, 0, self, iframeReader); - } - } - - function cancelConnect() { - isClosed = true; - clearRequest(); - log("stream: failed to connect."); - } - - // IE Stuff. - var theStream; - var ifrDiv; - var iframeTestCount = 0; - function testIframe() { - var state; - try { - state = ifrDiv.firstChild.readyState; - } catch (e) { - hiccup(self); - return; - } - if (state == 'interactive' || iframeTestCount > 10) { - try { var tmp = ifrDiv.firstChild.contentWindow.document.getElementById("thebody") } - catch (e) { hiccup(self); } - } else { - iframeTestCount++; - setTimeout(testIframe, 500); - } - } - - this.connect = function() { - timeout(timeouts, "initialConnect", 15000, cancelConnect) - - if (canUseSubdomains) { - var streamurl = "//"+randomVar()+".comet."+host+channelPath()+"&channel=streaming&type=iframe&new=yes&create="+(socket.readyState == socket.OPEN ? "no" : "yes")+"&seq="+lastReceivedSeqNumber; - log("stream to: "+streamurl); - if ($ && $.browser.opera) { - // set up the opera stream; requires jquery because, why not? - ifrDiv = $('<div style="display: none;"></div>').get(0); - $('body').append(ifrDiv); - window.comet = { - pass_data: iframeDataHandler, - disconnect: function() { hiccup(self); } - } - $(ifrDiv).append($("<iframe src='"+streamurl+"'></iframe>")); - iframeTestCount = 0; - setTimeout(testIframe, 2000); - // if event-source supported disconnect notifications, fuck yeah we'd use it. -// theStream = $('<event-source>'); -// var streamurl = channelPath()+"&channel=streaming&type=opera&new=yes&create="+(socket.readyState == socket.OPEN ? "no" : "yes")+"&seq="+lastReceivedSeqNumber; -// theStream.get(0).addEventListener('message', function(event) { -// iframeDataHandler(event.data); -// }, false); -// theStream.attr('src', streamurl); - log("stream connect sent!"); - return; - } - try { // TODO: remove reference to both theStream and ifrDiv on unload! - theStream = (window.ActiveXObject && new ActiveXObject("htmlfile")); - if (theStream) { - theStream.open(); - theStream.write("<html><head><title>f<\/title><\/head><body>") - theStream.write("<s"+"cript>document.domain='"+document.domain+"';<\/s"+"cript>") - theStream.write("<\/body><\/html>") - theStream.close(); - ifrDiv = theStream.createElement("div") - theStream.appendChild(ifrDiv) - theStream.parentWindow.comet = { - pass_data: iframeDataHandler, - disconnect: function() { hiccup(self); } - } - ifrDiv.innerHTML = "<iframe src='"+streamurl+"'></iframe>"; - iframeTestCount = 0; - setTimeout(testIframe, 2000); - } - } catch (e) { - theStream = false - } - } else if ($ && $.browser.opera) { - // opera thinks it can do a normal stream, but it can't. - log("opera - not trying xhr"); - return; - } - // End IE Stuff. - if (! theStream) { - request = newRequestObject(); - request.open('get', channelPath()+"&channel=streaming&new=yes&create="+(socket.readyState == socket.OPEN ? "no" : "yes")+"&seq="+lastReceivedSeqNumber); - request.onreadystatechange = streamDataHandler; - try { - request.send(null); - } catch (e) { } - } - log("stream connect sent!"); - } - - this.disconnect = function() { - log("stream disconnected"); - isClosed = true; - clearRequest(); - } - log("new streamchannel"); - } - - // long-polling related stuff. - function iframePath(key) { - return "//"+key+".comet."+host+"%contextPath%/xhrXdFrame"; - } - - function createHiddenDiv() { - if (! document.getElementById('newcomethidden')) { - var d = document.createElement('div'); - d.setAttribute('id', 'newcomethidden'); - d.style.display = 'none'; - document.body.appendChild(d); - } - return document.getElementById('newcomethidden'); - } - - function ExtHostXHR(iframe) { - this.open = function(method, uri, async) { - this.method = method; - this.uri = uri; - this.async = async; - } - var headers = {}; - this.setRequestHeader = function(name, value) { - headers[name] = value; - } - this.send = function(data) { - var self = this; - this.xhr = iframe.iframe.contentWindow.doAction(this.method, this.uri, this.async, headers, data || null, function(status, response) { - self.readyState = 4; - self.status = status; - self.responseText = response; - self.onreadystatechange(); - }); - } - this.abort = function() { - if (this.xhr) - iframe.contentWindow.doAbort(this.xhr); - } - } - - function createRequestIframe(cb) { - var randomKey = randomVar(); - try { - var activeXControl = (window.ActiveXObject && new ActiveXObject("htmlfile")); - var htmlfileDiv; - if (activeXControl) { - activeXControl.open(); - activeXControl.write('<html><head><title>f</title></head><body>'); - activeXControl.write('<scr'+'ipt>document.domain=\''+document.domain+'\';</scr'+'ipt>'); - activeXControl.write('</body></html>'); - activeXControl.close(); - htmlfileDiv = activeXControl.createElement('div'); - activeXControl.appendChild(htmlfileDiv); - activeXControl.parentWindow["done_"+randomKey] = cb; - htmlfileDiv.innerHTML = "<iframe src='"+iframePath(randomKey)+"'></iframe>"; - return {iframe: htmlfileDiv.firstChild /* should be an iframe */, axc: activeXControl, div: htmlfileDiv}; - } - } catch (e) { - activeXControl = false; - } - log("Not using IE setup."); - var requestIframe = document.createElement('iframe'); - createHiddenDiv().appendChild(requestIframe); - window["done_"+randomKey] = function() { try { delete window["done_"+randomKey]; } catch (e) { }; cb(); } - requestIframe.src = iframePath(randomKey); - return {iframe: requestIframe}; - } - - function createIframeRequestObject() { - if (! longPollingIFrame) throw Error("WebSocket isn't properly set up!"); - return new ExtHostXHR(longPollingIFrame); - } - - var longPollingIFrame; - function LongPollingChannel() { - ShortPollingChannel.apply(this); // sets up other state. - this.weight = 1; - this.name = "longpolling"; - - this.pollDelay = 0; - this.pollTimeout = 15000; - this.pollParams = function() { - return "&timeout="+(this.pollTimeout-5000); - } - var connect = this.connect; - this.connect = function() { - if (! longPollingIFrame) { - longPollingIFrame = - createRequestIframe(_wm(this, connect)); // specifically *not* this.connect. we want the old one! - } else { - connect.apply(this); - } - } - this.xhrGenerator = createIframeRequestObject; - this.emptyResponseBad = true; - } -}
\ No newline at end of file |