move restart of iframe/htmlfile based stream from iframe onload callback to postproc...
[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     this.stopped = false;
150 }
151
152 transport_htmlfile.prototype = {
153     doc: null,
154     xynt_streaming: null,
155     stopped: true,
156     ifra: null,
157     tradoc: null,
158
159     destroy: function () { /* public */
160         if (this.ifra != null) {
161         //     this.doc.body.removeChild(this.ifra);
162         //     delete this.ifra;
163              this.ifra = null;
164         }
165
166         if (this.transfdoc) {
167             delete this.transfdoc;
168             this.transfdoc = null;
169         }
170     },
171
172     xstr_is_init: function () { /* public */
173         return (typeof(this.ifra.contentWindow.xynt_streaming) != 'undefined');
174     },
175
176     /* only after a successfull is_initialized call */
177     xstr_set: function () { /* public */
178         if (this.ifra.contentWindow.xynt_streaming == "ready") {
179             this.ifra.contentWindow.xynt_streaming = this.xynt_streaming;
180             return (true);
181         }
182         else if (this.ifra.contentWindow.xynt_streaming == this.xynt_streaming) {
183             return (true);
184         }
185         else {
186             return (false);
187         }
188     },
189
190     ctx_new_is_set: function () { /* public */
191         return (typeof(this.ifra.contentWindow.ctx_new) != 'undefined');
192     },
193
194     ctx_new_curlen_get: function () { /* public */
195         return (this.ifra.contentWindow.ctx_new.length);
196     },
197
198     ctx_new_getchar: function(idx) { /* public */
199     },
200
201     ctx_old_len_is_set: function () { /* public */
202         return (typeof(this.ifra.contentWindow.ctx_old_len) != 'undefined');
203     },
204
205     ctx_old_len_get: function () { /* public */
206         return (this.ifra.contentWindow.ctx_old_len);
207     },
208
209     ctx_old_len_set: function (len) { /* public */
210         this.ifra.contentWindow.ctx_old_len = len;
211     },
212
213     ctx_old_len_add: function (len) { /* public */
214         this.ifra.contentWindow.ctx_old_len += len;
215     },
216
217     new_part: function () { /* public */
218         return (this.ifra.contentWindow.ctx_new.substr(this.ifra.contentWindow.ctx_old_len));
219     },
220
221     scrcls_set: function (step) { /* public */
222         this.ifra.contentWindow.script_clean = step;
223     },
224
225     postproc: function () { /* public */
226         if (this.stopped && !this.xstr_is_ready()) {
227             this.xynt_streaming.reload();
228         }
229     }
230 }
231
232
233
234 //
235 // CLASS transport_iframe
236 //
237 function transport_iframe(doc, xynt_streaming, page)
238 {
239     this.doc = doc;
240     this.xynt_streaming = xynt_streaming;
241     this.ifra = doc.createElement("iframe");
242     this.ifra.style.visibility = "hidden";
243     doc.body.appendChild(this.ifra);
244     this.ifra.contentWindow.location.href = page;
245     this.stopped = false;
246 }
247
248 transport_iframe.prototype = {
249     doc: null,
250     xynt_streaming: null,
251     stopped: true,
252     ifra: null,
253
254     destroy: function () { /* public */
255         try {
256             if (this.ifra != null) {
257                 // NOTE:  on Opera this remove child crash js if called from
258                 //        inside of the iframe, on IE on Windows without
259                 //        it stream abort fails.
260                 //        the problem is fixed setting into the iframe's onload
261                 //        function the stopped attribute to true and delegate
262                 //        postproc() fired by xynt_streaming watchdog()
263                 this.doc.body.removeChild(this.ifra);
264                 delete this.ifra;
265                 this.ifra = null;
266             }
267         } catch (b) {
268             alert("destroy exception catched");
269         }
270     },
271
272     xstr_is_init: function () { /* public */
273         return (typeof(this.ifra.contentWindow.xynt_streaming) != 'undefined');
274     },
275
276     /* only after a successfull is_initialized call */
277     xstr_is_ready: function () { /* public */
278         return (this.ifra.contentWindow.xynt_streaming == "ready");
279     },
280
281     /* only after a successfull is_initialized call */
282     xstr_set: function () { /* public */
283         if (this.ifra.contentWindow.xynt_streaming == "ready") {
284             this.ifra.contentWindow.xynt_streaming = this.xynt_streaming;
285             return (true);
286         }
287         else if (this.ifra.contentWindow.xynt_streaming == this.xynt_streaming) {
288             return (true);
289         }
290         else {
291             return (false);
292         }
293     },
294
295
296     /* only after a successfull is_ready call to be sure the accessibility of the var */
297     xstr_set_old: function (xynt_streaming) { /* public */
298         this.ifra.contentWindow.xynt_streaming = xynt_streaming;
299     },
300
301     ctx_new_is_set: function () { /* public */
302         return (typeof(this.ifra.contentWindow.ctx_new) != 'undefined');
303     },
304
305     ctx_new_curlen_get: function () { /* public */
306         return (this.ifra.contentWindow.ctx_new.length);
307     },
308
309     ctx_new_getchar: function(idx) { /* public */
310     },
311
312     ctx_old_len_is_set: function () { /* public */
313         return (typeof(this.ifra.contentWindow.ctx_old_len) != 'undefined');
314     },
315
316     ctx_old_len_get: function () { /* public */
317         return (this.ifra.contentWindow.ctx_old_len);
318     },
319
320     ctx_old_len_set: function (len) { /* public */
321         this.ifra.contentWindow.ctx_old_len = len;
322     },
323
324     ctx_old_len_add: function (len) { /* public */
325         this.ifra.contentWindow.ctx_old_len += len;
326     },
327
328     new_part: function () { /* public */
329         return (this.ifra.contentWindow.ctx_new.substr(this.ifra.contentWindow.ctx_old_len));
330     },
331
332     scrcls_set: function (step) { /* public */
333         this.ifra.contentWindow.script_clean = step;
334     },
335
336     postproc: function () { /* public */
337         if (this.stopped && !this.xstr_is_ready()) {
338             this.xynt_streaming.reload();
339         }
340     }
341 }
342
343 function xynt_streaming(win, transp_type, console, gst, from, cookiename, sess, sandbox, page, cmdproc)
344 {
345     this.win = win;
346     this.transp_type = transp_type;
347     this.console = console;
348     this.gst = gst;
349     this.from = from;
350     this.cookiename = cookiename;
351     this.sess = sess;
352     this.sandbox = sandbox;
353     this.page = page;
354     this.cmdproc = cmdproc;
355     // this.cmdproc = function(com){/* console.log("COM: "+com); */ eval(com);}
356
357     this.doc = win.document;
358     this.keepalive_old = -1;
359     this.keepalive_new = -1;
360 }
361
362 xynt_streaming.prototype = {
363     win:               null,
364     transp_type:       null,
365     transp:            null,
366     console:           null,
367     gst:               null,
368     from:              null,
369     cookiename:        null,
370     sess:              null,
371     sandbox:           null,
372     page:              null,
373     cmdproc:           null,
374
375     doc:               null,
376     cookiepath: "/brisk/",
377     watchdog_hdl:      null,
378     hbit:              null,
379     keepalive_old:    -1,
380     keepalive_new:    -1,
381     keepalives_equal:  0,
382     /* NOTE: right watch_timeout value to 100, for devel reasons use 1000 or more */
383     /* restart after  4 * 40 * 100 millisec if server ping is missing => 16secs */
384     keepalives_eq_max: 4,
385     watchdog_checktm:  40,
386     // FIXME watchdog_timeout:  100,
387     watchdog_timeout:  100,
388     watchdog_ct:       0,
389     watchable:         false,
390     restart_n:         0,
391     comm_match:        /_*@BEGIN@(.*?)@END@/g, 
392     comm_clean:        /_*@BEGIN@(.*?)@END@/,
393     stream:            "",
394     the_end:           false,
395
396     start: function() { /* public */
397         if (this.the_end) 
398             return;
399
400         createCookie(this.cookiename, sess, 24*365, this.cookiepath);
401         // alert("start");
402         this.log("xynt_streaming:start restart: "+this.restart_n);
403         this.keepalives_equal = 0;
404
405         // page arrangement
406         this.page = url_complete(this.win.location.href, this.page);
407         // stat, subst, this.gst.st
408
409         this.page = url_append_args(this.page, "sess", this.sess, "stat", stat, "subst", subst, "step", this.gst.st, "from", this.from);
410         this.log(this.page);
411
412         // transport instantiation
413         if (this.transp_type == "xhr") {
414             this.page = url_append_args(this.page, "transp", "xhr");
415             this.transp = new transport_xhr(this.doc, this, this.page);
416         }
417         else if (this.transp_type == "iframe") {
418             this.page = url_append_args(this.page, "transp", "iframe");
419             this.transp = new transport_iframe(this.doc, this, this.page);
420         }
421         else if (this.transp_type == "htmlfile") {
422             this.page = url_append_args(this.page, "transp", "htmlfile");
423             this.transp = new transport_htmlfile(this.doc, this, this.page);
424         }
425         else
426             return;
427
428         // watchdog setting
429         this.watchdog_ct  = 0;
430         if (!this.the_end) {
431             this.watchdog_hdl = setTimeout(function(obj) { obj.log("tout1"); obj.watchdog(); }, this.watchdog_timeout, this);
432         }
433     },
434
435     stop: function() {
436         this.the_end = true;
437         this.abort();
438     },
439
440     hbit_set: function (hbit) {
441         this.hbit = hbit;
442     },
443
444     watchdog: function () {
445         // alert("watchdog");
446         var i, again;
447         var comm_newpart, comm_len, comm_arr;
448         var ctx_new_len;
449
450         if (this.sandbox != null) {
451             // 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;
452             var zug = "WATCHDOG  sess = ["+this.sess+"]  step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new;          
453             if (zug != this.sandbox.innerHTML)
454                 this.sandbox.innerHTML = zug;
455         }
456
457         // WATCHDOGING THE CONNECTION
458         this.log("hs::watchdog: start, cur equal times: "+this.keepalives_equal);
459         if (!this.watchable) {
460             do {
461                 try{
462                     // if (typeof(this.ifra.contentWindow.xynt_streaming) == 'undefined')
463                     if (!this.transp.xstr_is_init()) {
464                         this.log("hs::watchdog: xstr_is_init = false");
465                         break;
466                     }
467                 }
468                 catch(b) {
469                     this.log("hs::watchdog: exception");
470                     break;
471                 }
472
473                 /*
474                   on IE7 the the window frame scope is cleaned after the href is set, so we wait 
475                   for a well know variable value before assign this object value to it (OO is a passion)
476                 */
477                 // if (this.ifra.contentWindow.xynt_streaming == "ready") {
478                 if (this.transp.xstr_set()) {
479                     // this.ifra.contentWindow.xynt_streaming = this;
480                     this.watchable = true;
481                     this.watchdog_ct = 0;
482                     this.log("hs::watchdog: watchable = yes");
483                 }
484             } while (false);
485         }
486         if ( (this.watchdog_ct % this.watchdog_checktm) == 0) {
487             this.log("hs::watchdog: this.keepalive_old: "+this.keepalive_old+" this.keepalive_new: "+this.keepalive_new);
488             if (this.keepalive_old == this.keepalive_new) {
489                 this.keepalives_equal++;
490             }
491             else {
492                 this.keepalive_old = this.keepalive_new;
493                 this.keepalives_equal = 0;
494             }
495             
496             if (this.keepalives_equal >= this.keepalives_eq_max) {
497                 this.log("hs::watchdog: MAX ACHIEVED "+this.keepalives_equal);
498                 this.reload();
499                 // alert("watchdog return reload");
500                 return;
501             }
502         }
503
504         // PICK COMMANDS FROM STREAM
505         do {
506             // alert("do--while begin ["+again+"]");
507             // CHECK: maybe again here isn't needed 
508             again = 0;
509             try {
510                 /* if (typeof(this.ifra.contentWindow.ctx_new)     == 'undefined' ||
511                    typeof(this.ifra.contentWindow.ctx_old_len) == 'undefined') */
512                 if (!this.transp.ctx_new_is_set() || !this.transp.ctx_old_len_is_set())
513                     break;
514             }
515             catch(b) {
516                 break;
517             }
518
519             // ctx_new_len = this.ifra.contentWindow.ctx_new.length;
520             ctx_new_len = this.transp.ctx_new_curlen_get();
521             // if (ctx_new_len <= this.ifra.contentWindow.ctx_old_len) {
522             if (ctx_new_len <= this.transp.ctx_old_len_get()) {
523                 break;
524             }
525             this.log("new: "+ ctx_new_len + "  old: "+this.transp.ctx_old_len_get());
526             this.keepalive_new++;
527             // alert("pre-loop 1");
528             for (i = this.transp.ctx_old_len_get() ; i < ctx_new_len ; i++) {
529                 // if (this.ifra.contentWindow.ctx_new.charAt(i) != '_') {
530                 if (this.transp.ctx_new_getchar(i) != '_') {
531                     // this.log("ctx_new.char(i) != '_' ["+this.ifra.contentWindow.ctx_new.charAt(i)+"]");
532                     break;
533                 }
534                 // else {
535                 //     this.log("ctx_new.charAt(i) == '_'");
536                 // }
537             }
538             // this.ifra.contentWindow.ctx_old_len = i;
539             this.transp.ctx_old_len_set(i);
540             if (i == ctx_new_len) {
541                 this.log("old_len == i");
542                 break;
543             }
544             else {
545                 this.log("old_len != i: "+i);
546             }
547             // alert("do--while middle ["+this.ifra.contentWindow.ctx_old_len+"]");
548
549             comm_newpart = this.transp.new_part();
550             this.log("COM_NEWPART: ["+comm_newpart+"]");
551             comm_len = 0;
552             comm_arr = comm_newpart.match(this.comm_match);
553
554             // alert("do--while middle2 ["+again+"]");
555             if (comm_arr) {
556                 var comm_arr_len = comm_arr.length;
557                 for (i = 0 ; i < comm_arr_len ; i++) {
558                     var temp = comm_arr[i].replace(this.comm_clean,"$1").split("|");
559                     this.gst.comms = this.gst.comms.concat(temp);
560                     comm_len += comm_arr[i].length;
561                 }
562                 again = 1;
563             }
564             // this.ifra.contentWindow.ctx_old_len += comm_len;
565             this.transp.ctx_old_len_add(comm_len);
566             // this.ifra.contentWindow.script_clean = this.gst.st;
567             this.transp.scrcls_set(this.gst.st);
568             // alert("do--while end ["+again+"]");
569         } while (again);
570
571         // alert("post while");
572         // EXECUTION OF STREAM COMMANDS
573         do {
574             again = 0;
575             //MOP ?? xhrrestart = 0;
576             if (this.gst.st_loc < this.gst.st_loc_new) {
577                 // there is some slow actions running
578                 break;
579             }
580             else if (this.gst.comms.length > 0) {
581                 var singlecomm;
582                 
583                 singlecomm = this.gst.comms.shift();
584                 // alert("EXE"+gugu);
585                 // $("xhrdeltalog").innerHTML = "EVALL: "+singlecomm.replace("<", "&lt;", "g"); +"<br>";
586                 //xx this.hbit("+");
587
588                 // alert("SINGLE: ["+singlecomm+"]");
589                 this.cmdproc(singlecomm);
590                 again = 1;
591             }
592         } while (again);
593         this.watchdog_ct++;
594         if (!this.the_end) {
595             this.transp.postproc();
596             this.watchdog_hdl = setTimeout(function(obj) { /* obj.log("tout2"); */ obj.watchdog(); }, this.watchdog_timeout, this);
597         }
598         // alert("watchdog return normal");
599
600         return;
601     },
602
603     //
604     // moved to xynt-streaming-ifra as push()
605     //
606     // keepalive: function (s) {
607     //     this.log("hs::keepalive");
608     //     if (s != null) {
609     //         this.log(s);
610     //         this.ifra.contentWindow.ctx_new += "@BEGIN@"+s+"@END@";
611     //     }
612     //     else {
613     //         this.ifra.contentWindow.ctx_new += "_";
614     //     }
615     //     // this.keepalive_new++;
616     // },
617
618     abort: function () { /* public */
619         // this.log("PATH: "+this.ifra.contentWindow.location.protocol + "://" + this.ifra.contentWindow.location.host + "/" + this.ifra.contentWindow.location.pathname);
620
621         this.gst.abort();
622         if (this.watchdog_hdl != null) {
623             clearTimeout(this.watchdog_hdl);
624             this.watchdog_hdl = null;
625         }
626
627         this.restart_n++;
628         this.log("hs::reload");
629         this.watchable = false;
630         if (this.transp != null) {
631             this.transp.destroy();
632             delete this.transp;
633             this.transp = null;
634         }
635     },
636
637     reload: function () {
638         this.abort();
639         this.start(null);
640     },
641
642     log: function (s) {
643         if (this.console != null) {
644             return (this.console.log(s));
645         }
646     }
647 }