|
29 | 29 | $.extend(settings, customSettings); |
30 | 30 |
|
31 | 31 | sse._url = url; |
| 32 | + sse._remoteHost = null; |
32 | 33 | sse._settings = settings; |
33 | 34 |
|
34 | 35 | // Start the proper EventSource object or Ajax fallback |
|
64 | 65 | this.type = null; |
65 | 66 |
|
66 | 67 | return true; |
67 | | - |
68 | 68 | }; |
69 | 69 |
|
70 | 70 | return sse; |
|
102 | 102 | me.instance = {successCount: 0, id: null, retry: 3000, data: "", event: ""}; |
103 | 103 | runAjax(me); |
104 | 104 | } |
| 105 | + |
| 106 | + function handleAjax(me, receivedData) { |
| 107 | + if (!me.instance) { |
| 108 | + return; |
| 109 | + } |
| 110 | + |
| 111 | + if (me.instance.successCount++ === 0) { |
| 112 | + me._settings.onOpen(); |
| 113 | + } |
| 114 | + |
| 115 | + var lines = receivedData.split("\n"); |
| 116 | + |
| 117 | + // Process the return to generate a compatible SSE response |
| 118 | + me.instance.data = ""; |
| 119 | + var countBreakLine = 0; |
| 120 | + for (var key in lines) { |
| 121 | + var separatorPos = lines[key].indexOf(":"); |
| 122 | + var item = [ |
| 123 | + lines[key].substr(0, separatorPos), |
| 124 | + lines[key].substr(separatorPos + 1) |
| 125 | + ]; |
| 126 | + switch (item[0]) { |
| 127 | + // If the first part is empty, needed to check another sequence |
| 128 | + case "": |
| 129 | + if (!item[1] && countBreakLine++ === 1) { // Avoid comments! |
| 130 | + eventMessage = { |
| 131 | + data: me.instance.data, |
| 132 | + lastEventId: me.instance.id, |
| 133 | + origin: 'http://' + me._remoteHost, |
| 134 | + returnValue: true |
| 135 | + }; |
| 136 | + |
| 137 | + // If there are a custom event then call it |
| 138 | + if (me.instance.event && me._settings.events[me.instance.event]) { |
| 139 | + me._settings.events[me.instance.event](eventMessage); |
| 140 | + } else { |
| 141 | + me._settings.onMessage(eventMessage); |
| 142 | + } |
| 143 | + me.instance.data = ""; |
| 144 | + me.instance.event = ""; |
| 145 | + countBreakLine = 0; |
| 146 | + } |
| 147 | + break; |
| 148 | + |
| 149 | + // Define the new retry object; |
| 150 | + case "retry": |
| 151 | + countBreakLine = 0; |
| 152 | + me.instance.retry = parseInt(item[1].trim()); |
| 153 | + break; |
| 154 | + |
| 155 | + // Define the new ID |
| 156 | + case "id": |
| 157 | + countBreakLine = 0; |
| 158 | + me.instance.id = item[1].trim(); |
| 159 | + break; |
| 160 | + |
| 161 | + // Define a custom event |
| 162 | + case "event": |
| 163 | + countBreakLine = 0; |
| 164 | + me.instance.event = item[1].trim(); |
| 165 | + break; |
| 166 | + |
| 167 | + // Define the data to be processed. |
| 168 | + case "data": |
| 169 | + countBreakLine = 0; |
| 170 | + me.instance.data += (me.instance.data !== "" ? "\n" : "") + item[1].trim(); |
| 171 | + break; |
| 172 | + |
| 173 | + default: |
| 174 | + countBreakLine = 0; |
| 175 | + } |
| 176 | + } |
| 177 | + } |
| 178 | + |
| 179 | + function getRemoteHost(me) { |
| 180 | + $.ajax({ |
| 181 | + type: 'HEAD', |
| 182 | + headers: me._settings.headers, |
| 183 | + url: me._url, |
| 184 | + complete: function(xhr) { |
| 185 | + me._remoteHost = xhr.getResponseHeader('Host'); |
| 186 | + } |
| 187 | + }); |
| 188 | + } |
105 | 189 |
|
106 | 190 | // Handle the continous Ajax request (fallback) |
107 | 191 | function runAjax(me) { |
108 | 192 | if (!me.instance) { |
109 | 193 | return; |
110 | 194 | } |
111 | 195 |
|
| 196 | + if (!me._remoteHost) { |
| 197 | + getRemoteHost(me); |
| 198 | + } |
| 199 | + |
112 | 200 | var headers = {'Last-Event-ID': me.instance.id}; |
113 | 201 |
|
114 | 202 | $.extend(headers, me._settings.headers); |
115 | 203 |
|
| 204 | + // https://stackoverflow.com/questions/7740646/jquery-read-ajax-stream-incrementally |
| 205 | + var lastResponseLen = false; |
| 206 | + var thisResponse = ""; |
116 | 207 | $.ajax({ |
117 | 208 | url: me._url, |
118 | 209 | method: 'GET', |
119 | 210 | headers: headers, |
120 | | - success: function (receivedData, status, info) { |
121 | | - if (!me.instance) { |
122 | | - return; |
123 | | - } |
124 | | - |
125 | | - if (me.instance.successCount++ === 0) { |
126 | | - me._settings.onOpen(); |
127 | | - } |
| 211 | + xhrFields: { |
| 212 | + onprogress: function(e) { |
| 213 | + var response = e.currentTarget.response; |
| 214 | + if(lastResponseLen === false) { |
| 215 | + thisResponse += response; |
| 216 | + } else { |
| 217 | + thisResponse += response.substring(lastResponseLen); |
| 218 | + } |
| 219 | + lastResponseLen = response.length; |
128 | 220 |
|
129 | | - var lines = receivedData.split("\n"); |
130 | | - |
131 | | - // Process the return to generate a compatible SSE response |
132 | | - me.instance.data = ""; |
133 | | - var countBreakLine = 0; |
134 | | - for (var key in lines) { |
135 | | - var separatorPos = lines[key].indexOf(":"); |
136 | | - var item = [ |
137 | | - lines[key].substr(0, separatorPos), |
138 | | - lines[key].substr(separatorPos + 1) |
139 | | - ]; |
140 | | - switch (item[0]) { |
141 | | - // If the first part is empty, needed to check another sequence |
142 | | - case "": |
143 | | - if (!item[1] && countBreakLine++ === 1) { // Avoid comments! |
144 | | - eventMessage = { |
145 | | - data: me.instance.data, |
146 | | - lastEventId: me.instance.id, |
147 | | - origin: 'http://' + info.getResponseHeader('Host'), |
148 | | - returnValue: true |
149 | | - }; |
150 | | - |
151 | | - // If there are a custom event then call it |
152 | | - if (me.instance.event && me._settings.events[me.instance.event]) { |
153 | | - me._settings.events[me.instance.event](eventMessage); |
154 | | - } else { |
155 | | - me._settings.onMessage(eventMessage); |
156 | | - } |
157 | | - me.instance.data = ""; |
158 | | - me.instance.event = ""; |
159 | | - countBreakLine = 0; |
160 | | - } |
161 | | - break; |
162 | | - |
163 | | - // Define the new retry object; |
164 | | - case "retry": |
165 | | - countBreakLine = 0; |
166 | | - me.instance.retry = parseInt(item[1].trim()); |
167 | | - break; |
168 | | - |
169 | | - // Define the new ID |
170 | | - case "id": |
171 | | - countBreakLine = 0; |
172 | | - me.instance.id = item[1].trim(); |
173 | | - break; |
174 | | - |
175 | | - // Define a custom event |
176 | | - case "event": |
177 | | - countBreakLine = 0; |
178 | | - me.instance.event = item[1].trim(); |
179 | | - break; |
180 | | - |
181 | | - // Define the data to be processed. |
182 | | - case "data": |
183 | | - countBreakLine = 0; |
184 | | - me.instance.data += (me.instance.data !== "" ? "\n" : "") + item[1].trim(); |
185 | | - break; |
186 | | - |
187 | | - default: |
188 | | - countBreakLine = 0; |
| 221 | + var hasFullMessage = thisResponse.lastIndexOf("\n\n"); |
| 222 | + if (hasFullMessage >= 0) { |
| 223 | + var chunk = thisResponse.substring(0, hasFullMessage + 2); |
| 224 | + thisResponse = thisResponse.substring(hasFullMessage + 2); |
| 225 | + handleAjax(me, chunk) |
189 | 226 | } |
190 | 227 | } |
| 228 | + }, |
| 229 | + success: function () { |
191 | 230 | setTimeout(function () { |
192 | 231 | runAjax(me); |
193 | 232 | }, me.instance.retry); |
|
0 commit comments