new class transport iframe decoupled from xynt_streaming to allow multiple transports
[brisk.git] / web / xynt-streaming.js
1 // old targetpage == page and moved into start method
2
3 function transport_iframe(doc, page)
4 {
5     this.doc = doc;
6     this.ifra = doc.createElement("iframe");
7     this.ifra.style.visibility = "hidden";
8     doc.body.appendChild(this.ifra);
9     this.ifra.contentWindow.location.href = page;
10 }
11
12 transport_iframe.prototype = {
13     doc: null,
14     ifra: null,
15
16     destroy: function () { /* public */
17         if (this.ifra != null) {
18             this.doc.body.removeChild(this.ifra);
19             delete this.ifra;
20             this.ifra = null;
21         }
22     },
23
24     xstr_is_init: function () { /* public */
25         return (typeof(this.ifra.contentWindow.xynt_streaming) != 'undefined');
26     },
27
28     /* only after a successfull is_initialized call */
29     xstr_is_ready: function () { /* public */
30         return (this.ifra.contentWindow.xynt_streaming == "ready");
31     },
32
33     /* only after a successfull is_ready call to be sure the accessibility of the var */
34     xstr_set: function (xynt_streaming) { /* public */
35         this.ifra.contentWindow.xynt_streaming = xynt_streaming;
36     },
37
38     ctx_new_is_set: function () { /* public */
39         return (typeof(this.ifra.contentWindow.ctx_new) != 'undefined');
40     },
41
42     ctx_new_curlen_get: function () { /* public */
43         return (this.ifra.contentWindow.ctx_new.length);
44     },
45
46     ctx_new_getchar: function(idx) { /* public */
47     },
48
49     ctx_old_len_is_set: function () { /* public */
50         return (typeof(this.ifra.contentWindow.ctx_old_len) != 'undefined');
51     },
52
53     ctx_old_len_get: function () { /* public */
54         return (this.ifra.contentWindow.ctx_old_len);
55     },
56
57     ctx_old_len_set: function (len) { /* public */
58         this.ifra.contentWindow.ctx_old_len = len;
59     },
60
61     ctx_old_len_add: function (len) { /* public */
62         this.ifra.contentWindow.ctx_old_len += len;
63     },
64
65     new_part: function () { /* public */
66         return (this.ifra.contentWindow.ctx_new.substr(this.ifra.contentWindow.ctx_old_len));
67     },
68
69     scrcls_set: function (step) { /* public */
70         this.ifra.contentWindow.script_clean = step;
71     }
72 }
73
74 function xynt_streaming(win, transp_type, console, gst, from, cookiename, sess, sandbox, page, cmdproc)
75 {
76     this.win = win;
77     this.transp_type = transp_type;
78     this.console = console;
79     this.gst = gst;
80     this.from = from;
81     this.cookiename = cookiename;
82     this.sess = sess;
83     this.sandbox = sandbox;
84     this.page = page;
85     this.cmdproc = cmdproc;
86     // this.cmdproc = function(com){/* console.log("COM: "+com); */ eval(com);}
87
88     this.doc = win.document;
89     this.keepalive_old = -1;
90     this.keepalive_new = -1;
91 }
92
93 xynt_streaming.prototype = {
94     win:               null,
95     transp_type:       null,
96     transp:            null,
97     console:           null,
98     gst:               null,
99     from:              null,
100     cookiename:        null,
101     sess:              null,
102     sandbox:           null,
103     page:              null,
104     cmdproc:           null,
105
106     doc:               null,
107     cookiepath: "/brisk/",
108     watchdog_hdl:      null,
109     hbit:              null,
110     keepalive_old:    -1,
111     keepalive_new:    -1,
112     keepalives_equal:  0,
113     /* NOTE: right watch_timeout value to 100, for devel reasons use 1000 or more */
114     // FIXME watchdog_timeout:  200,
115     /* restart after  3 * 40 * 100 millisec if server ping is missing => 12secs */
116     keepalives_eq_max: 3,
117     watchdog_checktm:  40,
118     watchdog_timeout:  100,
119     watchdog_ct:       0,
120     watchable:         false,
121     restart_n:         0,
122     comm_match:        /_*@BEGIN@(.*?)@END@/g, 
123     comm_clean:        /_*@BEGIN@(.*?)@END@/,
124     stream:            "",
125     the_end:           false,
126
127     start: function() { /* public */
128         if (this.the_end) 
129             return;
130
131         createCookie(this.cookiename, sess, 24*365, this.cookiepath);
132         // alert("start");
133         this.log("xynt_streaming:start restart: "+this.restart_n);
134         this.keepalives_equal = 0;
135
136         // page arrangement
137         this.page = url_complete(this.win.location.href, this.page);
138         // stat, subst, this.gst.st
139
140         this.page = url_append_args(this.page, "sess", this.sess, "stat", stat, "subst", subst, "step", this.gst.st, "from", this.from);
141         this.log(this.page);
142
143         // transport instantiation
144         if (this.transp_type == "iframe") {
145             this.transp = new transport_iframe(this.doc, this.page);
146         }
147
148         // watchdog setting
149         this.watchdog_ct  = 0;
150         if (!this.the_end) {
151             this.watchdog_hdl = setTimeout(function(obj) { obj.log("tout1"); obj.watchdog(); }, this.watchdog_timeout, this);
152         }
153     },
154
155     stop: function() {
156         this.the_end = true;
157         this.abort();
158     },
159
160     hbit_set: function (hbit) {
161         this.hbit = hbit;
162     },
163
164     watchdog: function () {
165         // alert("watchdog");
166         var i, again;
167         var comm_newpart, comm_len, comm_arr;
168         var ctx_new_len;
169
170         if (this.sandbox != null) {
171             // 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;
172             var zug = "WATCHDOG  sess = ["+this.sess+"]  step = "+this.gst.st+" step_loc = "+this.gst.st_loc+" step_loc_new = "+this.gst.st_loc_new;          
173             if (zug != this.sandbox.innerHTML)
174                 this.sandbox.innerHTML = zug;
175         }
176
177         // WATCHDOGING THE CONNECTION
178         this.log("hs::watchdog: start, cur equal times: "+this.keepalives_equal);
179         if (!this.watchable) {
180             do {
181                 try{
182                     // if (typeof(this.ifra.contentWindow.xynt_streaming) == 'undefined')
183                     if (!this.transp.xstr_is_init())
184                         break;
185                 }
186                 catch(b) {
187                     break;
188                 }
189
190                 /*
191                   on IE7 the the window frame scope is cleaned after the href is set, so we wait 
192                   for a well know variable value before assign this object value to it (OO is a passion)
193                 */
194                 // if (this.ifra.contentWindow.xynt_streaming == "ready") {
195                 if (this.transp.xstr_is_ready()) {
196                     // this.ifra.contentWindow.xynt_streaming = this;
197                     this.transp.xstr_set(this);
198                     this.watchable = true;
199                     this.watchdog_ct = 0;
200                     this.log("hs::watchdog: watchable = yes");
201                 }
202             } while (false);
203         }
204         if ( (this.watchdog_ct % this.watchdog_checktm) == 0) {
205             this.log("hs::watchdog: this.keepalive_old: "+this.keepalive_old+" this.keepalive_new: "+this.keepalive_new);
206             if (this.keepalive_old == this.keepalive_new) {
207                 this.keepalives_equal++;
208             }
209             else {
210                 this.keepalive_old = this.keepalive_new;
211                 this.keepalives_equal = 0;
212             }
213             
214             if (this.keepalives_equal > this.keepalives_eq_max) {
215                 this.log("hs::watchdog: MAX ACHIEVED "+this.keepalives_equal);
216                 this.reload();
217                 // alert("watchdog return reload");
218                 return;
219             }
220         }
221
222         // PICK COMMANDS FROM STREAM
223         do {
224             // alert("do--while begin ["+again+"]");
225             // CHECK: maybe again here isn't needed 
226             again = 0;
227             try {
228                 /* if (typeof(this.ifra.contentWindow.ctx_new)     == 'undefined' ||
229                    typeof(this.ifra.contentWindow.ctx_old_len) == 'undefined') */
230                 if (!this.transp.ctx_new_is_set() || !this.transp.ctx_old_len_is_set())
231                     break;
232             }
233             catch(b) {
234                 break;
235             }
236             
237             // ctx_new_len = this.ifra.contentWindow.ctx_new.length;
238             ctx_new_len = this.transp.ctx_new_curlen_get();
239             // if (ctx_new_len <= this.ifra.contentWindow.ctx_old_len) {
240             if (ctx_new_len <= this.transp.ctx_old_len_get()) {
241                 break;
242             }
243             this.log("new: "+ ctx_new_len + "  old: "+this.transp.ctx_old_len_get());
244             this.keepalive_new++;
245             // alert("pre-loop 1");
246             for (i = this.transp.ctx_old_len_get() ; i < ctx_new_len ; i++) {
247                 // if (this.ifra.contentWindow.ctx_new.charAt(i) != '_') {
248                 if (this.transp.ctx_new_getchar(i) != '_') {
249                     // this.log("ctx_new.char(i) != '_' ["+this.ifra.contentWindow.ctx_new.charAt(i)+"]");
250                     break;
251                 }
252                 // else {
253                 //     this.log("ctx_new.charAt(i) == '_'");
254                 // }
255             }
256             // this.ifra.contentWindow.ctx_old_len = i;
257             this.transp.ctx_old_len_set(i);
258             if (i == ctx_new_len) {
259                 this.log("old_len == i");
260                 break;
261             }
262             else {
263                 this.log("old_len != i: "+i);
264             }
265             // alert("do--while middle ["+this.ifra.contentWindow.ctx_old_len+"]");
266
267             comm_newpart = this.transp.new_part();
268             this.log("COM_NEWPART: ["+comm_newpart+"]");
269             comm_len = 0;
270             comm_arr = comm_newpart.match(this.comm_match);
271
272             // alert("do--while middle2 ["+again+"]");
273             if (comm_arr) {
274                 var comm_arr_len = comm_arr.length;
275                 for (i = 0 ; i < comm_arr_len ; i++) {
276                     var temp = comm_arr[i].replace(this.comm_clean,"$1").split("|");
277                     this.gst.comms = this.gst.comms.concat(temp);
278                     comm_len += comm_arr[i].length;
279                 }
280                 again = 1;
281             }
282             // this.ifra.contentWindow.ctx_old_len += comm_len;
283             this.transp.ctx_old_len_add(comm_len);
284             // this.ifra.contentWindow.script_clean = this.gst.st;
285             this.transp.scrcls_set(this.gst.st);
286             // alert("do--while end ["+again+"]");
287         } while (again);
288
289         // alert("post while");
290         // EXECUTION OF STREAM COMMANDS
291         do {
292             again = 0;
293             //MOP ?? xhrrestart = 0;
294             if (this.gst.st_loc < this.gst.st_loc_new) {
295                 // there is some slow actions running
296                 break;
297             }
298             else if (this.gst.comms.length > 0) {
299                 var singlecomm;
300                 
301                 singlecomm = this.gst.comms.shift();
302                 // alert("EXE"+gugu);
303                 // $("xhrdeltalog").innerHTML = "EVALL: "+singlecomm.replace("<", "&lt;", "g"); +"<br>";
304                 //xx this.hbit("+");
305
306                 // alert("SINGLE: ["+singlecomm+"]");
307                 this.cmdproc(singlecomm);
308                 again = 1;
309             }
310         } while (again);
311         this.watchdog_ct++;
312         if (!this.the_end) {
313             this.watchdog_hdl = setTimeout(function(obj) { /* obj.log("tout2"); */ obj.watchdog(); }, this.watchdog_timeout, this);
314         }
315         // alert("watchdog return normal");
316
317         return;
318     },
319
320     //
321     // moved to xynt-streaming-ifra as push()
322     //
323     // keepalive: function (s) {
324     //     this.log("hs::keepalive");
325     //     if (s != null) {
326     //         this.log(s);
327     //         this.ifra.contentWindow.ctx_new += "@BEGIN@"+s+"@END@";
328     //     }
329     //     else {
330     //         this.ifra.contentWindow.ctx_new += "_";
331     //     }
332     //     // this.keepalive_new++;
333     // },
334
335     abort: function () { /* public */
336         // this.log("PATH: "+this.ifra.contentWindow.location.protocol + "://" + this.ifra.contentWindow.location.host + "/" + this.ifra.contentWindow.location.pathname);
337
338         this.gst.abort();
339         if (this.watchdog_hdl != null) {
340             clearTimeout(this.watchdog_hdl);
341             this.watchdog_hdl = null;
342         }
343
344         this.restart_n++;
345         this.log("hs::reload");
346         this.watchable = false;
347         if (this.transp != null) {
348             this.transp.destroy();
349             delete this.transp;
350             this.transp = null;
351         }
352     },
353
354     reload: function () {
355         this.abort();
356         this.start(null);
357     },
358
359     log: function (s) {
360         if (this.console != null) {
361             return (this.console.log(s));
362         }
363     }
364 }