update comment about a removeChild that crash Opera on windows
[brisk.git] / web / xynt-streaming.js
1 // old targetpage == page and moved into start method
2
3 //
4 // CLASS transport_xhr
5 //
6 function transport_xhr(doc, xynt_streaming, page)
7 {
8     this.doc = doc;
9     this.xynt_streaming = xynt_streaming;
10     this.xhr = createXMLHttpRequest();
11     this.xhr.open('GET', page);
12
13     var self = this;
14     this.xhr.onreadystatechange = function () { self.xhr_cb(); };
15     this.xhr.send(null);
16
17     this.stopped = false;
18 }
19
20 transport_xhr.prototype = {
21     doc: null,
22     xynt_streaming: "ready",
23     xhr: null,
24     stopped: true,
25
26     ctx_old: "",
27     ctx_old_len: 0,
28     ctx_new: null,
29
30     // script_clean: 0,
31
32     destroy: function () { /* public */
33         if (this.xhr != null) {
34             this.xhr_abort();
35         }
36         delete this.xhr;
37     },
38
39     xhr_cb: function () {
40         var ret;
41
42         if (this.xhr.readyState == 4) {
43             // console.log("SS: "+safestatus(xhr));
44
45             // NOTE: delay management later
46             // try {
47             //     if ((ret = safestatus(this.xhr)) == 200) {
48             //         this.delay = 0;
49             //         // console.log("del a null "+this.delayed);
50             //     } else if (ret != -1) {
51             //         this.delay = 5000;
52             //         this.hbit('X');
53             //         // alert('There was a problem with the request.' + ret);
54             //     }
55             // } catch(b) {};
56
57             // this.delayed = null;
58             this.stopped = true;
59         }
60     },
61
62     xhr_abort: function() {
63         if (this.xhr != null) {
64             this.xhr.abort();
65         }
66     },
67
68     xstr_is_init: function () { /* public */
69         try {
70             if (this.xhr.responseText != null) {
71                 this.ctx_new = this.xhr.responseText;
72             }
73         }
74         catch (e) {
75         }
76
77         return (this.ctx_new != null);
78     },
79
80     /* only after a successfull is_initialized call */
81     xstr_is_ready: function () { /* public */
82         return (this.xynt_streaming == "ready");
83     },
84
85     xstr_set: function () { /* public */
86         // already set
87     },
88
89     ctx_new_is_set: function () { /* public */
90         return (this.ctx_new != null);
91     },
92
93     ctx_new_curlen_get: function () { /* public */
94         return (this.ctx_new.length);
95     },
96
97     ctx_new_getchar: function(idx) { /* public */
98         return (this.ctx_new[idx]);
99     },
100
101     ctx_old_len_is_set: function () { /* public */
102         return (true);
103     },
104
105     ctx_old_len_get: function () { /* public */
106         return (this.ctx_old_len);
107     },
108
109     ctx_old_len_set: function (len) { /* public */
110         this.ctx_old_len = len;
111     },
112
113     ctx_old_len_add: function (len) { /* public */
114         this.ctx_old_len += len;
115     },
116
117     new_part: function () { /* public */
118         return (this.ctx_new.substr(this.ctx_old_len));
119     },
120
121     scrcls_set: function (step) { /* public */
122         // this.script_clean = step;
123     },
124
125     postproc: function () {
126         if (this.stopped && !this.xstr_is_ready()) {
127             this.xynt_streaming.reload();
128         }
129     }
130 }
131
132 //
133 // CLASS transport_htmlfile
134 //
135 function transport_htmlfile(doc, xynt_streaming, page)
136 {
137     this.doc = doc;
138     this.xynt_streaming = xynt_streaming;
139     this.transfdoc = new ActiveXObject("htmlfile");
140     this.transfdoc.open();
141     /*this.transfdoc.write("<html><head><script>");
142     this.transfdoc.write("document.domain=\""+(doc.domain)+"\";");
143     this.transfdoc.write("</"+"script></"+"head>"); */
144     this.transfdoc.write("<html><body><iframe id='iframe'></iframe></body></html>");
145     this.transfdoc.close();
146
147     this.ifra = this.transfdoc.getElementById("iframe");
148     this.ifra.contentWindow.location.href = page;
149 }
150
151 transport_htmlfile.prototype = {
152     doc: null,
153     xynt_streaming: null,
154     ifra: null,
155     tradoc: null,
156
157     destroy: function () { /* public */
158         if (this.ifra != null) {
159         //     this.doc.body.removeChild(this.ifra);
160         //     delete this.ifra;
161              this.ifra = null;
162         }
163
164         if (this.transfdoc) {
165             delete this.transfdoc;
166             this.transfdoc = null;
167         }
168     },
169
170     xstr_is_init: function () { /* public */
171         return (typeof(this.ifra.contentWindow.xynt_streaming) != 'undefined');
172     },
173
174     /* only after a successfull is_initialized call */
175     xstr_set: function () { /* public */
176         if (this.ifra.contentWindow.xynt_streaming == "ready") {
177             this.ifra.contentWindow.xynt_streaming = this.xynt_streaming;
178             return (true);
179         }
180         else if (this.ifra.contentWindow.xynt_streaming == this.xynt_streaming) {
181             return (true);
182         }
183         else {
184             return (false);
185         }
186     },
187
188     ctx_new_is_set: function () { /* public */
189         return (typeof(this.ifra.contentWindow.ctx_new) != 'undefined');
190     },
191
192     ctx_new_curlen_get: function () { /* public */
193         return (this.ifra.contentWindow.ctx_new.length);
194     },
195
196     ctx_new_getchar: function(idx) { /* public */
197     },
198
199     ctx_old_len_is_set: function () { /* public */
200         return (typeof(this.ifra.contentWindow.ctx_old_len) != 'undefined');
201     },
202
203     ctx_old_len_get: function () { /* public */
204         return (this.ifra.contentWindow.ctx_old_len);
205     },
206
207     ctx_old_len_set: function (len) { /* public */
208         this.ifra.contentWindow.ctx_old_len = len;
209     },
210
211     ctx_old_len_add: function (len) { /* public */
212         this.ifra.contentWindow.ctx_old_len += len;
213     },
214
215     new_part: function () { /* public */
216         return (this.ifra.contentWindow.ctx_new.substr(this.ifra.contentWindow.ctx_old_len));
217     },
218
219     scrcls_set: function (step) { /* public */
220         this.ifra.contentWindow.script_clean = step;
221     },
222
223     postproc: function () {
224     }
225 }
226
227
228
229 //
230 // CLASS transport_iframe
231 //
232 function transport_iframe(doc, xynt_streaming, page)
233 {
234     this.doc = doc;
235     this.xynt_streaming = xynt_streaming;
236     this.ifra = doc.createElement("iframe");
237     this.ifra.style.visibility = "hidden";
238     doc.body.appendChild(this.ifra);
239     this.ifra.contentWindow.location.href = page;
240 }
241
242 transport_iframe.prototype = {
243     doc: null,
244     xynt_streaming: null,
245     ifra: null,
246
247     destroy: function () { /* public */
248         try {
249             if (this.ifra != null) {
250                 // FIXME: on Opera on Windows this remove child crash js so is commented
251                 //        on IE on Windows without it stream abort fails
252                 //        so we need to decide how can run it
253                 this.doc.body.removeChild(this.ifra);
254                 delete this.ifra;
255                 this.ifra = null;
256             }
257         } catch (b) {
258             alert("destroy exception catched");
259         }
260     },
261
262     xstr_is_init: function () { /* public */
263         return (typeof(this.ifra.contentWindow.xynt_streaming) != 'undefined');
264     },
265
266     /* only after a successfull is_initialized call */
267     xstr_is_ready: function () { /* public */
268         return (this.ifra.contentWindow.xynt_streaming == "ready");
269     },
270
271     /* only after a successfull is_initialized call */
272     xstr_set: function () { /* public */
273         if (this.ifra.contentWindow.xynt_streaming == "ready") {
274             this.ifra.contentWindow.xynt_streaming = this.xynt_streaming;
275             return (true);
276         }
277         else if (this.ifra.contentWindow.xynt_streaming == this.xynt_streaming) {
278             return (true);
279         }
280         else {
281             return (false);
282         }
283     },
284
285
286     /* only after a successfull is_ready call to be sure the accessibility of the var */
287     xstr_set_old: function (xynt_streaming) { /* public */
288         this.ifra.contentWindow.xynt_streaming = xynt_streaming;
289     },
290
291     ctx_new_is_set: function () { /* public */
292         return (typeof(this.ifra.contentWindow.ctx_new) != 'undefined');
293     },
294
295     ctx_new_curlen_get: function () { /* public */
296         return (this.ifra.contentWindow.ctx_new.length);
297     },
298
299     ctx_new_getchar: function(idx) { /* public */
300     },
301
302     ctx_old_len_is_set: function () { /* public */
303         return (typeof(this.ifra.contentWindow.ctx_old_len) != 'undefined');
304     },
305
306     ctx_old_len_get: function () { /* public */
307         return (this.ifra.contentWindow.ctx_old_len);
308     },
309
310     ctx_old_len_set: function (len) { /* public */
311         this.ifra.contentWindow.ctx_old_len = len;
312     },
313
314     ctx_old_len_add: function (len) { /* public */
315         this.ifra.contentWindow.ctx_old_len += len;
316     },
317
318     new_part: function () { /* public */
319         return (this.ifra.contentWindow.ctx_new.substr(this.ifra.contentWindow.ctx_old_len));
320     },
321
322     scrcls_set: function (step) { /* public */
323         this.ifra.contentWindow.script_clean = step;
324     },
325
326     postproc: function () {
327     }
328 }
329
330 function xynt_streaming(win, transp_type, console, gst, from, cookiename, sess, sandbox, page, cmdproc)
331 {
332     this.win = win;
333     this.transp_type = transp_type;
334     this.console = console;
335     this.gst = gst;
336     this.from = from;
337     this.cookiename = cookiename;
338     this.sess = sess;
339     this.sandbox = sandbox;
340     this.page = page;
341     this.cmdproc = cmdproc;
342     // this.cmdproc = function(com){/* console.log("COM: "+com); */ eval(com);}
343
344     this.doc = win.document;
345     this.keepalive_old = -1;
346     this.keepalive_new = -1;
347 }
348
349 xynt_streaming.prototype = {
350     win:               null,
351     transp_type:       null,
352     transp:            null,
353     console:           null,
354     gst:               null,
355     from:              null,
356     cookiename:        null,
357     sess:              null,
358     sandbox:           null,
359     page:              null,
360     cmdproc:           null,
361
362     doc:               null,
363     cookiepath: "/brisk/",
364     watchdog_hdl:      null,
365     hbit:              null,
366     keepalive_old:    -1,
367     keepalive_new:    -1,
368     keepalives_equal:  0,
369     /* NOTE: right watch_timeout value to 100, for devel reasons use 1000 or more */
370     /* restart after  4 * 40 * 100 millisec if server ping is missing => 16secs */
371     keepalives_eq_max: 4,
372     watchdog_checktm:  40,
373     // FIXME watchdog_timeout:  100,
374     watchdog_timeout:  100,
375     watchdog_ct:       0,
376     watchable:         false,
377     restart_n:         0,
378     comm_match:        /_*@BEGIN@(.*?)@END@/g, 
379     comm_clean:        /_*@BEGIN@(.*?)@END@/,
380     stream:            "",
381     the_end:           false,
382
383     start: function() { /* public */
384         if (this.the_end) 
385             return;
386
387         createCookie(this.cookiename, sess, 24*365, this.cookiepath);
388         // alert("start");
389         this.log("xynt_streaming:start restart: "+this.restart_n);
390         this.keepalives_equal = 0;
391
392         // page arrangement
393         this.page = url_complete(this.win.location.href, this.page);
394         // stat, subst, this.gst.st
395
396         this.page = url_append_args(this.page, "sess", this.sess, "stat", stat, "subst", subst, "step", this.gst.st, "from", this.from);
397         this.log(this.page);
398
399         // transport instantiation
400         if (this.transp_type == "xhr") {
401             this.page = url_append_args(this.page, "transp", "xhr");
402             this.transp = new transport_xhr(this.doc, this, this.page);
403         }
404         else if (this.transp_type == "iframe") {
405             this.page = url_append_args(this.page, "transp", "iframe");
406             this.transp = new transport_iframe(this.doc, this, this.page);
407         }
408         else if (this.transp_type == "htmlfile") {
409             this.page = url_append_args(this.page, "transp", "htmlfile");
410             this.transp = new transport_htmlfile(this.doc, this, this.page);
411         }
412         else
413             return;
414
415         // watchdog setting
416         this.watchdog_ct  = 0;
417         if (!this.the_end) {
418             this.watchdog_hdl = setTimeout(function(obj) { obj.log("tout1"); obj.watchdog(); }, this.watchdog_timeout, this);
419         }
420     },
421
422     stop: function() {
423         this.the_end = true;
424         this.abort();
425     },
426
427     hbit_set: function (hbit) {
428         this.hbit = hbit;
429     },
430
431     watchdog: function () {
432         // alert("watchdog");
433         var i, again;
434         var comm_newpart, comm_len, comm_arr;
435         var ctx_new_len;
436
437         if (this.sandbox != null) {
438             // from old: var zug = "POLL sess = "+sess+" stat = "+stat+" subst = "+subst+" step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new+" STOP: "+this.stopped;
439             var zug = "WATCHDOG  sess = ["+this.sess+"]  step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new;          
440             if (zug != this.sandbox.innerHTML)
441                 this.sandbox.innerHTML = zug;
442         }
443
444         // WATCHDOGING THE CONNECTION
445         this.log("hs::watchdog: start, cur equal times: "+this.keepalives_equal);
446         if (!this.watchable) {
447             do {
448                 try{
449                     // if (typeof(this.ifra.contentWindow.xynt_streaming) == 'undefined')
450                     if (!this.transp.xstr_is_init()) {
451                         this.log("hs::watchdog: xstr_is_init = false");
452                         break;
453                     }
454                 }
455                 catch(b) {
456                     this.log("hs::watchdog: exception");
457                     break;
458                 }
459
460                 /*
461                   on IE7 the the window frame scope is cleaned after the href is set, so we wait 
462                   for a well know variable value before assign this object value to it (OO is a passion)
463                 */
464                 // if (this.ifra.contentWindow.xynt_streaming == "ready") {
465                 if (this.transp.xstr_set()) {
466                     // this.ifra.contentWindow.xynt_streaming = this;
467                     this.watchable = true;
468                     this.watchdog_ct = 0;
469                     this.log("hs::watchdog: watchable = yes");
470                 }
471             } while (false);
472         }
473         if ( (this.watchdog_ct % this.watchdog_checktm) == 0) {
474             this.log("hs::watchdog: this.keepalive_old: "+this.keepalive_old+" this.keepalive_new: "+this.keepalive_new);
475             if (this.keepalive_old == this.keepalive_new) {
476                 this.keepalives_equal++;
477             }
478             else {
479                 this.keepalive_old = this.keepalive_new;
480                 this.keepalives_equal = 0;
481             }
482             
483             if (this.keepalives_equal >= this.keepalives_eq_max) {
484                 this.log("hs::watchdog: MAX ACHIEVED "+this.keepalives_equal);
485                 this.reload();
486                 // alert("watchdog return reload");
487                 return;
488             }
489         }
490
491         // PICK COMMANDS FROM STREAM
492         do {
493             // alert("do--while begin ["+again+"]");
494             // CHECK: maybe again here isn't needed 
495             again = 0;
496             try {
497                 /* if (typeof(this.ifra.contentWindow.ctx_new)     == 'undefined' ||
498                    typeof(this.ifra.contentWindow.ctx_old_len) == 'undefined') */
499                 if (!this.transp.ctx_new_is_set() || !this.transp.ctx_old_len_is_set())
500                     break;
501             }
502             catch(b) {
503                 break;
504             }
505
506             // ctx_new_len = this.ifra.contentWindow.ctx_new.length;
507             ctx_new_len = this.transp.ctx_new_curlen_get();
508             // if (ctx_new_len <= this.ifra.contentWindow.ctx_old_len) {
509             if (ctx_new_len <= this.transp.ctx_old_len_get()) {
510                 break;
511             }
512             this.log("new: "+ ctx_new_len + "  old: "+this.transp.ctx_old_len_get());
513             this.keepalive_new++;
514             // alert("pre-loop 1");
515             for (i = this.transp.ctx_old_len_get() ; i < ctx_new_len ; i++) {
516                 // if (this.ifra.contentWindow.ctx_new.charAt(i) != '_') {
517                 if (this.transp.ctx_new_getchar(i) != '_') {
518                     // this.log("ctx_new.char(i) != '_' ["+this.ifra.contentWindow.ctx_new.charAt(i)+"]");
519                     break;
520                 }
521                 // else {
522                 //     this.log("ctx_new.charAt(i) == '_'");
523                 // }
524             }
525             // this.ifra.contentWindow.ctx_old_len = i;
526             this.transp.ctx_old_len_set(i);
527             if (i == ctx_new_len) {
528                 this.log("old_len == i");
529                 break;
530             }
531             else {
532                 this.log("old_len != i: "+i);
533             }
534             // alert("do--while middle ["+this.ifra.contentWindow.ctx_old_len+"]");
535
536             comm_newpart = this.transp.new_part();
537             this.log("COM_NEWPART: ["+comm_newpart+"]");
538             comm_len = 0;
539             comm_arr = comm_newpart.match(this.comm_match);
540
541             // alert("do--while middle2 ["+again+"]");
542             if (comm_arr) {
543                 var comm_arr_len = comm_arr.length;
544                 for (i = 0 ; i < comm_arr_len ; i++) {
545                     var temp = comm_arr[i].replace(this.comm_clean,"$1").split("|");
546                     this.gst.comms = this.gst.comms.concat(temp);
547                     comm_len += comm_arr[i].length;
548                 }
549                 again = 1;
550             }
551             // this.ifra.contentWindow.ctx_old_len += comm_len;
552             this.transp.ctx_old_len_add(comm_len);
553             // this.ifra.contentWindow.script_clean = this.gst.st;
554             this.transp.scrcls_set(this.gst.st);
555             // alert("do--while end ["+again+"]");
556         } while (again);
557
558         // alert("post while");
559         // EXECUTION OF STREAM COMMANDS
560         do {
561             again = 0;
562             //MOP ?? xhrrestart = 0;
563             if (this.gst.st_loc < this.gst.st_loc_new) {
564                 // there is some slow actions running
565                 break;
566             }
567             else if (this.gst.comms.length > 0) {
568                 var singlecomm;
569                 
570                 singlecomm = this.gst.comms.shift();
571                 // alert("EXE"+gugu);
572                 // $("xhrdeltalog").innerHTML = "EVALL: "+singlecomm.replace("<", "&lt;", "g"); +"<br>";
573                 //xx this.hbit("+");
574
575                 // alert("SINGLE: ["+singlecomm+"]");
576                 this.cmdproc(singlecomm);
577                 again = 1;
578             }
579         } while (again);
580         this.watchdog_ct++;
581         if (!this.the_end) {
582             this.transp.postproc();
583             this.watchdog_hdl = setTimeout(function(obj) { /* obj.log("tout2"); */ obj.watchdog(); }, this.watchdog_timeout, this);
584         }
585         // alert("watchdog return normal");
586
587         return;
588     },
589
590     //
591     // moved to xynt-streaming-ifra as push()
592     //
593     // keepalive: function (s) {
594     //     this.log("hs::keepalive");
595     //     if (s != null) {
596     //         this.log(s);
597     //         this.ifra.contentWindow.ctx_new += "@BEGIN@"+s+"@END@";
598     //     }
599     //     else {
600     //         this.ifra.contentWindow.ctx_new += "_";
601     //     }
602     //     // this.keepalive_new++;
603     // },
604
605     abort: function () { /* public */
606         // this.log("PATH: "+this.ifra.contentWindow.location.protocol + "://" + this.ifra.contentWindow.location.host + "/" + this.ifra.contentWindow.location.pathname);
607
608         this.gst.abort();
609         if (this.watchdog_hdl != null) {
610             clearTimeout(this.watchdog_hdl);
611             this.watchdog_hdl = null;
612         }
613
614         this.restart_n++;
615         this.log("hs::reload");
616         this.watchable = false;
617         if (this.transp != null) {
618             this.transp.destroy();
619             delete this.transp;
620             this.transp = null;
621         }
622     },
623
624     reload: function () {
625         this.abort();
626         this.start(null);
627     },
628
629     log: function (s) {
630         if (this.console != null) {
631             return (this.console.log(s));
632         }
633     }
634 }