transport_xhr 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.transp = new transport_xhr(this.doc, this, this.page);
394         }
395         else if (this.transp_type == "iframe") {
396             this.transp = new transport_iframe(this.doc, this, this.page);
397         }
398         else if (this.transp_type == "htmlfile") {
399             this.transp = new transport_htmlfile(this.doc, this, this.page);
400         }
401         else
402             return;
403
404         // watchdog setting
405         this.watchdog_ct  = 0;
406         if (!this.the_end) {
407             this.watchdog_hdl = setTimeout(function(obj) { obj.log("tout1"); obj.watchdog(); }, this.watchdog_timeout, this);
408         }
409     },
410
411     stop: function() {
412         this.the_end = true;
413         this.abort();
414     },
415
416     hbit_set: function (hbit) {
417         this.hbit = hbit;
418     },
419
420     watchdog: function () {
421         // alert("watchdog");
422         var i, again;
423         var comm_newpart, comm_len, comm_arr;
424         var ctx_new_len;
425
426         if (this.sandbox != null) {
427             // 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;
428             var zug = "WATCHDOG  sess = ["+this.sess+"]  step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new;          
429             if (zug != this.sandbox.innerHTML)
430                 this.sandbox.innerHTML = zug;
431         }
432
433         // WATCHDOGING THE CONNECTION
434         this.log("hs::watchdog: start, cur equal times: "+this.keepalives_equal);
435         if (!this.watchable) {
436             do {
437                 try{
438                     // if (typeof(this.ifra.contentWindow.xynt_streaming) == 'undefined')
439                     if (!this.transp.xstr_is_init()) {
440                         this.log("hs::watchdog: xstr_is_init = false");
441                         break;
442                     }
443                 }
444                 catch(b) {
445                     this.log("hs::watchdog: exception");
446                     break;
447                 }
448
449                 /*
450                   on IE7 the the window frame scope is cleaned after the href is set, so we wait 
451                   for a well know variable value before assign this object value to it (OO is a passion)
452                 */
453                 // if (this.ifra.contentWindow.xynt_streaming == "ready") {
454                 if (this.transp.xstr_set()) {
455                     // this.ifra.contentWindow.xynt_streaming = this;
456                     this.watchable = true;
457                     this.watchdog_ct = 0;
458                     this.log("hs::watchdog: watchable = yes");
459                 }
460             } while (false);
461         }
462         if ( (this.watchdog_ct % this.watchdog_checktm) == 0) {
463             this.log("hs::watchdog: this.keepalive_old: "+this.keepalive_old+" this.keepalive_new: "+this.keepalive_new);
464             if (this.keepalive_old == this.keepalive_new) {
465                 this.keepalives_equal++;
466             }
467             else {
468                 this.keepalive_old = this.keepalive_new;
469                 this.keepalives_equal = 0;
470             }
471             
472             if (this.keepalives_equal > this.keepalives_eq_max) {
473                 this.log("hs::watchdog: MAX ACHIEVED "+this.keepalives_equal);
474                 this.reload();
475                 // alert("watchdog return reload");
476                 return;
477             }
478         }
479
480         // PICK COMMANDS FROM STREAM
481         do {
482             // alert("do--while begin ["+again+"]");
483             // CHECK: maybe again here isn't needed 
484             again = 0;
485             try {
486                 /* if (typeof(this.ifra.contentWindow.ctx_new)     == 'undefined' ||
487                    typeof(this.ifra.contentWindow.ctx_old_len) == 'undefined') */
488                 if (!this.transp.ctx_new_is_set() || !this.transp.ctx_old_len_is_set())
489                     break;
490             }
491             catch(b) {
492                 break;
493             }
494
495             // ctx_new_len = this.ifra.contentWindow.ctx_new.length;
496             ctx_new_len = this.transp.ctx_new_curlen_get();
497             // if (ctx_new_len <= this.ifra.contentWindow.ctx_old_len) {
498             if (ctx_new_len <= this.transp.ctx_old_len_get()) {
499                 break;
500             }
501             this.log("new: "+ ctx_new_len + "  old: "+this.transp.ctx_old_len_get());
502             this.keepalive_new++;
503             // alert("pre-loop 1");
504             for (i = this.transp.ctx_old_len_get() ; i < ctx_new_len ; i++) {
505                 // if (this.ifra.contentWindow.ctx_new.charAt(i) != '_') {
506                 if (this.transp.ctx_new_getchar(i) != '_') {
507                     // this.log("ctx_new.char(i) != '_' ["+this.ifra.contentWindow.ctx_new.charAt(i)+"]");
508                     break;
509                 }
510                 // else {
511                 //     this.log("ctx_new.charAt(i) == '_'");
512                 // }
513             }
514             // this.ifra.contentWindow.ctx_old_len = i;
515             this.transp.ctx_old_len_set(i);
516             if (i == ctx_new_len) {
517                 this.log("old_len == i");
518                 break;
519             }
520             else {
521                 this.log("old_len != i: "+i);
522             }
523             // alert("do--while middle ["+this.ifra.contentWindow.ctx_old_len+"]");
524
525             comm_newpart = this.transp.new_part();
526             this.log("COM_NEWPART: ["+comm_newpart+"]");
527             comm_len = 0;
528             comm_arr = comm_newpart.match(this.comm_match);
529
530             // alert("do--while middle2 ["+again+"]");
531             if (comm_arr) {
532                 var comm_arr_len = comm_arr.length;
533                 for (i = 0 ; i < comm_arr_len ; i++) {
534                     var temp = comm_arr[i].replace(this.comm_clean,"$1").split("|");
535                     this.gst.comms = this.gst.comms.concat(temp);
536                     comm_len += comm_arr[i].length;
537                 }
538                 again = 1;
539             }
540             // this.ifra.contentWindow.ctx_old_len += comm_len;
541             this.transp.ctx_old_len_add(comm_len);
542             // this.ifra.contentWindow.script_clean = this.gst.st;
543             this.transp.scrcls_set(this.gst.st);
544             // alert("do--while end ["+again+"]");
545         } while (again);
546
547         // alert("post while");
548         // EXECUTION OF STREAM COMMANDS
549         do {
550             again = 0;
551             //MOP ?? xhrrestart = 0;
552             if (this.gst.st_loc < this.gst.st_loc_new) {
553                 // there is some slow actions running
554                 break;
555             }
556             else if (this.gst.comms.length > 0) {
557                 var singlecomm;
558                 
559                 singlecomm = this.gst.comms.shift();
560                 // alert("EXE"+gugu);
561                 // $("xhrdeltalog").innerHTML = "EVALL: "+singlecomm.replace("<", "&lt;", "g"); +"<br>";
562                 //xx this.hbit("+");
563
564                 // alert("SINGLE: ["+singlecomm+"]");
565                 this.cmdproc(singlecomm);
566                 again = 1;
567             }
568         } while (again);
569         this.watchdog_ct++;
570         if (!this.the_end) {
571             this.transp.postproc();
572             this.watchdog_hdl = setTimeout(function(obj) { /* obj.log("tout2"); */ obj.watchdog(); }, this.watchdog_timeout, this);
573         }
574         // alert("watchdog return normal");
575
576         return;
577     },
578
579     //
580     // moved to xynt-streaming-ifra as push()
581     //
582     // keepalive: function (s) {
583     //     this.log("hs::keepalive");
584     //     if (s != null) {
585     //         this.log(s);
586     //         this.ifra.contentWindow.ctx_new += "@BEGIN@"+s+"@END@";
587     //     }
588     //     else {
589     //         this.ifra.contentWindow.ctx_new += "_";
590     //     }
591     //     // this.keepalive_new++;
592     // },
593
594     abort: function () { /* public */
595         // this.log("PATH: "+this.ifra.contentWindow.location.protocol + "://" + this.ifra.contentWindow.location.host + "/" + this.ifra.contentWindow.location.pathname);
596
597         this.gst.abort();
598         if (this.watchdog_hdl != null) {
599             clearTimeout(this.watchdog_hdl);
600             this.watchdog_hdl = null;
601         }
602
603         this.restart_n++;
604         this.log("hs::reload");
605         this.watchable = false;
606         if (this.transp != null) {
607             this.transp.destroy();
608             delete this.transp;
609             this.transp = null;
610         }
611     },
612
613     reload: function () {
614         this.abort();
615         this.start(null);
616     },
617
618     log: function (s) {
619         if (this.console != null) {
620             return (this.console.log(s));
621         }
622     }
623 }