/[meteor]/googlecode.com/svn/trunk/public_html/meteor.js
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /googlecode.com/svn/trunk/public_html/meteor.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (show annotations)
Thu Dec 14 10:45:43 2006 UTC (17 years, 4 months ago) by andrew.betts
File MIME type: application/javascript
File size: 10544 byte(s)
Some additional logging and bug fixes

1 // Set domain at highest level
2 var domainparts = document.domain.split(".");
3 document.domain = domainparts[domainparts.length-2]+"."+domainparts[domainparts.length-1];
4
5 Function.prototype.bind = function(obj) {
6 var method = this,
7 temp = function() {
8 return method.apply(obj, arguments);
9 };
10 return temp;
11 }
12 Function.prototype.andThen=function(g) {
13 var f=this;
14 var a=this.arguments
15 return function(args) {
16 f(a);g(args);
17 }
18 };
19 function addUnLoadEvent(func) {
20 var oldonunload = window.onunload;
21 if (typeof window.onunload != 'function') {
22 window.onunload = func;
23 } else {
24 window.onunload = function() {
25 if (oldonunload) {
26 oldonunload();
27 }
28 func();
29 }
30 }
31 }
32 //addUnLoadEvent(meteordestroy);
33 function meteordestroy() {
34 var x = Meteor.instances.length;
35 for(var i=0; i<x; i++) {
36 Meteor.instances[i].stop();
37 delete Meteor.instances[i];
38 }
39 }
40
41 function Meteor(instID) {
42
43 this.lastmsgreceived = -1;
44 this.transferDoc = false;
45 this.pingtimer = false;
46 this.updatepollfreqtimer = false;
47 this.lastrequest = 0;
48 this.recvtimes = new Array();
49 this.MHostId = false;
50 this.callback_process = function() {};
51 this.callback_reset = function() {};
52 this.callback_eof = function() {};
53 this.callback_changemode = function() {};
54 this.callback_statuschanged = function() {};
55 this.persist = true;
56 this.frameloadtimer = false;
57 this.frameurl = false;
58
59 // Documented public properties
60 this.channel = false;
61 this.subdomain = "data";
62 this.dynamicpageaddress = "push";
63 this.backtrack = 0;
64 this.smartpoll = true;
65 this.pollfreq = 2000;
66 this.minpollfreq = 2000;
67 this.mode = "stream";
68 this.polltimeout=30000;
69 this.maxmessages=0;
70 this.pingtimeout = 10000;
71 this.status = 0;
72
73 /* Statuses: 0 = Uninitialised,
74 1 = Loading stream,
75 2 = Loading controller frame,
76 3 = Controller frame timeout, retrying every 5 seconds
77 4 = Controller frame loaded and ready
78 5 = Receiving data
79 */
80
81 this.instID = (typeof(instID) != "undefined") ? instID : 0;
82 this.MHostId = Math.floor(Math.random()*100000000)+this.instID;
83 }
84
85 Meteor.instances = new Array();
86 Meteor.servertimeoffset = 0;
87
88 Meteor.create = function(instID) {
89 if (!instID) instID = Meteor.instances.length;
90 Meteor.instances[instID] = new Meteor(instID);
91 return Meteor.instances[instID];
92 }
93
94 Meteor.register = function(ifr) {
95 instid = new String(ifr.window.frameElement.id);
96 instid = instid.replace("meteorframe_", "");
97 ifr.p = this.instances[instid].process.bind(this.instances[instid]);
98 ifr.r = this.instances[instid].reset.bind(this.instances[instid]);
99 ifr.eof = this.instances[instid].eof.bind(this.instances[instid]);
100 ifr.get = this.instances[instid].get.bind(this.instances[instid]);
101 ifr.increasepolldelay = this.instances[instid].increasepolldelay.bind(this.instances[instid]);
102 clearTimeout(this.instances[instid].frameloadtimer);
103 this.instances[instid].setstatus(4);
104 }
105
106 Meteor.setServerTime = function(timestamp) {
107 var now = new Date();
108 var clienttime = (now.getTime() / 1000);
109 Meteor.servertimeoffset = timestamp - clienttime;
110 }
111
112 Meteor.prototype.start = function() {
113 this.persist = (this.maxmessages)?1:0;
114 this.smartpoll = (this.smartpoll)?1:0;
115 this.mode = (this.mode=="stream")?"stream":"poll";
116 if (!this.subdomain || !this.channel) throw "Channel or Meteor subdomain host not specified";
117 var now = new Date();
118 var t = now.getTime();
119 if (typeof(this.transferDoc)=="object") {
120 this.transferDoc.open();
121 this.transferDoc.close();
122 delete this.transferDoc;
123 }
124 if (document.getElementById("meteorframe_"+this.instID)) {
125 document.body.removeChild(document.getElementById("meteorframe_"+this.instID));
126 }
127 if (this.mode=="stream") {
128 if (document.all) {
129 this.setstatus(1);
130 this.transferDoc = new ActiveXObject("htmlfile");
131 this.transferDoc.open();
132 this.transferDoc.write("<html>");
133 this.transferDoc.write("<script>document.domain=\""+(document.domain)+"\";</"+"script>");
134 this.transferDoc.write("</html>");
135 var selfref = this;
136 this.transferDoc.parentWindow.Meteor = Meteor;
137 this.transferDoc.close();
138 var ifrDiv = this.transferDoc.createElement("div");
139 this.transferDoc.appendChild(ifrDiv);
140 var url = "http://"+this.subdomain+"."+location.hostname+"/"+this.dynamicpageaddress+"?channel="+this.channel+"&id="+this.MHostId;
141 if (this.lastmsgreceived >= 0) {
142 url += "&restartfrom="+this.lastmsgreceived;
143 } else if (this.backtrack > 0) {
144 url += "&backtrack="+this.backtrack;
145 } else if (this.backtrack < 0 || isNaN(this.backtrack)) {
146 url += "&restartfrom=";
147 }
148 ifrDiv.innerHTML = "<iframe id=\"meteorframe_"+this.instID+"\" src=\""+url+"&nocache="+t+"\" style=\"display: none;\"></iframe>";
149 } else {
150 var ifr = document.createElement("IFRAME");
151 ifr.style.width = "10px";
152 ifr.style.height = "10px";
153 ifr.style.border = "none";
154 ifr.style.position = "absolute";
155 ifr.style.top = "-10px";
156 ifr.style.marginTop = "-10px";
157 ifr.style.zIndex = "-20";
158 ifr.id = "meteorframe_"+this.instID;
159 document.body.appendChild(ifr);
160 this.frameurl = "http://"+this.subdomain+"."+location.hostname+"/stream.html";
161 this.frameload();
162 }
163 var f = this.pollmode.bind(this);
164 clearTimeout(this.pingtimer);
165 this.pingtimer = setTimeout(f, this.pingtimeout);
166
167 } else {
168 var ifr = document.createElement("IFRAME");
169 ifr.style.width = "10px";
170 ifr.style.height = "10px";
171 ifr.style.border = "none";
172 if (document.all) {
173 ifr.style.display = "none";
174 } else {
175 ifr.style.position = "absolute";
176 ifr.style.marginTop = "-10px";
177 ifr.style.zIndex = "-20";
178 }
179 ifr.id = "meteorframe_"+this.instID;
180 document.body.appendChild(ifr);
181 this.frameurl = "http://"+this.subdomain+"."+location.hostname+"/poll.html";
182 this.frameload();
183 this.recvtimes[0] = t;
184 if (this.updatepollfreqtimer) clearTimeout(this.updatepollfreqtimer);
185 this.updatepollfreqtimer = setInterval(this.updatepollfreq.bind(this), 2500);
186 }
187 this.lastrequest = t;
188 }
189
190 Meteor.prototype.stop = function() {
191 if (typeof(this.transferDoc)=="object") {
192 this.transferDoc.open();
193 this.transferDoc.close();
194 delete this.transferDoc;
195 }
196 if (document.getElementById("meteorframe_"+this.instID)) {
197 document.getElementById("meteorframe_"+this.instID).src="about:blank";
198 document.body.removeChild(document.getElementById("meteorframe_"+this.instID));
199 }
200 if (!isNaN(this.pingtimer)) clearTimeout(this.pingtimer);
201 if (!isNaN(this.updatepollfreqtimer)) clearTimeout(this.updatepollfreqtimer);
202 if (!isNaN(this.frameloadtimer)) clearTimeout(this.frameloadtimer);
203 this.setstatus(0);
204 }
205
206 Meteor.prototype.pollmode = function() {
207 this.mode="poll";
208 this.start();
209 this.callback_changemode("poll");
210 this.lastpingtime = false;
211 }
212
213 Meteor.prototype.process = function(id, data) {
214 if (id > this.lastmsgreceived) {
215 this.callback_process(data);
216 if (id != -1) this.lastmsgreceived = id;
217 if (this.mode=="poll") {
218 var now = new Date();
219 var t = now.getTime();
220 this.recvtimes[this.recvtimes.length] = t;
221 while (this.recvtimes.length > 5) this.recvtimes.shift();
222 }
223 } else if (id == -1) {
224 this.ping();
225 }
226 this.setstatus(5);
227 }
228
229 Meteor.prototype.ping = function() {
230 if (this.mode=="stream" && this.pingtimer) {
231 clearTimeout(this.pingtimer);
232 var f = this.pollmode.bind(this);
233 this.pingtimer = setTimeout(f, this.pingtimeout);
234 var now = new Date();
235 this.lastpingtime = now.getTime();
236 }
237 this.setstatus(5);
238 }
239
240 Meteor.prototype.reset = function() {
241 var now = new Date();
242 var t = now.getTime();
243 var x = this.pollfreq - (t-this.lastrequest);
244 if (x < 10) x = 10;
245 this.ping();
246 this.callback_reset();
247 setTimeout(this.start.bind(this), x);
248 }
249
250 Meteor.prototype.eof = function() {
251 this.callback_eof();
252 }
253
254 Meteor.prototype.get = function(varname) {
255 eval("var a = this."+varname+";");
256 if (typeof(a) == "undefined") throw "Cannot get value of "+varname;
257 return a;
258 }
259
260 Meteor.prototype.increasepolldelay = function() {
261 this.pollfreq *= 2;
262 }
263
264 Meteor.prototype.updatepollfreq = function() {
265 if (this.smartpoll) {
266 var now = new Date();
267 var t = now.getTime();
268 var avg = 0;
269 for (var i=1; i<this.recvtimes.length; i++) {
270 var x = (this.recvtimes[i]-this.recvtimes[i-1]);
271 avg += (x>60000)? 60000 : x;
272 }
273 x = (t-this.recvtimes[this.recvtimes.length-1]);
274 avg += (x>180000)? 180000 : x;
275 avg /= this.recvtimes.length;
276 if ((avg/3) < this.pollfreq && (avg/3) >= this.minpollfreq) this.pollfreq = Math.ceil(this.pollfreq*0.9);
277 if ((avg/3) > this.pollfreq) this.pollfreq = Math.floor(this.pollfreq*1.05);
278 }
279 }
280
281 Meteor.prototype.registerEventCallback = function(evt, funcRef) {
282 if (evt=="process") {
283 this.callback_process = (this.callback_process).andThen(funcRef);
284 } else if (evt=="reset") {
285 this.callback_reset = (this.callback_reset).andThen(funcRef);
286 } else if (evt=="eof") {
287 this.callback_eof = (this.callback_eof).andThen(funcRef);
288 } else if (evt=="changemode") {
289 this.callback_changemode = (this.callback_changemode).andThen(funcRef);
290 } else if (evt=="changestatus") {
291 this.callback_statuschanged = (this.callback_statuschanged).andThen(funcRef);
292 }
293 }
294
295 Meteor.prototype.frameload = function() {
296 this.setstatus(2);
297 if (document.getElementById("meteorframe_"+this.instID)) {
298 var f = this.frameloadtimeout.bind(this);
299 this.frameloadtimer = setTimeout(f, 5000);
300 document.getElementById("meteorframe_"+this.instID).src = "about:blank";
301 setTimeout(this.doloadurl.bind(this), 100);
302 }
303 }
304 Meteor.prototype.doloadurl = function() {
305 var now = new Date();
306 var t = now.getTime();
307 document.getElementById("meteorframe_"+this.instID).src = this.frameurl+"?nocache="+t;
308 }
309 Meteor.prototype.frameloadtimeout = function() {
310 if (this.frameloadtimer) clearTimeout(this.frameloadtimer);
311 this.setstatus(3);
312 this.frameload();
313 }
314 Meteor.prototype.setstatus = function(newstatus) {
315 if (this.status != newstatus) {
316 this.status = newstatus;
317 this.callback_statuschanged(newstatus);
318 }
319 }
320
321 Meteor.createCookie = function(name,value,days) {
322 if (days) {
323 var date = new Date();
324 date.setTime(date.getTime()+(days*24*60*60*1000));
325 var expires = "; expires="+date.toGMTString();
326 }
327 else var expires = "";
328 document.cookie = name+"="+value+expires+"; path=/";
329 }
330
331 Meteor.readCookie = function(name) {
332 var nameEQ = name + "=";
333 var ca = document.cookie.split(';');
334 for(var i=0;i < ca.length;i++) {
335 var c = ca[i];
336 while (c.charAt(0)==' ') c = c.substring(1,c.length);
337 if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
338 }
339 return null;
340 }
341
342 Meteor.eraseCookie = function(name) {
343 createCookie(name,"",-1);
344 }

  ViewVC Help
Powered by ViewVC 1.1.26