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