16 |
f(a);g(args); |
f(a);g(args); |
17 |
} |
} |
18 |
}; |
}; |
|
function addUnLoadEvent(func) { |
|
|
var oldonunload = window.onunload; |
|
|
if (typeof window.onunload != 'function') { |
|
|
window.onunload = func; |
|
|
} else { |
|
|
window.onunload = function() { |
|
|
if (oldonunload) { |
|
|
oldonunload(); |
|
|
} |
|
|
func(); |
|
|
} |
|
|
} |
|
|
} |
|
|
addUnLoadEvent(meteordestroy); |
|
|
function meteordestroy() { |
|
|
var x = Meteor.instances.length; |
|
|
for(var i=0; i<x; i++) { |
|
|
if (typeof(Meteor.instances[i].transferDoc)=="object") { |
|
|
Meteor.instances[i].transferDoc.open(); |
|
|
Meteor.instances[i].transferDoc.close(); |
|
|
delete Meteor.instances[i].transferDoc; |
|
|
} |
|
|
if (document.getElementById("meteorframe_"+Meteor.instances[i].instID)) { |
|
|
document.body.removeChild(document.getElementById("meteorframe_"+Meteor.instances[i].instID)); |
|
|
} |
|
|
delete Meteor.instances[i]; |
|
|
} |
|
|
} |
|
19 |
|
|
20 |
function Meteor(instID) { |
function Meteor(instID) { |
21 |
|
|
|
this.lastmsgreceived = -1; |
|
22 |
this.transferDoc = false; |
this.transferDoc = false; |
23 |
this.pingtimer = false; |
this.pingtimer = false; |
24 |
this.updatepollfreqtimer = false; |
this.updatepollfreqtimer = false; |
32 |
this.callback_statuschanged = function() {}; |
this.callback_statuschanged = function() {}; |
33 |
this.persist = true; |
this.persist = true; |
34 |
this.frameloadtimer = false; |
this.frameloadtimer = false; |
35 |
this.frameurl = false; |
this.debugmode = false; |
36 |
|
this.subsurl = false; |
37 |
|
|
38 |
// Documented public properties |
// Documented public properties |
39 |
this.channel = false; |
this.channels = new Array(); |
40 |
this.subdomain = "data"; |
this.subdomain = "data"; |
41 |
this.dynamicpageaddress = "push"; |
this.dynamicpageaddress = "push"; |
|
this.backtrack = 0; |
|
42 |
this.smartpoll = true; |
this.smartpoll = true; |
43 |
this.pollfreq = 2000; |
this.pollfreq = 2000; |
44 |
this.minpollfreq = 2000; |
this.minpollfreq = 2000; |
45 |
this.mode = "stream"; |
this.mode = "poll"; |
46 |
this.polltimeout=30000; |
this.polltimeout=30000; |
|
this.maxmessages=0; |
|
47 |
this.pingtimeout = 10000; |
this.pingtimeout = 10000; |
48 |
|
this.maxmessages = 0; |
49 |
this.status = 0; |
this.status = 0; |
50 |
|
|
51 |
/* Statuses: 0 = Uninitialised, |
/* Statuses: 0 = Uninitialised, |
52 |
1 = Loading stream, |
1 = Loading stream, |
53 |
2 = Loading controller frame, |
2 = Loading controller frame, |
54 |
3 = Controller frame timeout, retrying every 5 seconds |
3 = Controller frame timeout, retrying. |
55 |
4 = Controller frame loaded and ready |
4 = Controller frame loaded and ready |
56 |
5 = Receiving data |
5 = Receiving data |
57 |
*/ |
*/ |
58 |
|
|
|
// Set or retrieve host id. Cookie takes this form: |
|
|
// MeteorID=123:6356353/124:098320454; |
|
|
var MeteIds = Meteor.readCookie("MeteorID"); |
|
|
var regex1 = new RegExp("^([0-9\:\/M]+\/)*"+instID+"\:([^\/]+)(\/[0-9\:\/M]+)*$"); |
|
|
var regex2 = new RegExp("^([0-9\:\/M]+\/)*M\:([^\/]+)(\/[0-9\:\/M]+)*$"); |
|
|
if (typeof(instID) == "Number" && regex1.exec(MeteIds)) { |
|
|
this.MHostId = ma[2]; |
|
|
} else if (typeof(instID) == "Number") { |
|
|
this.MHostId = Math.floor(Math.random()*1000000); |
|
|
var newcookie = (MeteIds)?MeteIds+"/":""; |
|
|
newcookie += instID+":"+this.MHostId; |
|
|
Meteor.createCookie("MeteorID", newcookie); |
|
|
} else if (ma = regex2.exec(MeteIds)) { |
|
|
this.MHostId = ma[2]; |
|
|
} else { |
|
|
this.MHostId = Math.floor(Math.random()*1000000); |
|
|
var newcookie = (MeteIds)?MeteIds+"/":""; |
|
|
newcookie += "M:"+this.MHostId; |
|
|
Meteor.createCookie("MeteorID", newcookie); |
|
|
} |
|
59 |
this.instID = (typeof(instID) != "undefined") ? instID : 0; |
this.instID = (typeof(instID) != "undefined") ? instID : 0; |
60 |
|
this.MHostId = Math.floor(Math.random()*100000000)+""+this.instID; |
61 |
} |
} |
62 |
|
|
63 |
Meteor.instances = new Array(); |
Meteor.instances = new Array(); |
|
Meteor.servertimeoffset = 0; |
|
64 |
|
|
65 |
Meteor.create = function(instID) { |
Meteor.create = function(instID) { |
66 |
if (!instID) instID = 0; |
if (!instID) instID = Meteor.instances.length; |
67 |
Meteor.instances[instID] = new Meteor(instID); |
Meteor.instances[instID] = new Meteor(instID); |
68 |
return Meteor.instances[instID]; |
return Meteor.instances[instID]; |
69 |
} |
} |
70 |
|
|
71 |
Meteor.register = function(ifr) { |
Meteor.register = function(ifr) { |
72 |
instid = new String(ifr.window.frameElement.id); |
instid = new String(ifr.window.frameElement.id); |
73 |
instid = instid.replace("meteorframe_", ""); |
instid = instid.replace(/.*_([0-9]*)$/, "$1"); |
74 |
ifr.p = this.instances[instid].process.bind(this.instances[instid]); |
ifr.p = this.instances[instid].process.bind(this.instances[instid]); |
75 |
ifr.r = this.instances[instid].reset.bind(this.instances[instid]); |
ifr.r = this.instances[instid].reset.bind(this.instances[instid]); |
76 |
ifr.eof = this.instances[instid].eof.bind(this.instances[instid]); |
ifr.eof = this.instances[instid].eof.bind(this.instances[instid]); |
78 |
ifr.increasepolldelay = this.instances[instid].increasepolldelay.bind(this.instances[instid]); |
ifr.increasepolldelay = this.instances[instid].increasepolldelay.bind(this.instances[instid]); |
79 |
clearTimeout(this.instances[instid].frameloadtimer); |
clearTimeout(this.instances[instid].frameloadtimer); |
80 |
this.instances[instid].setstatus(4); |
this.instances[instid].setstatus(4); |
81 |
|
if (this.debugmode) console.log("Frame registered"); |
82 |
} |
} |
83 |
|
|
84 |
Meteor.setServerTime = function(timestamp) { |
Meteor.reset = function(ifr) { |
85 |
var now = new Date(); |
instid = new String(ifr.window.frameElement.id); |
86 |
var clienttime = (now.getTime() / 1000); |
instid = instid.replace(/.*_([0-9]*)$/, "$1"); |
87 |
Meteor.servertimeoffset = timestamp - clienttime; |
this.instances[instid].reset(); |
88 |
|
} |
89 |
|
|
90 |
|
Meteor.prototype.joinChannel = function(channelname, backtrack) { |
91 |
|
if (typeof(this.channels[channelname]) != "undefined") throw "Cannot join channel "+channelname+": already subscribed"; |
92 |
|
this.channels[channelname] = {backtrack:backtrack, lastmsgreceived:0}; |
93 |
|
if (this.status != 0) this.start(); |
94 |
|
} |
95 |
|
|
96 |
|
Meteor.prototype.leaveChannel = function(channelname) { |
97 |
|
if (typeof(this.channels[channelname]) == "undefined") throw "Cannot leave channel "+channelname+": not subscribed"; |
98 |
|
delete this.channels[channelname]; |
99 |
|
if (this.status != 0) this.start(); |
100 |
} |
} |
101 |
|
|
102 |
Meteor.prototype.start = function() { |
Meteor.prototype.start = function() { |
103 |
this.persist = (this.maxmessages)?1:0; |
this.persist = (this.maxmessages)?1:0; |
104 |
this.smartpoll = (this.smartpoll)?1:0; |
this.smartpoll = (this.smartpoll)?1:0; |
105 |
this.mode = (this.mode=="stream")?"stream":"poll"; |
this.mode = (this.mode=="stream")?"stream":"poll"; |
106 |
if (!this.subdomain || !this.channel) throw "Channel or Meteor subdomain host not specified"; |
if (!this.subdomain || this.channels.length) throw "Channel or Meteor subdomain host not specified"; |
107 |
|
this.stop(); |
108 |
var now = new Date(); |
var now = new Date(); |
109 |
var t = now.getTime(); |
var t = now.getTime(); |
110 |
if (typeof(this.transferDoc)=="object") { |
this.setstatus(1); |
111 |
this.transferDoc.open(); |
var surl = "http://" + this.subdomain + "." + location.hostname + "/" + this.dynamicpageaddress + "?id=" + this.MHostId; |
112 |
this.transferDoc.close(); |
if (this.maxmessages && !this.persist) surl += "&maxmessages=" + this.maxmessages; |
113 |
delete this.transferDoc; |
for (var c in this.channels) { |
114 |
} |
surl += "&channel="+c; |
115 |
if (document.getElementById("meteorframe_"+this.instID)) { |
if (this.channels[c].lastmsgreceived >= 0) { |
116 |
document.body.removeChild(document.getElementById("meteorframe_"+this.instID)); |
surl += "&restartfrom="+this.channels[c].lastmsgreceived; |
117 |
|
} else if (this.channels[c].backtrack > 0) { |
118 |
|
surl += "&backtrack="+this.channels[c].backtrack; |
119 |
|
} else if (this.channels[c].backtrack < 0 || isNaN(this.channels[c].backtrack)) { |
120 |
|
surl += "&restartfrom="; |
121 |
|
} |
122 |
} |
} |
123 |
|
this.subsurl = surl; |
124 |
if (this.mode=="stream") { |
if (this.mode=="stream") { |
125 |
if (document.all) { |
this.createIframe(this.subsurl); |
|
this.setstatus(1); |
|
|
this.transferDoc = new ActiveXObject("htmlfile"); |
|
|
this.transferDoc.open(); |
|
|
this.transferDoc.write("<html>"); |
|
|
this.transferDoc.write("<script>document.domain=\""+(document.domain)+"\";</"+"script>"); |
|
|
this.transferDoc.write("</html>"); |
|
|
var selfref = this; |
|
|
this.transferDoc.parentWindow.Meteor = Meteor; |
|
|
this.transferDoc.close(); |
|
|
var ifrDiv = this.transferDoc.createElement("div"); |
|
|
this.transferDoc.appendChild(ifrDiv); |
|
|
var url = "http://"+this.subdomain+"."+location.hostname+"/"+this.dynamicpageaddress+"?channel="+this.channel+"&id="+this.MHostId; |
|
|
if (this.lastmsgreceived >= 0) { |
|
|
url += "&restartfrom="+this.lastmsgreceived; |
|
|
} else if (this.backtrack > 0) { |
|
|
url += "&backtrack="+this.backtrack; |
|
|
} else if (this.backtrack < 0 || isNaN(this.backtrack)) { |
|
|
url += "&restartfrom="; |
|
|
} |
|
|
ifrDiv.innerHTML = "<iframe id=\"meteorframe_"+this.instID+"\" src=\""+url+"&nocache="+t+"\" style=\"display: none;\"></iframe>"; |
|
|
} else { |
|
|
var ifr = document.createElement("IFRAME"); |
|
|
ifr.style.width = "10px"; |
|
|
ifr.style.height = "10px"; |
|
|
ifr.style.border = "none"; |
|
|
ifr.style.position = "absolute"; |
|
|
ifr.style.top = "-10px"; |
|
|
ifr.style.marginTop = "-10px"; |
|
|
ifr.style.zIndex = "-20"; |
|
|
ifr.id = "meteorframe_"+this.instID; |
|
|
document.body.appendChild(ifr); |
|
|
this.frameurl = "http://"+this.subdomain+"."+location.hostname+"/stream.html"; |
|
|
this.frameload(); |
|
|
} |
|
126 |
var f = this.pollmode.bind(this); |
var f = this.pollmode.bind(this); |
127 |
clearTimeout(this.pingtimer); |
clearTimeout(this.pingtimer); |
128 |
this.pingtimer = setTimeout(f, this.pingtimeout); |
this.pingtimer = setTimeout(f, this.pingtimeout); |
129 |
|
|
130 |
} else { |
} else { |
131 |
|
this.createIframe("http://"+this.subdomain+"."+location.hostname+"/poll.html"); |
132 |
|
this.recvtimes[0] = t; |
133 |
|
if (this.updatepollfreqtimer) clearTimeout(this.updatepollfreqtimer); |
134 |
|
this.updatepollfreqtimer = setInterval(this.updatepollfreq.bind(this), 2500); |
135 |
|
} |
136 |
|
this.lastrequest = t; |
137 |
|
} |
138 |
|
|
139 |
|
Meteor.prototype.createIframe = function(url) { |
140 |
|
if (document.all) { |
141 |
|
this.transferDoc = new ActiveXObject("htmlfile"); |
142 |
|
this.transferDoc.open(); |
143 |
|
this.transferDoc.write("<html>"); |
144 |
|
this.transferDoc.write("<script>document.domain=\""+(document.domain)+"\";</"+"script>"); |
145 |
|
this.transferDoc.write("</html>"); |
146 |
|
var selfref = this; |
147 |
|
this.transferDoc.parentWindow.Meteor = Meteor; |
148 |
|
this.transferDoc.close(); |
149 |
|
var ifrDiv = this.transferDoc.createElement("div"); |
150 |
|
this.transferDoc.appendChild(ifrDiv); |
151 |
|
ifrDiv.innerHTML = "<iframe id=\"meteorframe_"+this.instID+"\" src=\""+url+"\" style=\"display: none;\"></iframe>"; |
152 |
|
} else { |
153 |
var ifr = document.createElement("IFRAME"); |
var ifr = document.createElement("IFRAME"); |
154 |
ifr.style.width = "10px"; |
ifr.style.width = "10px"; |
155 |
ifr.style.height = "10px"; |
ifr.style.height = "10px"; |
156 |
ifr.style.border = "none"; |
ifr.style.border = "none"; |
157 |
if (document.all) { |
ifr.style.position = "absolute"; |
158 |
ifr.style.display = "none"; |
ifr.style.top = "-10px"; |
159 |
} else { |
ifr.style.marginTop = "-10px"; |
160 |
ifr.style.position = "absolute"; |
ifr.style.zIndex = "-20"; |
161 |
ifr.style.marginTop = "-10px"; |
ifr.setAttribute("id", "meteorframe_"+this.instID); |
162 |
ifr.style.zIndex = "-20"; |
ifr.Meteor = Meteor; |
163 |
} |
var innerifr = document.createElement("IFRAME"); |
164 |
ifr.id = "meteorframe_"+this.instID; |
innerifr.setAttribute("src", url); |
165 |
|
innerifr.setAttribute("id", "meteorinnerframe_"+this.instID); |
166 |
|
ifr.appendChild(innerifr); |
167 |
document.body.appendChild(ifr); |
document.body.appendChild(ifr); |
|
this.frameurl = "http://"+this.subdomain+"."+location.hostname+"/poll.html"; |
|
|
this.frameload(); |
|
|
this.recvtimes[0] = t; |
|
|
if (this.updatepollfreqtimer) clearTimeout(this.updatepollfreqtimer); |
|
|
this.updatepollfreqtimer = setInterval(this.updatepollfreq.bind(this), 2500); |
|
168 |
} |
} |
169 |
this.lastrequest = t; |
if (this.debugmode) console.log("Loading URL '"+url+"' into frame..."); |
170 |
|
var f = this.frameloadtimeout.bind(this); |
171 |
|
this.frameloadtimer = setTimeout(f, 5000); |
172 |
|
} |
173 |
|
|
174 |
|
Meteor.prototype.stop = function() { |
175 |
|
if (typeof(this.transferDoc)=="object") { |
176 |
|
this.transferDoc = false; |
177 |
|
} |
178 |
|
if (document.getElementById("meteorframe_"+this.instID)) { |
179 |
|
document.getElementById("meteorframe_"+this.instID).src="about:blank"; |
180 |
|
document.body.removeChild(document.getElementById("meteorframe_"+this.instID)); |
181 |
|
} |
182 |
|
if (!isNaN(this.pingtimer)) clearTimeout(this.pingtimer); |
183 |
|
if (!isNaN(this.updatepollfreqtimer)) clearTimeout(this.updatepollfreqtimer); |
184 |
|
if (!isNaN(this.frameloadtimer)) clearTimeout(this.frameloadtimer); |
185 |
|
this.setstatus(0); |
186 |
} |
} |
187 |
|
|
188 |
Meteor.prototype.pollmode = function() { |
Meteor.prototype.pollmode = function() { |
189 |
|
if (this.debugmode) console.log("Ping timeout"); |
190 |
this.mode="poll"; |
this.mode="poll"; |
191 |
this.start(); |
this.start(); |
192 |
this.callback_changemode("poll"); |
this.callback_changemode("poll"); |
193 |
this.lastpingtime = false; |
this.lastpingtime = false; |
194 |
} |
} |
195 |
|
|
196 |
Meteor.prototype.process = function(id, data) { |
Meteor.prototype.process = function(id, channel, data) { |
197 |
if (id > this.lastmsgreceived) { |
if (id > this.channels[channel].lastmsgreceived) { |
198 |
|
if (this.debugmode) console.log("Message "+id+" received on channel "+channel+": "+data); |
199 |
this.callback_process(data); |
this.callback_process(data); |
200 |
if (id != -1) this.lastmsgreceived = id; |
this.channels[channel].lastmsgreceived = id; |
201 |
if (this.mode=="poll") { |
if (this.mode=="poll") { |
202 |
var now = new Date(); |
var now = new Date(); |
203 |
var t = now.getTime(); |
var t = now.getTime(); |
205 |
while (this.recvtimes.length > 5) this.recvtimes.shift(); |
while (this.recvtimes.length > 5) this.recvtimes.shift(); |
206 |
} |
} |
207 |
} else if (id == -1) { |
} else if (id == -1) { |
208 |
|
if (this.debugmode) console.log("Ping"); |
209 |
this.ping(); |
this.ping(); |
210 |
} |
} |
211 |
this.setstatus(5); |
this.setstatus(5); |
223 |
} |
} |
224 |
|
|
225 |
Meteor.prototype.reset = function() { |
Meteor.prototype.reset = function() { |
226 |
|
if (this.debugmode) console.log("Stream reset"); |
227 |
var now = new Date(); |
var now = new Date(); |
228 |
var t = now.getTime(); |
var t = now.getTime(); |
229 |
var x = this.pollfreq - (t-this.lastrequest); |
var x = this.pollfreq - (t-this.lastrequest); |
278 |
} |
} |
279 |
} |
} |
280 |
|
|
|
Meteor.prototype.frameload = function() { |
|
|
this.setstatus(2); |
|
|
if (document.getElementById("meteorframe_"+this.instID)) { |
|
|
var f = this.frameloadtimeout.bind(this); |
|
|
this.frameloadtimer = setTimeout(f, 5000); |
|
|
document.getElementById("meteorframe_"+this.instID).src = "about:blank"; |
|
|
setTimeout(this.doloadurl.bind(this), 100); |
|
|
} |
|
|
} |
|
|
Meteor.prototype.doloadurl = function() { |
|
|
var now = new Date(); |
|
|
var t = now.getTime(); |
|
|
document.getElementById("meteorframe_"+this.instID).src = this.frameurl+"?nocache="+t; |
|
|
} |
|
281 |
Meteor.prototype.frameloadtimeout = function() { |
Meteor.prototype.frameloadtimeout = function() { |
282 |
|
if (this.debugmode) console.log("Frame load timeout"); |
283 |
if (this.frameloadtimer) clearTimeout(this.frameloadtimer); |
if (this.frameloadtimer) clearTimeout(this.frameloadtimer); |
284 |
this.setstatus(3); |
this.setstatus(3); |
285 |
this.frameload(); |
setTimeout(this.start.bind(this), 5000); |
286 |
} |
} |
287 |
Meteor.prototype.setstatus = function(newstatus) { |
Meteor.prototype.setstatus = function(newstatus) { |
288 |
if (this.status != newstatus) { |
if (this.status != newstatus) { |