Merge branch 'post-bold2' into avoid-domino
[brisk.git] / web / xynt-streaming.js
1 // old targetpage == page and moved into start method
2
3 //
4 // CLASS transport_ws
5 //
6 function transport_ws(doc, xynt_streaming, page)
7 {
8     // if four arguments manage if WS or WSS connection
9     if (arguments.length > 3)
10         this.is_secure = arguments[3];
11     else
12         this.is_secure = false;
13
14     if (this.is_secure)
15         this.name = "WebSocketSecure";
16     else
17         this.name = "WebSocket";
18     this.ctx_new = "";
19     var self = this;
20
21     this.doc = doc;
22     this.failed = false;
23     this.xynt_streaming = xynt_streaming;
24     try {
25         this.xynt_streaming.log("PAGE: "+page);
26         this.ws = new WebSocket(page);
27         this.ws.onopen = function () {
28             console.log('WS On open');
29
30             self.xynt_streaming.log("onopen");
31             if (this.readyState == 1) {
32                 // connected
33                 self.ws_cb("open");
34                 self.init_steps = 1;
35             }
36         };
37         this.ws.onmessage = function (msg) {
38             console.log('WS On message');
39             self.xynt_streaming.log("onmessage");
40             // new data in msg.data
41             self.ctx_new += msg.data;
42         };
43         this.ws.onclose = function (msg) {
44             console.log('WS On close');
45             self.onopen  = null;
46             self.onclose = null;
47             self.onerror = null;
48             self.xynt_streaming.log("onclose"+self.init_steps);
49             if (self.init_steps == 0)
50                 self.ws_cb("error");
51             else
52                 self.ws_cb("close");
53         };
54         this.ws.onerror = function () {
55             // on error
56             this.onopen  = null;
57             this.onclose = null;
58             this.onerror = null;
59             self.xynt_streaming.log("onerror");
60             self.ws_cb("error");
61         };
62     }
63     catch (ex) {
64         throw "websocket creation failed";
65     }
66
67     this.stopped = false;
68 }
69
70 transport_ws.prototype = {
71     doc: null,
72     name: null,
73     xynt_streaming: "ready",
74     ws: null,
75     stopped: true,
76     failed: false,
77
78     init_steps: 0,
79
80     ctx_old: "",
81     ctx_old_len: 0,
82     ctx_new: "",
83
84     // script_clean: 0,
85
86     destroy: function () { /* public */
87         if (this.ws != null) {
88             this.ws_abort();
89         }
90         delete this.ws;
91     },
92
93     ws_cb: function (from) {
94         var ret;
95
96         if (from == "error") {
97             if (this.xynt_streaming != "ready") {
98                 if (this.xynt_streaming.transp_fback > 0) {
99 this.xynt_streaming.log("DEC: "+this.xynt_streaming.transp_fback);
100                     this.xynt_streaming.transp_fback--;
101                     this.stopped = true;
102                     this.xynt_streaming.reload();
103                 }
104             }
105         }
106         else if (from == "open") {
107             this.flush_out_queue();
108         }
109
110         if (this.ws != null && this.ws.readyState > 1) {
111             this.stopped = true;
112         }
113     },
114
115     flush_out_queue: function() {
116         var l_out = this.xynt_streaming.out_queue.length;
117
118         if (l_out == 0)
119             return;
120
121         console.log('flush_out_queue: ' + l_out);
122         for (var i = 0 ; i < l_out ; i++) {
123             if (this.ws.readyState != 1) {
124                 break;
125             }
126             var item = this.xynt_streaming.out_queue.shift();
127             var sent = true;
128             try {
129                 this.ws.send(item);
130             }
131             catch (ex) {
132                 this.xynt_streaming.out_queue.unshift(item);
133                 break;
134             }
135         }
136     },
137
138     send: function(msg) {
139         console.log('new send');
140         if (this.ws && this.ws.readyState == 1) {
141             try {
142                 console.log('Try send ... ');
143                 this.flush_out_queue();
144                 this.ws.send(msg);
145                 console.log(' ... done');
146             }
147             catch (ex) {
148                 console.log(' ... catched exception');
149                 this.xynt_streaming.out_queue.push(msg);
150             }
151         }
152         else {
153             console.log('ws not ready: push into out_queue');
154             this.xynt_streaming.out_queue.push(msg);
155         }
156     },
157
158     ws_abort: function() {
159         if (this.ws != null) {
160 this.xynt_streaming.log("WSCLOSE");
161             this.ws.close();
162         }
163     },
164
165     xstr_is_init: function () { /* public */
166         return (true);
167     },
168
169     /* only after a successfull is_initialized call */
170     xstr_is_ready: function () { /* public */
171         return (this.ws.readyState == 1);
172     },
173
174     xstr_set: function () { /* public */
175         // already set
176     },
177
178     ctx_new_is_set: function () { /* public */
179         return (this.ctx_new != null);
180     },
181
182     ctx_new_curlen_get: function () { /* public */
183         return (this.ctx_new.length);
184     },
185
186     ctx_new_getchar: function(idx) { /* public */
187         return (this.ctx_new[idx]);
188     },
189
190     ctx_old_len_is_set: function () { /* public */
191         return (true);
192     },
193
194     ctx_old_len_get: function () { /* public */
195         return (this.ctx_old_len);
196     },
197
198     ctx_old_len_set: function (len) { /* public */
199         this.ctx_old_len = len;
200     },
201
202     ctx_old_len_add: function (len) { /* public */
203         this.ctx_old_len += len;
204     },
205
206     new_part: function () { /* public */
207         return (this.ctx_new.substr(this.ctx_old_len));
208     },
209
210     scrcls_set: function (step) { /* public */
211         // this.script_clean = step;
212     },
213
214     postproc: function () {
215         if (this.stopped && !this.xstr_is_ready()) {
216             this.xynt_streaming.reload();
217         }
218     }
219 }
220
221 //
222 // CLASS transport_xhr
223 //
224 function transport_xhr(doc, xynt_streaming, page)
225 {
226     this.name = "XHR";
227     this.doc = doc;
228     this.xynt_streaming = xynt_streaming;
229     this.xhr = createXMLHttpRequest();
230     this.xhr.open('GET', page);
231
232     var self = this;
233     this.xhr.onreadystatechange = function () { self.xhr_cb(); };
234     this.xhr.send(null);
235
236     this.stopped = false;
237 }
238
239 transport_xhr.prototype = {
240     doc: null,
241     name: null,
242     xynt_streaming: "ready",
243     xhr: null,
244     stopped: true,
245
246     ctx_old: "",
247     ctx_old_len: 0,
248     ctx_new: null,
249
250     // script_clean: 0,
251
252     destroy: function () { /* public */
253         if (this.xhr != null) {
254             this.xhr_abort();
255         }
256         delete this.xhr;
257     },
258
259     xhr_cb: function () {
260         var ret;
261
262         if (this.xhr.readyState == 4) {
263             // console.log("SS: "+safestatus(xhr));
264
265             // NOTE: delay management later
266             // try {
267             //     if ((ret = safestatus(this.xhr)) == 200) {
268             //         this.delay = 0;
269             //         // console.log("del a null "+this.delayed);
270             //     } else if (ret != -1) {
271             //         this.delay = 5000;
272             //         this.hbit('X');
273             //         // alert('There was a problem with the request.' + ret);
274             //     }
275             // } catch(b) {};
276
277             // this.delayed = null;
278             this.stopped = true;
279         }
280     },
281
282     xhr_abort: function() {
283         if (this.xhr != null) {
284             this.xhr.abort();
285         }
286     },
287
288     xstr_is_init: function () { /* public */
289         try {
290             if (this.xhr.responseText != null) {
291                 this.ctx_new = this.xhr.responseText;
292             }
293         }
294         catch (e) {
295         }
296
297         return (this.ctx_new != null);
298     },
299
300     /* only after a successfull is_initialized call */
301     xstr_is_ready: function () { /* public */
302         return (this.xynt_streaming == "ready");
303     },
304
305     xstr_set: function () { /* public */
306         // already set
307     },
308
309     ctx_new_is_set: function () { /* public */
310         return (this.ctx_new != null);
311     },
312
313     ctx_new_curlen_get: function () { /* public */
314         return (this.ctx_new.length);
315     },
316
317     ctx_new_getchar: function(idx) { /* public */
318         return (this.ctx_new[idx]);
319     },
320
321     ctx_old_len_is_set: function () { /* public */
322         return (true);
323     },
324
325     ctx_old_len_get: function () { /* public */
326         return (this.ctx_old_len);
327     },
328
329     ctx_old_len_set: function (len) { /* public */
330         this.ctx_old_len = len;
331     },
332
333     ctx_old_len_add: function (len) { /* public */
334         this.ctx_old_len += len;
335     },
336
337     new_part: function () { /* public */
338         return (this.ctx_new.substr(this.ctx_old_len));
339     },
340
341     scrcls_set: function (step) { /* public */
342         // this.script_clean = step;
343     },
344
345     postproc: function () {
346         if (this.stopped && !this.xstr_is_ready()) {
347             this.xynt_streaming.reload();
348         }
349     }
350 }
351
352 //
353 // CLASS transport_htmlfile
354 //
355 function transport_htmlfile(doc, xynt_streaming, page)
356 {
357     this.name = "HTMLFile";
358     this.doc = doc;
359     this.xynt_streaming = xynt_streaming;
360     this.transfdoc = new ActiveXObject("htmlfile");
361     this.transfdoc.open();
362     this.transfdoc.write("<html><body><iframe id='iframe'></iframe></body></html>");
363     this.transfdoc.close();
364
365     this.ifra = this.transfdoc.getElementById("iframe");
366     this.ifra.contentWindow.location.href = page;
367     this.stopped = false;
368 }
369
370 transport_htmlfile.prototype = {
371     doc: null,
372     name: null,
373     xynt_streaming: null,
374     stopped: true,
375     ifra: null,
376     tradoc: null,
377
378     destroy: function () { /* public */
379         if (this.ifra != null) {
380         //     this.doc.body.removeChild(this.ifra);
381         //     delete this.ifra;
382              this.ifra = null;
383         }
384
385         if (this.transfdoc) {
386             delete this.transfdoc;
387             this.transfdoc = null;
388         }
389     },
390
391     xstr_is_init: function () { /* public */
392         return (typeof(this.ifra.contentWindow.xynt_streaming) != 'undefined');
393     },
394
395     /* only after a successfull is_initialized call */
396     xstr_is_ready: function () { /* public */
397         return (this.ifra.contentWindow.xynt_streaming == "ready");
398     },
399
400     /* only after a successfull is_initialized call */
401     xstr_set: function () { /* public */
402         if (this.ifra.contentWindow.xynt_streaming == "ready") {
403             this.ifra.contentWindow.xynt_streaming = this.xynt_streaming;
404             return (true);
405         }
406         else if (this.ifra.contentWindow.xynt_streaming == this.xynt_streaming) {
407             return (true);
408         }
409         else {
410             return (false);
411         }
412     },
413
414     ctx_new_is_set: function () { /* public */
415         return (typeof(this.ifra.contentWindow.ctx_new) != 'undefined');
416     },
417
418     ctx_new_curlen_get: function () { /* public */
419         return (this.ifra.contentWindow.ctx_new.length);
420     },
421
422     ctx_new_getchar: function(idx) { /* public */
423         return (this.ifra.contentWindow.ctx_new.charAt(idx));
424     },
425
426     ctx_old_len_is_set: function () { /* public */
427         return (typeof(this.ifra.contentWindow.ctx_old_len) != 'undefined');
428     },
429
430     ctx_old_len_get: function () { /* public */
431         return (this.ifra.contentWindow.ctx_old_len);
432     },
433
434     ctx_old_len_set: function (len) { /* public */
435         this.ifra.contentWindow.ctx_old_len = len;
436     },
437
438     ctx_old_len_add: function (len) { /* public */
439         this.ifra.contentWindow.ctx_old_len += len;
440     },
441
442     new_part: function () { /* public */
443         return (this.ifra.contentWindow.ctx_new.substr(this.ifra.contentWindow.ctx_old_len));
444     },
445
446     scrcls_set: function (step) { /* public */
447         this.ifra.contentWindow.script_clean = step;
448     },
449
450     postproc: function () { /* public */
451         if (this.stopped && !this.xstr_is_ready()) {
452             this.xynt_streaming.reload();
453         }
454     }
455 }
456
457 //
458 // CLASS transport_iframe
459 //
460 function transport_iframe(doc, xynt_streaming, page)
461 {
462     this.name = "IFRAME";
463     this.doc = doc;
464     this.xynt_streaming = xynt_streaming;
465     this.ifra = doc.createElement("iframe");
466     this.ifra.style.visibility = "hidden";
467     doc.body.appendChild(this.ifra);
468     this.ifra.contentWindow.location.href = page;
469     this.stopped = false;
470 }
471
472 transport_iframe.prototype = {
473     doc: null,
474     name: null,
475     xynt_streaming: null,
476     stopped: true,
477     ifra: null,
478
479     destroy: function () { /* public */
480         try {
481             if (this.ifra != null) {
482                 // NOTE:  on Opera this remove child crash js if called from
483                 //        inside of the iframe, on IE on Windows without
484                 //        it stream abort fails.
485                 //        the problem is fixed setting into the iframe's onload
486                 //        function the stopped attribute to true and delegate
487                 //        postproc() fired by xynt_streaming watchdog()
488                 this.doc.body.removeChild(this.ifra);
489                 delete this.ifra;
490                 this.ifra = null;
491             }
492         } catch (b) {
493             alert("destroy exception catched");
494         }
495     },
496
497     xstr_is_init: function () { /* public */
498         return (typeof(this.ifra.contentWindow.xynt_streaming) != 'undefined');
499     },
500
501     /* only after a successfull is_initialized call */
502     xstr_is_ready: function () { /* public */
503         return (this.ifra.contentWindow.xynt_streaming == "ready");
504     },
505
506     /* only after a successfull is_initialized call */
507     xstr_set: function () { /* public */
508         if (this.ifra.contentWindow.xynt_streaming == "ready") {
509             this.ifra.contentWindow.xynt_streaming = this.xynt_streaming;
510             return (true);
511         }
512         else if (this.ifra.contentWindow.xynt_streaming == this.xynt_streaming) {
513             return (true);
514         }
515         else {
516             return (false);
517         }
518     },
519
520
521     /* only after a successfull is_ready call to be sure the accessibility of the var */
522     xstr_set_old: function (xynt_streaming) { /* public */
523         this.ifra.contentWindow.xynt_streaming = xynt_streaming;
524     },
525
526     ctx_new_is_set: function () { /* public */
527         return (typeof(this.ifra.contentWindow.ctx_new) != 'undefined');
528     },
529
530     ctx_new_curlen_get: function () { /* public */
531         return (this.ifra.contentWindow.ctx_new.length);
532     },
533
534     ctx_new_getchar: function(idx) { /* public */
535         return (this.ifra.contentWindow.ctx_new.charAt(idx));
536     },
537
538     ctx_old_len_is_set: function () { /* public */
539         return (typeof(this.ifra.contentWindow.ctx_old_len) != 'undefined');
540     },
541
542     ctx_old_len_get: function () { /* public */
543         return (this.ifra.contentWindow.ctx_old_len);
544     },
545
546     ctx_old_len_set: function (len) { /* public */
547         this.ifra.contentWindow.ctx_old_len = len;
548     },
549
550     ctx_old_len_add: function (len) { /* public */
551         this.ifra.contentWindow.ctx_old_len += len;
552     },
553
554     new_part: function () { /* public */
555         return (this.ifra.contentWindow.ctx_new.substr(this.ifra.contentWindow.ctx_old_len));
556     },
557
558     scrcls_set: function (step) { /* public */
559         this.ifra.contentWindow.script_clean = step;
560     },
561
562     postproc: function () { /* public */
563         if (this.stopped && !this.xstr_is_ready()) {
564             this.xynt_streaming.reload();
565         }
566     }
567 }
568
569 function xynt_streaming(win, transp_type, transp_port, transp_fback, console, gst, from, cookiename, sess, sandbox, page, page_id, cmdproc)
570 {
571     this.win = win;
572     this.transp_type = transp_type;
573     this.transp_port = transp_port;
574     this.transp_fback = transp_fback;
575     this.console = console;
576     this.gst = gst;
577     this.from = from;
578     this.cookiename = cookiename;
579     this.sess = sess;
580     this.sandbox = sandbox;
581     this.page = page;
582     this.page_id = page_id;
583     this.cmdproc = cmdproc;
584     // this.cmdproc = function(com){/* console.log("COM: "+com); */ eval(com);}
585     this.doc = win.document;
586     this.keepalive_old = -1;
587     this.keepalive_new = -1;
588     this.out_queue = [];
589
590     this.mon_errtime = this.keepalives_eq_max * this.watchdog_checktm * this.watchdog_timeout;
591     this.mon_wrntime = this.mon_errtime / 2;
592
593     this.mon_update();
594 }
595
596 xynt_streaming.prototype = {
597     win:               null,
598     transp_type:       null,
599     transp_port:         80,
600     transp_type_cur:   null,
601     transp_port_cur:     80,
602     transp_fback:         0,
603     transp:            null,
604     console:           null,
605     gst:               null,
606     from:              null,
607     cookiename:        null,
608     sess:              null,
609     sandbox:           null,
610     page:              null,
611     page_id:           null,
612     cmdproc:           null,
613
614     start_time:        0,
615     restart_wait:      5000, // wait restart_wait millisec before begin to check if restart is needed
616
617     doc:               null,
618     cookiepath: "/brisk/",
619     watchdog_hdl:      null,
620     hbit:              function () {},
621     keepalive_old:    -1,
622     keepalive_new:    -1,
623     keepalives_equal:  0,
624     /* NOTE: right watch_timeout value to 100, for devel reasons use 1000 or more */
625     /* restart after  4 * 40 * 100 millisec if server ping is missing => 16secs */
626     keepalives_eq_max: 4,
627     watchdog_checktm:  40,
628     watchdog_timeout:  100,
629     watchdog_ct:       0,
630     watchable:         false,
631     restart_n:         0,
632     comm_match:        /_*@BEGIN@(.*?)@END@/g,
633     comm_clean:        /_*@BEGIN@(.*?)@END@/,
634     stream:            "",
635     out_queue:         null,
636     the_end:           false,
637
638     mon_time:         -1,
639     mon_wrntime:       0,
640     mon_errtime:       0,
641
642     mon_stat_old:      "",
643
644     mon_update: function()
645     {
646         var date = new Date();
647
648         this.mon_time = date.getTime();
649     },
650
651     /*
652       ping arrives at least every RD_KEEPALIVE_TOUT secs (currently 4 secs)
653
654       return values: 0 unknown
655                      1 ok
656                      2 warning
657                      3 error
658      */
659     mon_status: function()
660     {
661         var delta, date;
662
663         var date = new Date();
664
665         delta = date.getTime() - this.mon_time;
666
667         if (delta < this.mon_wrntime)
668             return 1;
669         else if (delta < this.mon_errtime)
670             return 2;
671         else
672             return 3;
673     },
674
675     start: function() { /* public */
676         var transp_type;
677         var page;
678
679         // this.log("start "+this.transp_type+" "+this.transp_fback);
680         if (this.the_end)
681             return;
682
683         createCookie(this.cookiename, sess, 24*365, this.cookiepath);
684         // alert("start");
685         this.log("xynt_streaming:start restart: "+this.restart_n);
686         this.keepalives_equal = 0;
687
688         // page arrangement
689         this.page = url_complete(this.win.location.href, this.page);
690
691         // DEFAULT TRANSPORT PROTOCOL HERE websocketsec, websocket
692         if (this.transp_fback > 0) {
693             if (location.protocol == 'https:') {
694                 transp_type = "websocketsec";
695                 transp_port = 443;
696             }
697             else {
698                 transp_type = "websocket";
699                 transp_port = (this.transp_fback == 2 ? 80 : 8080);
700             }
701
702         }
703         else {
704             transp_type = this.transp_type;
705             transp_port = this.transp_port;
706         }
707
708         this.transp_type_cur = transp_type;
709         this.transp_port_cur = transp_port;
710
711         if (transp_type == "websocket" || transp_type == "websocketsec") {
712             var end_proto, first_slash, newpage;
713
714             // change protocol
715             this.log("precha ["+this.page+"]");
716             if (transp_type == "websocketsec") {
717                 newpage = this.page.replace(/\.php$/g, "_wss.php").replace(/\.php\?/g, "_wss.php?");
718                 }
719             else {
720                 newpage = this.page;
721                 }
722             end_proto = newpage.indexOf("://");
723             first_slash = newpage.substring(end_proto+3).indexOf("/");
724
725             page = (transp_type == "websocketsec" ? "wss://" : "ws://")
726                 + newpage.substring(end_proto+3, end_proto+3 + first_slash) + ":"
727                 + transp_port + newpage.substring(end_proto+3 + first_slash);
728             // this.log("MOP WS: " + page);
729         }
730         else {
731             page = this.page;
732         }
733         // stat, subst, this.gst.st
734
735         page = url_append_args(page, "sess", this.sess, "page_id", this.page_id, "stat", stat, "subst", subst, "step", this.gst.st, "from", this.from);
736         // this.log("the page:");
737         // this.log(page);
738
739         try {
740             // transport instantiation
741             if (transp_type == "websocketsec") {
742                 page = url_append_args(page, "transp", "websocketsec");
743                 this.transp = new transport_ws(this.doc, this, page, true);
744             }
745             else if (transp_type == "websocket") {
746                 page = url_append_args(page, "transp", "websocket");
747                 this.transp = new transport_ws(this.doc, this, page);
748             }
749             else if (transp_type == "xhr") {
750                 page = url_append_args(page, "transp", "xhr");
751                 this.transp = new transport_xhr(this.doc, this, page);
752             }
753             else if (transp_type == "iframe") {
754                 page = url_append_args(page, "transp", "iframe");
755                 this.transp = new transport_iframe(this.doc, this, page);
756             }
757             else if (transp_type == "htmlfile") {
758                 page = url_append_args(page, "transp", "htmlfile");
759                 this.transp = new transport_htmlfile(this.doc, this, page);
760             }
761             else
762                 return;
763         }
764         catch (err) {
765             if (this.transp_fback > 0) {
766                 this.transp_fback--;
767                 this.start();
768                 return;
769             }
770         }
771
772         // watchdog setting
773         this.watchdog_ct  = 0;
774         if (!this.the_end) {
775             this.watchdog_hdl = setTimeout(function(obj) { obj.log("tout1"); obj.watchdog(); }, this.watchdog_timeout, this);
776         }
777
778         var date = new Date();
779         this.start_time = date.getTime();
780     },
781
782     stop: function() {
783         this.the_end = true;
784         this.abort();
785     },
786
787     hbit_set: function (hbit) {
788         this.hbit = hbit;
789     },
790
791
792     hbit_status: function () {
793         var ret;
794
795         ret = this.mon_status();
796         // console.log("mon_status: "+ret+" 0: "+this.mon_time);
797         switch (ret) {
798         case 0:
799             mon_stat = "b";
800             break;
801         case 1:
802             mon_stat = "g";
803             break;
804         case 2:
805             mon_stat = "y";
806             break;
807         case 3:
808             mon_stat = "r";
809             break;
810         }
811
812         if (this.mon_stat_old != mon_stat) {
813             this.hbit(mon_stat);
814             this.mon_stat_old = mon_stat;
815         }
816     },
817
818
819     watchdog: function () {
820         // alert("watchdog");
821         var i, again;
822         var comm_newpart, comm_len, comm_arr;
823         var ctx_new_len;
824
825         if (this.sandbox != null) {
826             var zug = "WATCHDOG  sess = ["+this.sess+"]  step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new+"Transport: "+this.transp.name;
827             if (zug != this.sandbox.innerHTML)
828                 this.sandbox.innerHTML = zug;
829         }
830
831         // WATCHDOGING THE CONNECTION
832         this.log("hs::watchdog: start, cur equal times: "+this.keepalives_equal);
833         if (!this.watchable) {
834             do {
835                 try{
836                     // if (typeof(this.ifra.contentWindow.xynt_streaming) == 'undefined')
837                     if (!this.transp.xstr_is_init()) {
838                         this.log("hs::watchdog: xstr_is_init = false");
839                         break;
840                     }
841                 }
842                 catch(b) {
843                     this.log("hs::watchdog: exception");
844                     break;
845                 }
846
847                 /*
848                   on IE7 the the window frame scope is cleaned after the href is set, so we wait
849                   for a well know variable value before assign this object value to it (OO is a passion)
850                 */
851                 // if (this.ifra.contentWindow.xynt_streaming == "ready") {
852                 if (this.transp.xstr_set()) {
853                     // this.ifra.contentWindow.xynt_streaming = this;
854                     this.watchable = true;
855                     this.watchdog_ct = 0;
856                     this.log("hs::watchdog: watchable = yes");
857                 }
858             } while (false);
859         }
860         if ( (this.watchdog_ct % this.watchdog_checktm) == 0) {
861             this.log("hs::watchdog: this.keepalive_old: "+this.keepalive_old+" this.keepalive_new: "+this.keepalive_new);
862             if (this.keepalive_old == this.keepalive_new) {
863                 this.keepalives_equal++;
864             }
865             else {
866                 this.keepalive_old = this.keepalive_new;
867                 this.keepalives_equal = 0;
868             }
869
870             if (this.keepalives_equal >= this.keepalives_eq_max) {
871                 this.log("hs::watchdog: MAX ACHIEVED "+this.keepalives_equal);
872                 this.reload();
873                 // alert("watchdog return reload");
874                 this.hbit_status();
875                 return;
876             }
877         }
878
879         // PICK COMMANDS FROM STREAM
880         do {
881             // alert("do--while begin ["+again+"]");
882             // CHECK: maybe again here isn't needed
883             again = 0;
884             try {
885                 /* if (typeof(this.ifra.contentWindow.ctx_new)     == 'undefined' ||
886                    typeof(this.ifra.contentWindow.ctx_old_len) == 'undefined') */
887                 if (!this.transp.ctx_new_is_set() || !this.transp.ctx_old_len_is_set())
888                     break;
889             }
890             catch(b) {
891                 break;
892             }
893
894             // ctx_new_len = this.ifra.contentWindow.ctx_new.length;
895             ctx_new_len = this.transp.ctx_new_curlen_get();
896             // if (ctx_new_len <= this.ifra.contentWindow.ctx_old_len) {
897             if (ctx_new_len <= this.transp.ctx_old_len_get()) {
898                 break;
899             }
900             this.log("new: "+ ctx_new_len + "  old: "+this.transp.ctx_old_len_get());
901             this.keepalive_new++;
902             // alert("pre-loop 1");
903             for (i = this.transp.ctx_old_len_get() ; i < ctx_new_len ; i++) {
904                 // if (this.ifra.contentWindow.ctx_new.charAt(i) != '_') {
905                 if (this.transp.ctx_new_getchar(i) != '_') {
906                     // this.log("ctx_new.char(i) != '_' ["+this.ifra.contentWindow.ctx_new.charAt(i)+"]");
907                     break;
908                 }
909                 this.mon_update();
910                 this.hbit_status();
911
912                 // else {
913                 //     this.log("ctx_new.charAt(i) == '_'");
914                 // }
915             }
916             // this.ifra.contentWindow.ctx_old_len = i;
917             this.transp.ctx_old_len_set(i);
918             if (i == ctx_new_len) {
919                 this.log("old_len == i");
920                 break;
921             }
922             else {
923                 this.log("old_len != i: "+i);
924             }
925             // alert("do--while middle ["+this.ifra.contentWindow.ctx_old_len+"]");
926
927             comm_newpart = this.transp.new_part();
928             this.log("COM_NEWPART: ["+comm_newpart+"]");
929             comm_len = 0;
930             comm_arr = comm_newpart.match(this.comm_match);
931
932             // alert("do--while middle2 ["+again+"]");
933             if (comm_arr) {
934                 var comm_arr_len = comm_arr.length;
935                 for (i = 0 ; i < comm_arr_len ; i++) {
936                     var temp = comm_arr[i].replace(this.comm_clean,"$1").split("|");
937                     this.gst.comms = this.gst.comms.concat(temp);
938                     comm_len += comm_arr[i].length;
939                 }
940                 again = 1;
941                 this.mon_update();
942                 this.hbit_status();
943             }
944             // this.ifra.contentWindow.ctx_old_len += comm_len;
945             this.transp.ctx_old_len_add(comm_len);
946             // this.ifra.contentWindow.script_clean = this.gst.st;
947             this.transp.scrcls_set(this.gst.st);
948             // alert("do--while end ["+again+"]");
949         } while (again);
950
951         // alert("post while");
952         // EXECUTION OF STREAM COMMANDS
953         do {
954             again = 0;
955             //MOP ?? xhrrestart = 0;
956             if (this.gst.st_loc < this.gst.st_loc_new) {
957                 // there is some slow actions running
958                 break;
959             }
960             else if (this.gst.comms.length > 0) {
961                 var singlecomm;
962
963                 singlecomm = this.gst.comms.shift();
964                 // alert("EXE"+gugu);
965                 // $("xhrdeltalog").innerHTML = "EVALL: "+singlecomm.replace("<", "&lt;", "g"); +"<br>";
966                 //xx this.hbit("+");
967
968                 // alert("SINGLE: ["+singlecomm+"]");
969                 // window.console.log("["+singlecomm+"]");
970                 this.cmdproc(singlecomm);
971                 if (this.transp_type_cur) {
972                     this.transp_type = this.transp_type_cur;
973                     this.transp_port = this.transp_port_cur;
974                 }
975                 again = 1;
976             }
977         } while (again);
978         this.watchdog_ct++;
979         if (!this.the_end) {
980             var date = new Date();
981             if (date.getTime() > (this.start_time + this.restart_wait)) {
982                 this.transp.postproc();
983             }
984             this.watchdog_hdl = setTimeout(function(obj) { /* obj.log("tout2"); */ obj.watchdog(); }, this.watchdog_timeout, this);
985             this.hbit_status();
986         }
987         // alert("watchdog return normal");
988
989         return;
990     },
991
992     send: function(msg) {
993         if (typeof(this.transp.send) == 'undefined') {
994             this.log('send not implemented for ' + this.transp_type);
995             return;
996         }
997
998         return this.transp.send(msg);
999     },
1000
1001     //
1002     // moved to xynt-streaming-ifra as push()
1003     //
1004     // keepalive: function (s) {
1005     //     this.log("hs::keepalive");
1006     //     if (s != null) {
1007     //         this.log(s);
1008     //         this.ifra.contentWindow.ctx_new += "@BEGIN@"+s+"@END@";
1009     //     }
1010     //     else {
1011     //         this.ifra.contentWindow.ctx_new += "_";
1012     //     }
1013     //     // this.keepalive_new++;
1014     // },
1015
1016     abort: function () { /* public */
1017         // this.log("PATH: "+this.ifra.contentWindow.location.protocol + "://" + this.ifra.contentWindow.location.host + "/" + this.ifra.contentWindow.location.pathname);
1018
1019         this.gst.abort();
1020         if (this.watchdog_hdl != null) {
1021             clearTimeout(this.watchdog_hdl);
1022             this.watchdog_hdl = null;
1023         }
1024
1025         this.restart_n++;
1026         this.log("hs::reload");
1027         this.watchable = false;
1028         if (this.transp != null) {
1029             this.transp.destroy();
1030             delete this.transp;
1031             this.transp = null;
1032         }
1033     },
1034
1035     reload: function () {
1036         this.abort();
1037         this.start(null);
1038     },
1039
1040     log: function (s) {
1041         if (this.console != null) {
1042             return (this.console.log(s));
1043         }
1044     }
1045 }