1 Request.XHRStreaming = new Class({
6 read: 0, //Contain the amout of data read
8 send: function(options) {
9 //mootools set onreadystatechange after xhr.open. In webkit, this cause readyState 1 to be never fired
10 if (Browser.Engine.webkit) this.xhr.onreadystatechange = this.onStateChange.bind(this);
11 return this.parent(options);
14 onStateChange: function() {
15 if (this.xhr.readyState == 1) this.dataSent = true;
16 else if (this.xhr.readyState == 3) this.progress(this.xhr.responseText, this.xhr.responseXML);
20 onProgress: function(){
21 this.fireEvent('progress', arguments);
24 progress: function(text, xml){
25 var length = text.length;
27 text = text.substr(this.lastTextLength);
28 this.lastTextLength = length;
29 this.onProgress(this.processScripts(text), xml);
32 APE.Transport.XHRStreaming = new Class({
34 maxRequestSize: 100000,
36 Implements: APE.Request.SSE,
38 initialize: function(ape){
40 this.requestFailObserver = [];
42 //If browser support servent sent event, switch to SSE / XHR transport
43 if (this.SSESupport) this.ape.options.transport = 4;
46 timeoutObserver: null,
53 send: function(queryString, options) {
54 if (this.SSESupport && !this.eventSource) {
55 this.initSSE(queryString, options, this.readSSE.bind(this));
56 if (options.requestCallback) this.streamInfo.callback = options.requestCallback;
58 if ((!this.streamRequest || !this.streamRequest.running) && !this.eventSource) { //Only one XHRstreaming request is allowed
60 this.request = this.doRequest(queryString, options);
62 if (options.requestCallback) this.streamInfo.callback = options.requestCallback;
63 } else { //Simple XHR request
64 var request = new Request({
65 url: this.ape.serverUri,
66 onFailure: this.ape.requestFail.bind(this.ape, [-2, this]),
67 onComplete: function(resp) {
68 $clear(this.requestFailObserver.shift());
69 this.request.dataSent = true;//In the case of XHRStreaming. Request are imediatly close.
70 this.ape.parseResponse(resp, options.callback);
73 this.request = request;
75 //set up an observer to detect request timeout
76 this.requestFailObserver.push(this.ape.requestFail.delay(this.ape.options.pollTime + 10000, this.ape, [1, request]));
84 doRequest: function(queryString, options) {
85 this.streamInfo.forceClose = false;
87 var request = new Request.XHRStreaming({
88 url: this.ape.serverUri,
89 onProgress: this.readFragment.bindWithEvent(this),
90 onFailure: this.ape.requestFail.bind(this.ape, [-2, this]),
91 onComplete: function(resp) {
92 $clear(this.streamInfo.timeoutObserver);
93 if (this.ape.status > 0) {
94 if (this.streamInfo.cleanClose) this.ape.check();
95 else this.newStream();
96 this.streamInfo.cleanClose = false;
101 request.id = $time();
102 this.streamRequest = request;
104 //this should no longer exist
105 //this.streamInfo.timeoutObserver = (function() {
106 // this.streamInfo.forceClose = true;
107 // //try to imediatly close stream
108 // if (this.checkStream()) this.newStream();
109 //}).delay(1000*60, this);
114 readSSE: function(data) {
115 this.ape.parseResponse(data, this.streamInfo.callback);
116 this.streamInfo.callback = null;
119 readFragment: function(text){
120 this.streamInfo.canClose = false;
124 this.streamInfo.canClose = true;
125 this.streamInfo.cleanClose = true;
126 this.ape.parseResponse(text, this.streamInfo.callback);
128 this.streamInfo.callback = null;
130 text = this.buffer + text;
131 var group = text.split("\n\n");
132 var length = group.length;
134 // If group.length is gretter than 1 the fragment received complete last RAW or contains more than one RAW
135 if (group.length > 1) {
139 for (var i = 0; i < length-1; i++) {
140 this.ape.parseResponse(group[i], this.streamInfo.callback);
143 if (group[length-1] !== '') { //Last group complete last received raw but it's not finish
144 this.buffer += group[length-1];
145 } else { //Received fragment is complete
146 this.streamInfo.canClose = true;
147 if (this.checkStream()) this.newStream();
151 this.streamInfo.callback = null;
152 } else {//Fragement received is a part of a raw
158 running: function() {
159 return (this.streamRequest && this.streamRequest.running) ? true : this.eventSource ? true : false;
162 checkStream: function() {
163 return (this.streamInfo.forceClose && this.streamInfo.canClose) || (this.streamRequest && this.streamRequest.read >= this.maxRequestSize && this.streamInfo.canClose);
166 newStream: function() {
167 // this.ape.request.send('CLOSE');//This will close the stream request
168 $clear(this.streamInfo.timeoutObserver);
169 this.streamRequest.cancel();
174 if (this.request) this.request.cancel();
176 $clear(this.streamInfo.timeoutObserver);
177 $clear(this.requestFailObserver.shift());
180 APE.Transport.XHRStreaming.browserSupport = function() {
181 if (Browser.Features.xhr && (Browser.Engine.webkit || Browser.Engine.gecko)) {
184 if (Browser.Engine.presto && ((typeof window.addEventStream) == 'function')) return true;
185 else if (window.XDomainRequest) return true;
186 else return Browser.Engine.trident ? 0 : true;
188 } else if (Browser.Features.xhr) return 0;//No XHRStreaming support switch to long polling
189 else return 2;//No XHR Support, switch to JSONP