fix wrong out_queue placement
[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, 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.cmdproc = cmdproc;
583     // this.cmdproc = function(com){/* console.log("COM: "+com); */ eval(com);}
584     this.doc = win.document;
585     this.keepalive_old = -1;
586     this.keepalive_new = -1;
587     this.out_queue = [];
588
589     this.mon_errtime = this.keepalives_eq_max * this.watchdog_checktm * this.watchdog_timeout;
590     this.mon_wrntime = this.mon_errtime / 2;
591
592     this.mon_update();
593 }
594
595 xynt_streaming.prototype = {
596     win:               null,
597     transp_type:       null,
598     transp_port:         80,
599     transp_type_cur:   null,
600     transp_port_cur:     80,
601     transp_fback:         0,
602     transp:            null,
603     console:           null,
604     gst:               null,
605     from:              null,
606     cookiename:        null,
607     sess:              null,
608     sandbox:           null,
609     page:              null,
610     cmdproc:           null,
611
612     start_time:        0,
613     restart_wait:      5000, // wait restart_wait millisec before begin to check if restart is needed
614
615     doc:               null,
616     cookiepath: "/brisk/",
617     watchdog_hdl:      null,
618     hbit:              function () {},
619     keepalive_old:    -1,
620     keepalive_new:    -1,
621     keepalives_equal:  0,
622     /* NOTE: right watch_timeout value to 100, for devel reasons use 1000 or more */
623     /* restart after  4 * 40 * 100 millisec if server ping is missing => 16secs */
624     keepalives_eq_max: 4,
625     watchdog_checktm:  40,
626     watchdog_timeout:  100,
627     watchdog_ct:       0,
628     watchable:         false,
629     restart_n:         0,
630     comm_match:        /_*@BEGIN@(.*?)@END@/g,
631     comm_clean:        /_*@BEGIN@(.*?)@END@/,
632     stream:            "",
633     out_queue:         null,
634     the_end:           false,
635
636     mon_time:         -1,
637     mon_wrntime:       0,
638     mon_errtime:       0,
639
640     mon_stat_old:      "",
641
642     mon_update: function()
643     {
644         var date = new Date();
645
646         this.mon_time = date.getTime();
647     },
648
649     /*
650       ping arrives at least every RD_KEEPALIVE_TOUT secs (currently 4 secs)
651
652       return values: 0 unknown
653                      1 ok
654                      2 warning
655                      3 error
656      */
657     mon_status: function()
658     {
659         var delta, date;
660
661         var date = new Date();
662
663         delta = date.getTime() - this.mon_time;
664
665         if (delta < this.mon_wrntime)
666             return 1;
667         else if (delta < this.mon_errtime)
668             return 2;
669         else
670             return 3;
671     },
672
673     start: function() { /* public */
674         var transp_type;
675         var page;
676
677         // this.log("start "+this.transp_type+" "+this.transp_fback);
678         if (this.the_end)
679             return;
680
681         createCookie(this.cookiename, sess, 24*365, this.cookiepath);
682         // alert("start");
683         this.log("xynt_streaming:start restart: "+this.restart_n);
684         this.keepalives_equal = 0;
685
686         // page arrangement
687         this.page = url_complete(this.win.location.href, this.page);
688
689         // DEFAULT TRANSPORT PROTOCOL HERE websocketsec, websocket
690         if (this.transp_fback > 0) {
691             if (location.protocol == 'https:') {
692                 transp_type = "websocketsec";
693                 transp_port = 443;
694             }
695             else {
696                 transp_type = "websocket";
697                 transp_port = (this.transp_fback == 2 ? 80 : 8080);
698             }
699
700         }
701         else {
702             transp_type = this.transp_type;
703             transp_port = this.transp_port;
704         }
705
706         this.transp_type_cur = transp_type;
707         this.transp_port_cur = transp_port;
708
709         if (transp_type == "websocket" || transp_type == "websocketsec") {
710             var end_proto, first_slash, newpage;
711
712             // change protocol
713             this.log("precha ["+this.page+"]");
714             if (transp_type == "websocketsec") {
715                 newpage = this.page.replace(/\.php$/g, "_wss.php").replace(/\.php\?/g, "_wss.php?");
716                 }
717             else {
718                 newpage = this.page;
719                 }
720             end_proto = newpage.indexOf("://");
721             first_slash = newpage.substring(end_proto+3).indexOf("/");
722
723             page = (transp_type == "websocketsec" ? "wss://" : "ws://")
724                 + newpage.substring(end_proto+3, end_proto+3 + first_slash) + ":"
725                 + transp_port + newpage.substring(end_proto+3 + first_slash);
726             // this.log("MOP WS: " + page);
727         }
728         else {
729             page = this.page;
730         }
731         // stat, subst, this.gst.st
732
733         page = url_append_args(page, "sess", this.sess, "stat", stat, "subst", subst, "step", this.gst.st, "from", this.from);
734         // this.log("the page:");
735         // this.log(page);
736
737         try {
738             // transport instantiation
739             if (transp_type == "websocketsec") {
740                 page = url_append_args(page, "transp", "websocketsec");
741                 this.transp = new transport_ws(this.doc, this, page, true);
742             }
743             else if (transp_type == "websocket") {
744                 page = url_append_args(page, "transp", "websocket");
745                 this.transp = new transport_ws(this.doc, this, page);
746             }
747             else if (transp_type == "xhr") {
748                 page = url_append_args(page, "transp", "xhr");
749                 this.transp = new transport_xhr(this.doc, this, page);
750             }
751             else if (transp_type == "iframe") {
752                 page = url_append_args(page, "transp", "iframe");
753                 this.transp = new transport_iframe(this.doc, this, page);
754             }
755             else if (transp_type == "htmlfile") {
756                 page = url_append_args(page, "transp", "htmlfile");
757                 this.transp = new transport_htmlfile(this.doc, this, page);
758             }
759             else
760                 return;
761         }
762         catch (err) {
763             if (this.transp_fback > 0) {
764                 this.transp_fback--;
765                 this.start();
766                 return;
767             }
768         }
769
770         // watchdog setting
771         this.watchdog_ct  = 0;
772         if (!this.the_end) {
773             this.watchdog_hdl = setTimeout(function(obj) { obj.log("tout1"); obj.watchdog(); }, this.watchdog_timeout, this);
774         }
775
776         var date = new Date();
777         this.start_time = date.getTime();
778     },
779
780     stop: function() {
781         this.the_end = true;
782         this.abort();
783     },
784
785     hbit_set: function (hbit) {
786         this.hbit = hbit;
787     },
788
789
790     hbit_status: function () {
791         var ret;
792
793         ret = this.mon_status();
794         // console.log("mon_status: "+ret+" 0: "+this.mon_time);
795         switch (ret) {
796         case 0:
797             mon_stat = "b";
798             break;
799         case 1:
800             mon_stat = "g";
801             break;
802         case 2:
803             mon_stat = "y";
804             break;
805         case 3:
806             mon_stat = "r";
807             break;
808         }
809
810         if (this.mon_stat_old != mon_stat) {
811             this.hbit(mon_stat);
812             this.mon_stat_old = mon_stat;
813         }
814     },
815
816
817     watchdog: function () {
818         // alert("watchdog");
819         var i, again;
820         var comm_newpart, comm_len, comm_arr;
821         var ctx_new_len;
822
823         if (this.sandbox != null) {
824             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;
825             if (zug != this.sandbox.innerHTML)
826                 this.sandbox.innerHTML = zug;
827         }
828
829         // WATCHDOGING THE CONNECTION
830         this.log("hs::watchdog: start, cur equal times: "+this.keepalives_equal);
831         if (!this.watchable) {
832             do {
833                 try{
834                     // if (typeof(this.ifra.contentWindow.xynt_streaming) == 'undefined')
835                     if (!this.transp.xstr_is_init()) {
836                         this.log("hs::watchdog: xstr_is_init = false");
837                         break;
838                     }
839                 }
840                 catch(b) {
841                     this.log("hs::watchdog: exception");
842                     break;
843                 }
844
845                 /*
846                   on IE7 the the window frame scope is cleaned after the href is set, so we wait
847                   for a well know variable value before assign this object value to it (OO is a passion)
848                 */
849                 // if (this.ifra.contentWindow.xynt_streaming == "ready") {
850                 if (this.transp.xstr_set()) {
851                     // this.ifra.contentWindow.xynt_streaming = this;
852                     this.watchable = true;
853                     this.watchdog_ct = 0;
854                     this.log("hs::watchdog: watchable = yes");
855                 }
856             } while (false);
857         }
858         if ( (this.watchdog_ct % this.watchdog_checktm) == 0) {
859             this.log("hs::watchdog: this.keepalive_old: "+this.keepalive_old+" this.keepalive_new: "+this.keepalive_new);
860             if (this.keepalive_old == this.keepalive_new) {
861                 this.keepalives_equal++;
862             }
863             else {
864                 this.keepalive_old = this.keepalive_new;
865                 this.keepalives_equal = 0;
866             }
867
868             if (this.keepalives_equal >= this.keepalives_eq_max) {
869                 this.log("hs::watchdog: MAX ACHIEVED "+this.keepalives_equal);
870                 this.reload();
871                 // alert("watchdog return reload");
872                 this.hbit_status();
873                 return;
874             }
875         }
876
877         // PICK COMMANDS FROM STREAM
878         do {
879             // alert("do--while begin ["+again+"]");
880             // CHECK: maybe again here isn't needed
881             again = 0;
882             try {
883                 /* if (typeof(this.ifra.contentWindow.ctx_new)     == 'undefined' ||
884                    typeof(this.ifra.contentWindow.ctx_old_len) == 'undefined') */
885                 if (!this.transp.ctx_new_is_set() || !this.transp.ctx_old_len_is_set())
886                     break;
887             }
888             catch(b) {
889                 break;
890             }
891
892             // ctx_new_len = this.ifra.contentWindow.ctx_new.length;
893             ctx_new_len = this.transp.ctx_new_curlen_get();
894             // if (ctx_new_len <= this.ifra.contentWindow.ctx_old_len) {
895             if (ctx_new_len <= this.transp.ctx_old_len_get()) {
896                 break;
897             }
898             this.log("new: "+ ctx_new_len + "  old: "+this.transp.ctx_old_len_get());
899             this.keepalive_new++;
900             // alert("pre-loop 1");
901             for (i = this.transp.ctx_old_len_get() ; i < ctx_new_len ; i++) {
902                 // if (this.ifra.contentWindow.ctx_new.charAt(i) != '_') {
903                 if (this.transp.ctx_new_getchar(i) != '_') {
904                     // this.log("ctx_new.char(i) != '_' ["+this.ifra.contentWindow.ctx_new.charAt(i)+"]");
905                     break;
906                 }
907                 this.mon_update();
908                 this.hbit_status();
909
910                 // else {
911                 //     this.log("ctx_new.charAt(i) == '_'");
912                 // }
913             }
914             // this.ifra.contentWindow.ctx_old_len = i;
915             this.transp.ctx_old_len_set(i);
916             if (i == ctx_new_len) {
917                 this.log("old_len == i");
918                 break;
919             }
920             else {
921                 this.log("old_len != i: "+i);
922             }
923             // alert("do--while middle ["+this.ifra.contentWindow.ctx_old_len+"]");
924
925             comm_newpart = this.transp.new_part();
926             this.log("COM_NEWPART: ["+comm_newpart+"]");
927             comm_len = 0;
928             comm_arr = comm_newpart.match(this.comm_match);
929
930             // alert("do--while middle2 ["+again+"]");
931             if (comm_arr) {
932                 var comm_arr_len = comm_arr.length;
933                 for (i = 0 ; i < comm_arr_len ; i++) {
934                     var temp = comm_arr[i].replace(this.comm_clean,"$1").split("|");
935                     this.gst.comms = this.gst.comms.concat(temp);
936                     comm_len += comm_arr[i].length;
937                 }
938                 again = 1;
939                 this.mon_update();
940                 this.hbit_status();
941             }
942             // this.ifra.contentWindow.ctx_old_len += comm_len;
943             this.transp.ctx_old_len_add(comm_len);
944             // this.ifra.contentWindow.script_clean = this.gst.st;
945             this.transp.scrcls_set(this.gst.st);
946             // alert("do--while end ["+again+"]");
947         } while (again);
948
949         // alert("post while");
950         // EXECUTION OF STREAM COMMANDS
951         do {
952             again = 0;
953             //MOP ?? xhrrestart = 0;
954             if (this.gst.st_loc < this.gst.st_loc_new) {
955                 // there is some slow actions running
956                 break;
957             }
958             else if (this.gst.comms.length > 0) {
959                 var singlecomm;
960
961                 singlecomm = this.gst.comms.shift();
962                 // alert("EXE"+gugu);
963                 // $("xhrdeltalog").innerHTML = "EVALL: "+singlecomm.replace("<", "&lt;", "g"); +"<br>";
964                 //xx this.hbit("+");
965
966                 // alert("SINGLE: ["+singlecomm+"]");
967                 // window.console.log("["+singlecomm+"]");
968                 this.cmdproc(singlecomm);
969                 if (this.transp_type_cur) {
970                     this.transp_type = this.transp_type_cur;
971                     this.transp_port = this.transp_port_cur;
972                 }
973                 again = 1;
974             }
975         } while (again);
976         this.watchdog_ct++;
977         if (!this.the_end) {
978             var date = new Date();
979             if (date.getTime() > (this.start_time + this.restart_wait)) {
980                 this.transp.postproc();
981             }
982             this.watchdog_hdl = setTimeout(function(obj) { /* obj.log("tout2"); */ obj.watchdog(); }, this.watchdog_timeout, this);
983             this.hbit_status();
984         }
985         // alert("watchdog return normal");
986
987         return;
988     },
989
990     send: function(msg) {
991         if (typeof(this.transp.send) == 'undefined') {
992             this.log('send not implemented for ' + this.transp_type);
993             return;
994         }
995
996         return this.transp.send(msg);
997     },
998
999     //
1000     // moved to xynt-streaming-ifra as push()
1001     //
1002     // keepalive: function (s) {
1003     //     this.log("hs::keepalive");
1004     //     if (s != null) {
1005     //         this.log(s);
1006     //         this.ifra.contentWindow.ctx_new += "@BEGIN@"+s+"@END@";
1007     //     }
1008     //     else {
1009     //         this.ifra.contentWindow.ctx_new += "_";
1010     //     }
1011     //     // this.keepalive_new++;
1012     // },
1013
1014     abort: function () { /* public */
1015         // this.log("PATH: "+this.ifra.contentWindow.location.protocol + "://" + this.ifra.contentWindow.location.host + "/" + this.ifra.contentWindow.location.pathname);
1016
1017         this.gst.abort();
1018         if (this.watchdog_hdl != null) {
1019             clearTimeout(this.watchdog_hdl);
1020             this.watchdog_hdl = null;
1021         }
1022
1023         this.restart_n++;
1024         this.log("hs::reload");
1025         this.watchable = false;
1026         if (this.transp != null) {
1027             this.transp.destroy();
1028             delete this.transp;
1029             this.transp = null;
1030         }
1031     },
1032
1033     reload: function () {
1034         this.abort();
1035         this.start(null);
1036     },
1037
1038     log: function (s) {
1039         if (this.console != null) {
1040             return (this.console.log(s));
1041         }
1042     }
1043 }