27 |
pingtimer: null, |
pingtimer: null, |
28 |
pollfreq: 3000, |
pollfreq: 3000, |
29 |
port: 80, |
port: 80, |
30 |
|
pollaborted: false, |
31 |
|
pollhost: null, |
32 |
|
pollnum: 0, |
33 |
polltimeout: 30000, |
polltimeout: 30000, |
34 |
|
polltimer: null, |
35 |
recvtimes: [], |
recvtimes: [], |
36 |
|
lastrequest: null, |
37 |
status: 0, |
status: 0, |
38 |
updatepollfreqtimer: null, |
updatepollfreqtimer: null, |
39 |
|
|
40 |
|
isSupportedBrowser: function() { |
41 |
|
var v; |
42 |
|
if (v = navigator.userAgent.match(/compatible\; MSIE\ ([0-9\.]+)\;/i)) { |
43 |
|
if (parseFloat(v[1]) <= 5.5) return false; |
44 |
|
} else if (v = navigator.userAgent.match(/Gecko\/([0-9]+)/i)) { |
45 |
|
if (parseInt(v[1]) <= 20051015) return false; |
46 |
|
} else if (v = navigator.userAgent.match(/WebKit\/([0-9\.]+)/i)) { |
47 |
|
if (parseFloat(v[1]) < 400) return false; |
48 |
|
} |
49 |
|
return true; |
50 |
|
}, |
51 |
|
|
52 |
register: function(ifr) { |
register: function(ifr) { |
53 |
ifr.p = Meteor.process; |
ifr.p = Meteor.process; |
54 |
ifr.r = Meteor.reset; |
ifr.r = Meteor.reset; |
55 |
ifr.eof = Meteor.eof; |
ifr.eof = Meteor.eof; |
56 |
|
ifr.ch = Meteor.channelInfo; |
57 |
clearTimeout(Meteor.frameloadtimer); |
clearTimeout(Meteor.frameloadtimer); |
58 |
Meteor.setstatus(4); |
Meteor.setstatus(4); |
59 |
Meteor.log("Frame registered"); |
Meteor.log("Frame registered"); |
61 |
|
|
62 |
joinChannel: function(channelname, backtrack) { |
joinChannel: function(channelname, backtrack) { |
63 |
if (typeof(Meteor.channels[channelname]) != "undefined") throw "Cannot join channel "+channelname+": already subscribed"; |
if (typeof(Meteor.channels[channelname]) != "undefined") throw "Cannot join channel "+channelname+": already subscribed"; |
64 |
Meteor.channels[channelname] = {backtrack:backtrack, lastmsgreceived:0}; |
Meteor.channels[channelname] = {backtrack:backtrack}; |
65 |
Meteor.log("Joined channel "+channelname); |
Meteor.log("Joined channel "+channelname); |
66 |
Meteor.channelcount++; |
Meteor.channelcount++; |
67 |
if (Meteor.status != 0) Meteor.connect(); |
if (Meteor.status != 0 && Meteor.status != 6) Meteor.connect(); |
68 |
}, |
}, |
69 |
|
|
70 |
leaveChannel: function(channelname) { |
leaveChannel: function(channelname) { |
71 |
if (typeof(Meteor.channels[channelname]) == "undefined") throw "Cannot leave channel "+channelname+": not subscribed"; |
if (typeof(Meteor.channels[channelname]) == "undefined") throw "Cannot leave channel "+channelname+": not subscribed"; |
72 |
delete Meteor.channels[channelname]; |
delete Meteor.channels[channelname]; |
73 |
Meteor.log("Left channel "+channelname); |
Meteor.log("Left channel "+channelname); |
|
if (Meteor.status != 0) Meteor.connect(); |
|
74 |
Meteor.channelcount--; |
Meteor.channelcount--; |
75 |
|
if (Meteor.channelcount && Meteor.status != 0 && Meteor.status != 6) Meteor.connect(); |
76 |
|
else Meteor.disconnect(); |
77 |
}, |
}, |
78 |
|
|
79 |
connect: function() { |
connect: function() { |
|
Meteor.log("Connecting"); |
|
80 |
if (!Meteor.host) throw "Meteor host not specified"; |
if (!Meteor.host) throw "Meteor host not specified"; |
81 |
if (isNaN(Meteor.port)) throw "Meteor port not specified"; |
if (isNaN(Meteor.port)) throw "Meteor port not specified"; |
82 |
if (!Meteor.channelcount) throw "No channels specified"; |
if (!Meteor.channelcount) throw "No channels specified"; |
83 |
if (Meteor.status) Meteor.disconnect(); |
if (Meteor.status) Meteor.disconnect(); |
84 |
|
Meteor.log("Connecting"); |
85 |
Meteor.setstatus(1); |
Meteor.setstatus(1); |
86 |
var now = new Date(); |
if (!Meteor.hostid) Meteor.hostid = Meteor.time()+""+Math.floor(Math.random()*1000000) |
|
var t = now.getTime(); |
|
|
if (!Meteor.hostid) Meteor.hostid = t+""+Math.floor(Math.random()*1000000) |
|
87 |
document.domain = Meteor.extract_xss_domain(document.domain); |
document.domain = Meteor.extract_xss_domain(document.domain); |
88 |
if (Meteor.mode=="stream") Meteor.mode = Meteor.selectStreamTransport(); |
if (Meteor.mode=="stream") Meteor.mode = Meteor.selectStreamTransport(); |
89 |
Meteor.log("Selected "+Meteor.mode+" transport"); |
Meteor.log("Selected "+Meteor.mode+" transport"); |
97 |
Meteor.pingtimer = setTimeout(Meteor.pollmode, Meteor.pingtimeout); |
Meteor.pingtimer = setTimeout(Meteor.pollmode, Meteor.pingtimeout); |
98 |
|
|
99 |
} else { |
} else { |
100 |
Meteor.loadFrame("http://"+Meteor.host+((Meteor.port==80)?"":":"+Meteor.port)+"/poll.html"); |
Meteor.recvtimes[0] = Meteor.time(); |
|
Meteor.recvtimes[0] = t; |
|
101 |
if (Meteor.updatepollfreqtimer) clearTimeout(Meteor.updatepollfreqtimer); |
if (Meteor.updatepollfreqtimer) clearTimeout(Meteor.updatepollfreqtimer); |
102 |
if (Meteor.mode=='smartpoll') Meteor.updatepollfreqtimer = setInterval(Meteor.updatepollfreq, 2500); |
if (Meteor.mode=='smartpoll') Meteor.updatepollfreqtimer = setInterval(Meteor.updatepollfreq, 10000); |
103 |
if (Meteor.mode=='longpoll') Meteor.pollfreq = Meteor.minpollfreq; |
if (Meteor.mode=='longpoll') Meteor.pollfreq = Meteor.minpollfreq; |
104 |
|
Meteor.poll(); |
105 |
} |
} |
|
Meteor.lastrequest = t; |
|
106 |
}, |
}, |
107 |
|
|
108 |
disconnect: function() { |
disconnect: function() { |
109 |
if (Meteor.status) { |
if (Meteor.status) { |
110 |
|
if (Meteor.status != 6) Meteor.setstatus(0); |
111 |
|
Meteor.clearpoll(); |
112 |
clearTimeout(Meteor.pingtimer); |
clearTimeout(Meteor.pingtimer); |
113 |
clearTimeout(Meteor.updatepollfreqtimer); |
clearTimeout(Meteor.updatepollfreqtimer); |
114 |
clearTimeout(Meteor.frameloadtimer); |
clearTimeout(Meteor.frameloadtimer); |
115 |
if (typeof CollectGarbage == 'function') CollectGarbage(); |
if (typeof CollectGarbage == 'function') CollectGarbage(); |
116 |
Meteor.setstatus(0); |
Meteor.log("Disconnected"); |
117 |
|
try { Meteor.frameref.parentNode.removeChild(Meteor.frameref); delete Meteor.frameref; return true; } catch(e) { } |
118 |
|
try { Meteor.frameref.open(); Meteor.frameref.close(); return true; } catch(e) {} |
119 |
} |
} |
120 |
}, |
}, |
121 |
|
|
129 |
}, |
}, |
130 |
|
|
131 |
getSubsUrl: function() { |
getSubsUrl: function() { |
132 |
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; |
133 |
|
var surl = "http://" + host + ((Meteor.port==80)?"":":"+Meteor.port) + "/push/" + Meteor.hostid + "/" + Meteor.mode; |
134 |
for (var c in Meteor.channels) { |
for (var c in Meteor.channels) { |
135 |
surl += "/"+c; |
surl += "/"+c; |
136 |
if (Meteor.channels[c].lastmsgreceived > 0) { |
if (typeof Meteor.channels[c].lastmsgreceived != 'undefined') { |
137 |
surl += ".r"+(Meteor.channels[c].lastmsgreceived+1); |
surl += ".r"+(Meteor.channels[c].lastmsgreceived+1); |
138 |
} else if (Meteor.channels[c].backtrack > 0) { |
} else if (Meteor.channels[c].backtrack > 0) { |
139 |
surl += ".b"+Meteor.channels[c].backtrack; |
surl += ".b"+Meteor.channels[c].backtrack; |
140 |
} else if (Meteor.channels[c].backtrack < 0 || isNaN(Meteor.channels[c].backtrack)) { |
} else if (Meteor.channels[c].backtrack != undefined) { |
141 |
surl += ".h"; |
surl += ".h"; |
142 |
} |
} |
143 |
} |
} |
144 |
|
surl += "?nc="+Meteor.time(); |
145 |
return surl; |
return surl; |
146 |
}, |
}, |
147 |
|
|
182 |
|
|
183 |
pollmode: function() { |
pollmode: function() { |
184 |
Meteor.log("Ping timeout"); |
Meteor.log("Ping timeout"); |
185 |
Meteor.mode="simplepoll"; |
if (Meteor.mode != "smartpoll") { |
186 |
clearTimeout(Meteor.pingtimer); |
Meteor.mode="smartpoll"; |
187 |
|
Meteor.callbacks["changemode"]("poll"); |
188 |
|
clearTimeout(Meteor.pingtimer); |
189 |
|
Meteor.lastpingtime = false; |
190 |
|
} |
191 |
Meteor.connect(); |
Meteor.connect(); |
|
Meteor.callbacks["changemode"]("poll"); |
|
|
Meteor.lastpingtime = false; |
|
192 |
}, |
}, |
193 |
|
|
194 |
process: function(id, channel, data) { |
process: function(id, channel, data) { |
195 |
if (id == -1) { |
if (id == -1) { |
196 |
Meteor.log("Ping"); |
Meteor.log("Ping"); |
197 |
Meteor.ping(); |
Meteor.ping(); |
198 |
} else if (typeof(Meteor.channels[channel]) != "undefined" && id > Meteor.channels[channel].lastmsgreceived) { |
} else if (typeof(Meteor.channels[channel]) != "undefined") { |
199 |
Meteor.log("Message "+id+" received on channel "+channel+" (last id on channel: "+Meteor.channels[channel].lastmsgreceived+")\n"+data); |
Meteor.log("Message "+id+" received on channel "+channel+" (last id on channel: "+Meteor.channels[channel].lastmsgreceived+")\n"+data); |
200 |
Meteor.callbacks["process"](data); |
Meteor.callbacks["process"](data); |
201 |
Meteor.channels[channel].lastmsgreceived = id; |
Meteor.channels[channel].lastmsgreceived = id; |
202 |
if (Meteor.mode=="smartpoll") { |
if (Meteor.mode=="smartpoll") { |
203 |
var now = new Date(); |
Meteor.recvtimes[Meteor.recvtimes.length] = Meteor.time(); |
|
Meteor.recvtimes[Meteor.recvtimes.length] = now.getTime(); |
|
204 |
while (Meteor.recvtimes.length > 5) Meteor.recvtimes.shift(); |
while (Meteor.recvtimes.length > 5) Meteor.recvtimes.shift(); |
205 |
} |
} |
206 |
} |
} |
211 |
if (Meteor.pingtimer) { |
if (Meteor.pingtimer) { |
212 |
clearTimeout(Meteor.pingtimer); |
clearTimeout(Meteor.pingtimer); |
213 |
Meteor.pingtimer = setTimeout(Meteor.pollmode, Meteor.pingtimeout); |
Meteor.pingtimer = setTimeout(Meteor.pollmode, Meteor.pingtimeout); |
214 |
var now = new Date(); |
Meteor.lastpingtime = Meteor.time(); |
|
Meteor.lastpingtime = now.getTime(); |
|
215 |
} |
} |
216 |
Meteor.setstatus(5); |
Meteor.setstatus(5); |
217 |
}, |
}, |
218 |
|
|
219 |
reset: function() { |
reset: function() { |
220 |
Meteor.log("Stream reset"); |
if (Meteor.status != 6 && Meteor.status != 0) { |
221 |
Meteor.ping(); |
Meteor.log("Stream reset"); |
222 |
Meteor.callbacks["reset"](); |
Meteor.ping(); |
223 |
var now = new Date(); |
Meteor.callbacks["reset"](); |
224 |
var t = now.getTime(); |
var x = Meteor.pollfreq - (Meteor.time()-Meteor.lastrequest); |
225 |
var x = Meteor.pollfreq - (t-Meteor.lastrequest); |
if (x < 10) x = 10; |
226 |
if (x < 10) x = 10; |
setTimeout(Meteor.connect, x); |
227 |
setTimeout(Meteor.connect, x); |
} |
228 |
}, |
}, |
229 |
|
|
230 |
eof: function() { |
eof: function() { |
231 |
|
Meteor.log("Received end of stream, will not reconnect"); |
232 |
Meteor.callbacks["eof"](); |
Meteor.callbacks["eof"](); |
233 |
|
Meteor.setstatus(6); |
234 |
|
Meteor.disconnect(); |
235 |
|
}, |
236 |
|
|
237 |
|
channelInfo: function(channel, id) { |
238 |
|
Meteor.channels[channel].lastmsgreceived = id; |
239 |
|
Meteor.log("Received channel info for channel "+channel+": resume from "+id); |
240 |
}, |
}, |
241 |
|
|
242 |
updatepollfreq: function() { |
updatepollfreq: function() { |
|
var now = new Date(); |
|
|
var t = now.getTime(); |
|
243 |
var avg = 0; |
var avg = 0; |
244 |
for (var i=1; i<Meteor.recvtimes.length; i++) { |
for (var i=1; i<Meteor.recvtimes.length; i++) { |
245 |
avg += (Meteor.recvtimes[i]-Meteor.recvtimes[i-1]); |
avg += (Meteor.recvtimes[i]-Meteor.recvtimes[i-1]); |
246 |
} |
} |
247 |
avg += (t-Meteor.recvtimes[Meteor.recvtimes.length-1]); |
avg += (Meteor.time()-Meteor.recvtimes[Meteor.recvtimes.length-1]); |
248 |
avg /= Meteor.recvtimes.length; |
avg /= Meteor.recvtimes.length; |
249 |
var target = avg/2; |
var target = avg/2; |
250 |
if (target < Meteor.pollfreq && Meteor.pollfreq > Meteor.minpollfreq) Meteor.pollfreq = Math.ceil(Meteor.pollfreq*0.9); |
if (target < Meteor.pollfreq && Meteor.pollfreq > Meteor.minpollfreq) Meteor.pollfreq = Math.ceil(Meteor.pollfreq*0.9); |
270 |
Meteor.log("Frame load timeout"); |
Meteor.log("Frame load timeout"); |
271 |
if (Meteor.frameloadtimer) clearTimeout(Meteor.frameloadtimer); |
if (Meteor.frameloadtimer) clearTimeout(Meteor.frameloadtimer); |
272 |
Meteor.setstatus(3); |
Meteor.setstatus(3); |
273 |
setTimeout(Meteor.connect, 5000); |
Meteor.pollmode(); |
274 |
}, |
}, |
275 |
|
|
276 |
extract_xss_domain: function(old_domain) { |
extract_xss_domain: function(old_domain) { |
286 |
// 3 = Controller frame timeout, retrying. |
// 3 = Controller frame timeout, retrying. |
287 |
// 4 = Controller frame loaded and ready |
// 4 = Controller frame loaded and ready |
288 |
// 5 = Receiving data |
// 5 = Receiving data |
289 |
|
// 6 = End of stream, will not reconnect |
290 |
|
|
291 |
if (Meteor.status != newstatus) { |
if (Meteor.status != newstatus) { |
292 |
Meteor.status = newstatus; |
Meteor.status = newstatus; |
302 |
document.getElementById("meteorlogoutput").innerHTML += logstr+"<br/>"; |
document.getElementById("meteorlogoutput").innerHTML += logstr+"<br/>"; |
303 |
} |
} |
304 |
} |
} |
305 |
|
}, |
306 |
|
|
307 |
|
poll: function() { |
308 |
|
Meteor.pollaborted = 0; |
309 |
|
try { |
310 |
|
clearTimeout(Meteor.polltimer); |
311 |
|
} catch (e) {}; |
312 |
|
Meteor.lastrequest = Meteor.time(); |
313 |
|
if (Meteor.polltimeout) Meteor.polltimer = setTimeout(Meteor.clearpoll, Meteor.polltimeout); |
314 |
|
var scripttag = document.createElement("SCRIPT"); |
315 |
|
scripttag.type = "text/javascript"; |
316 |
|
scripttag.src = Meteor.getSubsUrl(); |
317 |
|
scripttag.id = "meteorpoll"+(++Meteor.pollnum); |
318 |
|
scripttag.className = "meteorpoll"; |
319 |
|
document.getElementsByTagName("HEAD")[0].appendChild(scripttag); |
320 |
|
}, |
321 |
|
|
322 |
|
clearpoll: function() { |
323 |
|
if (document.getElementById('meteorpoll'+Meteor.pollnum)) { |
324 |
|
var s = document.getElementById('meteorpoll'+Meteor.pollnum); |
325 |
|
s.parentNode.removeChild(s); |
326 |
|
} |
327 |
|
if (Meteor.status == 5) { |
328 |
|
var x = parent.Meteor.pollfreq - (Meteor.time()-Meteor.lastrequest); |
329 |
|
if (x < 10) x = 10; |
330 |
|
setTimeout(Meteor.poll, x); |
331 |
|
} |
332 |
|
}, |
333 |
|
|
334 |
|
time: function() { |
335 |
|
var now = new Date(); |
336 |
|
return now.getTime(); |
337 |
} |
} |
338 |
} |
} |
339 |
|
|