--- googlecode.com/svn/trunk/public_html/meteor.js 2008/02/02 16:53:19 40 +++ googlecode.com/svn/trunk/public_html/meteor.js 2008/11/27 00:33:21 62 @@ -27,15 +27,33 @@ pingtimer: null, pollfreq: 3000, port: 80, + pollaborted: false, + pollhost: null, + pollnum: 0, polltimeout: 30000, + polltimer: null, recvtimes: [], + lastrequest: null, status: 0, updatepollfreqtimer: null, + isSupportedBrowser: function() { + var v; + if (v = navigator.userAgent.match(/compatible\; MSIE\ ([0-9\.]+)\;/i)) { + if (parseFloat(v[1]) <= 5.5) return false; + } else if (v = navigator.userAgent.match(/Gecko\/([0-9]+)/i)) { + if (parseInt(v[1]) <= 20051015) return false; + } else if (v = navigator.userAgent.match(/WebKit\/([0-9\.]+)/i)) { + if (parseFloat(v[1]) < 400) return false; + } + return true; + }, + register: function(ifr) { ifr.p = Meteor.process; ifr.r = Meteor.reset; ifr.eof = Meteor.eof; + ifr.ch = Meteor.channelInfo; clearTimeout(Meteor.frameloadtimer); Meteor.setstatus(4); Meteor.log("Frame registered"); @@ -43,18 +61,19 @@ joinChannel: function(channelname, backtrack) { if (typeof(Meteor.channels[channelname]) != "undefined") throw "Cannot join channel "+channelname+": already subscribed"; - Meteor.channels[channelname] = {backtrack:backtrack, lastmsgreceived:0}; + Meteor.channels[channelname] = {backtrack:backtrack}; Meteor.log("Joined channel "+channelname); Meteor.channelcount++; - if (Meteor.status != 0) Meteor.connect(); + if (Meteor.status != 0 && Meteor.status != 6) Meteor.connect(); }, leaveChannel: function(channelname) { if (typeof(Meteor.channels[channelname]) == "undefined") throw "Cannot leave channel "+channelname+": not subscribed"; delete Meteor.channels[channelname]; Meteor.log("Left channel "+channelname); - if (Meteor.status != 0) Meteor.connect(); Meteor.channelcount--; + if (Meteor.channelcount && Meteor.status != 0 && Meteor.status != 6) Meteor.connect(); + else Meteor.disconnect(); }, connect: function() { @@ -64,9 +83,7 @@ if (!Meteor.channelcount) throw "No channels specified"; if (Meteor.status) Meteor.disconnect(); Meteor.setstatus(1); - var now = new Date(); - var t = now.getTime(); - if (!Meteor.hostid) Meteor.hostid = t+""+Math.floor(Math.random()*1000000) + if (!Meteor.hostid) Meteor.hostid = Meteor.time()+""+Math.floor(Math.random()*1000000) document.domain = Meteor.extract_xss_domain(document.domain); if (Meteor.mode=="stream") Meteor.mode = Meteor.selectStreamTransport(); Meteor.log("Selected "+Meteor.mode+" transport"); @@ -80,13 +97,12 @@ Meteor.pingtimer = setTimeout(Meteor.pollmode, Meteor.pingtimeout); } else { - Meteor.loadFrame("http://"+Meteor.host+((Meteor.port==80)?"":":"+Meteor.port)+"/poll.html"); - Meteor.recvtimes[0] = t; + Meteor.recvtimes[0] = Meteor.time(); if (Meteor.updatepollfreqtimer) clearTimeout(Meteor.updatepollfreqtimer); - if (Meteor.mode=='smartpoll') Meteor.updatepollfreqtimer = setInterval(Meteor.updatepollfreq, 2500); + if (Meteor.mode=='smartpoll') Meteor.updatepollfreqtimer = setInterval(Meteor.updatepollfreq, 10000); if (Meteor.mode=='longpoll') Meteor.pollfreq = Meteor.minpollfreq; + Meteor.poll(); } - Meteor.lastrequest = t; }, disconnect: function() { @@ -95,7 +111,10 @@ clearTimeout(Meteor.updatepollfreqtimer); clearTimeout(Meteor.frameloadtimer); if (typeof CollectGarbage == 'function') CollectGarbage(); - Meteor.setstatus(0); + if (Meteor.status != 6) Meteor.setstatus(0); + Meteor.log("Disconnected"); + try { Meteor.frameref.parentNode.removeChild(Meteor.frameref); delete Meteor.frameref; return true; } catch(e) { } + try { Meteor.frameref.open(); Meteor.frameref.close(); return true; } catch(e) {} } }, @@ -109,17 +128,19 @@ }, getSubsUrl: function() { - var surl = "http://" + Meteor.host + ((Meteor.port==80)?"":":"+Meteor.port) + "/push/" + Meteor.hostid + "/" + Meteor.mode; + var host = ((Meteor.mode=='simplepoll' || Meteor.mode=='smartpoll' || Meteor.mode=='longpoll') && Meteor.pollhost) ? Meteor.pollhost : Meteor.host; + var surl = "http://" + host + ((Meteor.port==80)?"":":"+Meteor.port) + "/push/" + Meteor.hostid + "/" + Meteor.mode; for (var c in Meteor.channels) { surl += "/"+c; - if (Meteor.channels[c].lastmsgreceived > 0) { + if (typeof Meteor.channels[c].lastmsgreceived != 'undefined') { surl += ".r"+(Meteor.channels[c].lastmsgreceived+1); } else if (Meteor.channels[c].backtrack > 0) { surl += ".b"+Meteor.channels[c].backtrack; - } else if (Meteor.channels[c].backtrack < 0 || isNaN(Meteor.channels[c].backtrack)) { + } else if (Meteor.channels[c].backtrack != undefined) { surl += ".h"; } } + surl += "?nc="+Meteor.time(); return surl; }, @@ -160,24 +181,25 @@ pollmode: function() { Meteor.log("Ping timeout"); - Meteor.mode="smartpoll"; - clearTimeout(Meteor.pingtimer); + if (Meteor.mode != "smartpoll") { + Meteor.mode="smartpoll"; + Meteor.callbacks["changemode"]("poll"); + clearTimeout(Meteor.pingtimer); + Meteor.lastpingtime = false; + } Meteor.connect(); - Meteor.callbacks["changemode"]("poll"); - Meteor.lastpingtime = false; }, process: function(id, channel, data) { if (id == -1) { Meteor.log("Ping"); Meteor.ping(); - } else if (typeof(Meteor.channels[channel]) != "undefined" && id > Meteor.channels[channel].lastmsgreceived) { + } else if (typeof(Meteor.channels[channel]) != "undefined") { Meteor.log("Message "+id+" received on channel "+channel+" (last id on channel: "+Meteor.channels[channel].lastmsgreceived+")\n"+data); Meteor.callbacks["process"](data); Meteor.channels[channel].lastmsgreceived = id; if (Meteor.mode=="smartpoll") { - var now = new Date(); - Meteor.recvtimes[Meteor.recvtimes.length] = now.getTime(); + Meteor.recvtimes[Meteor.recvtimes.length] = Meteor.time(); while (Meteor.recvtimes.length > 5) Meteor.recvtimes.shift(); } } @@ -188,35 +210,40 @@ if (Meteor.pingtimer) { clearTimeout(Meteor.pingtimer); Meteor.pingtimer = setTimeout(Meteor.pollmode, Meteor.pingtimeout); - var now = new Date(); - Meteor.lastpingtime = now.getTime(); + Meteor.lastpingtime = Meteor.time(); } Meteor.setstatus(5); }, reset: function() { - Meteor.log("Stream reset"); - Meteor.ping(); - Meteor.callbacks["reset"](); - var now = new Date(); - var t = now.getTime(); - var x = Meteor.pollfreq - (t-Meteor.lastrequest); - if (x < 10) x = 10; - setTimeout(Meteor.connect, x); + if (Meteor.status != 6 && Meteor.status != 0) { + Meteor.log("Stream reset"); + Meteor.ping(); + Meteor.callbacks["reset"](); + var x = Meteor.pollfreq - (Meteor.time()-Meteor.lastrequest); + if (x < 10) x = 10; + setTimeout(Meteor.connect, x); + } }, eof: function() { + Meteor.log("Received end of stream, will not reconnect"); Meteor.callbacks["eof"](); + Meteor.setstatus(6); + Meteor.disconnect(); + }, + + channelInfo: function(channel, id) { + Meteor.channels[channel].lastmsgreceived = id; + Meteor.log("Received channel info for channel "+channel+": resume from "+id); }, updatepollfreq: function() { - var now = new Date(); - var t = now.getTime(); var avg = 0; for (var i=1; i Meteor.minpollfreq) Meteor.pollfreq = Math.ceil(Meteor.pollfreq*0.9); @@ -242,7 +269,7 @@ Meteor.log("Frame load timeout"); if (Meteor.frameloadtimer) clearTimeout(Meteor.frameloadtimer); Meteor.setstatus(3); - setTimeout(Meteor.connect, 5000); + Meteor.pollmode(); }, extract_xss_domain: function(old_domain) { @@ -258,6 +285,7 @@ // 3 = Controller frame timeout, retrying. // 4 = Controller frame loaded and ready // 5 = Receiving data + // 6 = End of stream, will not reconnect if (Meteor.status != newstatus) { Meteor.status = newstatus; @@ -273,6 +301,36 @@ document.getElementById("meteorlogoutput").innerHTML += logstr+"
"; } } + }, + + poll: function() { + Meteor.pollaborted = 0; + try { + clearTimeout(Meteor.polltimer); + } catch (e) {}; + Meteor.lastrequest = Meteor.time(); + if (Meteor.polltimeout) Meteor.polltimer = setTimeout(Meteor.clearpoll, Meteor.polltimeout); + var scripttag = document.createElement("SCRIPT"); + scripttag.type = "text/javascript"; + scripttag.src = Meteor.getSubsUrl(); + scripttag.id = "meteorpoll"+(++Meteor.pollnum); + scripttag.className = "meteorpoll"; + document.getElementsByTagName("HEAD")[0].appendChild(scripttag); + }, + + clearpoll: function() { + var s = document.getElementById('meteorpoll'+Meteor.pollnum); + if (typeof s != 'undefined') s.parentNode.removeChild(s); + if (Meteor.status) { + var x = parent.Meteor.pollfreq - (Meteor.time()-Meteor.lastrequest); + if (x < 10) x = 10; + setTimeout(Meteor.poll, x); + } + }, + + time: function() { + var now = new Date(); + return now.getTime(); } }