| 1 | | |
|---|
| 2 | | split_schemedomainandport = function( url){ |
|---|
| 3 | | /*** |
|---|
| 4 | | |
|---|
| 5 | | **Split a url into its constituent parts.** |
|---|
| 6 | | |
|---|
| 7 | | If port and or path parts are missing from the url, the associated fields |
|---|
| 8 | | are set to null:: |
|---|
| 9 | | |
|---|
| 10 | | sdpp => [scheme, domain, port|null, path|null] |
|---|
| 11 | | |
|---|
| 12 | | Both, ``join_schemedomainandport`` and ``replace_schemedomainandport_path`` |
|---|
| 13 | | cope with this. Note that:: |
|---|
| 14 | | |
|---|
| 15 | | join(split('http://some.domain')) => 'http://some.domain/' |
|---|
| 16 | | join(split('http://some.domain:8080')) => 'http://some.domain:8080/' |
|---|
| 17 | | join(split('http://some.domain/')) => 'http://some.domain/' |
|---|
| 18 | | join(split('http://some.domain:8080/')) => 'http://some.domain:8080/' |
|---|
| 19 | | |
|---|
| 20 | | Ie., root path is forced if it is missing. |
|---|
| 21 | | |
|---|
| 22 | | ``url: url to split. if null or undefined currentDocument().URL is used.`` |
|---|
| 23 | | |
|---|
| | 1 | if (typeof(streamservice) == 'undefined') { |
|---|
| | 2 | streamservice = {}; |
|---|
| | 3 | } |
|---|
| | 4 | |
|---|
| | 5 | update(streamservice, { |
|---|
| | 6 | strip_tag_inplace : function(seperator, item){ |
|---|
| | 7 | item[0] = item[0].slice(item[0].split(seperator,1)[0].length + 1); |
|---|
| | 8 | return item; |
|---|
| | 9 | }, |
|---|
| | 10 | |
|---|
| | 11 | strip_tag : function (seperator, tag){ |
|---|
| | 12 | return tag.slice(tag.split(seperator,1)[0].length + 1); |
|---|
| | 13 | }, |
|---|
| | 14 | |
|---|
| | 15 | prepare_protocol : function (self, servicepath, |
|---|
| | 16 | dispatchparametername, names, values, sdpp){ |
|---|
| | 17 | if(self == null) |
|---|
| | 18 | self=this; |
|---|
| | 19 | if(typeof(self)=="undefined") |
|---|
| | 20 | self={}; |
|---|
| | 21 | |
|---|
| | 22 | if(typeof(dispatchparametername) == "undefined" || |
|---|
| | 23 | dispatchparametername==null) |
|---|
| | 24 | dispatchparametername="dispatcher"; |
|---|
| | 25 | self.dispatchparametername=dispatchparametername; |
|---|
| | 26 | |
|---|
| | 27 | if(typeof(names) == "undefined" || names==null){ |
|---|
| | 28 | self.queryparameters=parseQueryString( |
|---|
| | 29 | queryString([self.dispatchparametername],["[[],[]]"]), true); |
|---|
| | 30 | /*log("***: self.queryparameters = " + |
|---|
| | 31 | serializeJSON(self.queryparameters));*/ |
|---|
| | 32 | } else { |
|---|
| | 33 | /* normalize parameter representation */ |
|---|
| | 34 | self.queryparameters=parseQueryString(queryString( |
|---|
| | 35 | names, values), true); |
|---|
| | 36 | log("***: self.queryparameters = " + serializeJSON( |
|---|
| | 37 | self.queryparameters)); |
|---|
| | 38 | /* if there is a collision the first element of user specified |
|---|
| | 39 | value is clobbered */ |
|---|
| | 40 | if(typeof(self.queryparameters[self.dispatchparametername]) |
|---|
| | 41 | != "undefined"){ |
|---|
| | 42 | self.queryparameters[self.dispatchparametername][0]="[[],[]]" |
|---|
| | 43 | } |
|---|
| | 44 | else{ |
|---|
| | 45 | self.queryparameters[self.dispatchparametername]=["[[],[]]"]; |
|---|
| | 46 | } |
|---|
| | 47 | } |
|---|
| | 48 | |
|---|
| | 49 | if(typeof(sdpp)=="undefined" || sdpp == null){ |
|---|
| | 50 | self.sdpp=streamservice.split_schemedomainandport(); |
|---|
| | 51 | } else { |
|---|
| | 52 | self.sdpp = sdpp; |
|---|
| | 53 | } |
|---|
| | 54 | self.baseurl=streamservice.replace_schemedomainandport_path( |
|---|
| | 55 | self.sdpp, servicepath); |
|---|
| | 56 | self.sdpp[3]=servicepath; |
|---|
| | 57 | |
|---|
| | 58 | /* If interval is null or undefined, the Dispatcher uses its own value. |
|---|
| | 59 | Otherwise it uses this one. */ |
|---|
| | 60 | |
|---|
| | 61 | return self; |
|---|
| | 62 | }, |
|---|
| | 63 | |
|---|
| | 64 | poll_loopback_json : function( |
|---|
| | 65 | clientdata, |
|---|
| | 66 | latency, |
|---|
| | 67 | emulatedbackendpollresult, |
|---|
| | 68 | ignoreemulatedresponses){ |
|---|
| | 69 | /*** |
|---|
| | 70 | |
|---|
| | 71 | **Loopback implementation for** ``Protocol.poll``. |
|---|
| | 72 | |
|---|
| | 73 | Provided for the benefit of test code. Echos query items, encoded in |
|---|
| | 74 | clientdata, as the loopbackresult. |
|---|
| | 75 | |
|---|
| | 76 | ``clientdata: the serialized and encoded queries & responses`` to |
|---|
| | 77 | submit on the clients behalf. response items in ``clientdata`` |
|---|
| | 78 | are silently ignored. |
|---|
| | 79 | |
|---|
| | 80 | ``latency: how long the poll should take``. the default is 0. *Note* |
|---|
| | 81 | that latency <= 0 is special, it forces synchronous behaviour. |
|---|
| | 82 | |
|---|
| | 83 | ``emulatedbackendpollresult: emulated backend responses``, Serialized |
|---|
| | 84 | and encoded queries & responses fake response to this poll. By |
|---|
| | 85 | default, response items are not included in the items looped back |
|---|
| | 86 | to the client. |
|---|
| | 87 | |
|---|
| | 88 | ``ignoreemulatedresponses: Don't throw away emulated responses``. if this |
|---|
| | 89 | parameter is true then emulated backend responses are included in the |
|---|
| | 90 | loopback result. |
|---|
| | 91 | |
|---|
| | 92 | if latency was zero or unspecified the returned |
|---|
| | 93 | deferred has allready been fired.:: |
|---|
| | 94 | |
|---|
| | 95 | if latency unspecified or latency <= 0 |
|---|
| | 96 | returns succede(loopbackresult) |
|---|
| | 97 | Otherwise: |
|---|
| | 98 | wait(latency, loopbackresult) |
|---|
| | 99 | |
|---|
| | 100 | ``rtype: Deferred`` |
|---|
| | 101 | |
|---|
| | 102 | ***/ |
|---|
| | 103 | |
|---|
| | 104 | if(typeof(latency)=="undefined" || latency==null){ |
|---|
| | 105 | latency=0; |
|---|
| | 106 | } |
|---|
| | 107 | try{ |
|---|
| | 108 | /*log("***:" + clientdata);*/ |
|---|
| | 109 | var sent = streamservice.split_json(clientdata); |
|---|
| | 110 | var recvd = [null,null]; |
|---|
| | 111 | if( typeof(emulatedbackendpollresult)!="undefined" && |
|---|
| | 112 | emulatedbackendpollresult != null){ |
|---|
| | 113 | /*log("***:" + emulatedbackendpollresult); |
|---|
| | 114 | log("***:" + typeof(emulatedbackendpollresult));*/ |
|---|
| | 115 | recvd = streamservice.split_json(emulatedbackendpollresult); |
|---|
| | 116 | if(ignoreemulatedresponses != false) |
|---|
| | 117 | recvd = [recvd[0],null]; |
|---|
| | 118 | } |
|---|
| | 119 | /* log("***:" + serializeJSON(recvd)); */ |
|---|
| | 120 | var result = streamservice.join_json(recvd[0], sent[0]); |
|---|
| | 121 | if(recvd[1] != null){ |
|---|
| | 122 | /* merge the emulated responses in *before* the looped back |
|---|
| | 123 | responses */ |
|---|
| | 124 | result = streamservice.split_json(result); |
|---|
| | 125 | result = streamservice.join_json(result[0], |
|---|
| | 126 | extend(recvd[1], result[1])); |
|---|
| | 127 | } |
|---|
| | 128 | return latency <= 0 ? succeed(result) : wait(latency, result); |
|---|
| | 129 | } catch (result){ |
|---|
| | 130 | log("loopback raised:" + result); |
|---|
| | 131 | waitfail = function(seconds, value){ |
|---|
| | 132 | var d = wait(seconds); |
|---|
| | 133 | d.addBoth(partial(function (value){throw value;}, value)); |
|---|
| | 134 | return d; |
|---|
| | 135 | } |
|---|
| | 136 | return latency <= 0 ? fail(result) : waitfail(latency, result); |
|---|
| | 137 | } |
|---|
| | 138 | }, |
|---|
| | 139 | |
|---|
| | 140 | split_schemedomainandport : function( url){ |
|---|
| | 141 | /*** |
|---|
| | 142 | |
|---|
| | 143 | **Split a url into its constituent parts.** |
|---|
| | 144 | |
|---|
| | 145 | If port and or path parts are missing from the url, the associated fields |
|---|
| | 146 | are set to null:: |
|---|
| | 147 | |
|---|
| | 148 | sdpp => [scheme, domain, port|null, path|null] |
|---|
| | 149 | |
|---|
| | 150 | Both, ``join_schemedomainandport`` and ``replace_schemedomainandport_path`` |
|---|
| | 151 | cope with this. Note that:: |
|---|
| | 152 | |
|---|
| | 153 | join(split('http://some.domain')) => 'http://some.domain/' |
|---|
| | 154 | join(split('http://some.domain:8080')) => 'http://some.domain:8080/' |
|---|
| | 155 | join(split('http://some.domain/')) => 'http://some.domain/' |
|---|
| | 156 | join(split('http://some.domain:8080/')) => 'http://some.domain:8080/' |
|---|
| | 157 | |
|---|
| | 158 | Ie., root path is forced if it is missing. |
|---|
| | 159 | |
|---|
| | 160 | ``url: url to split. if null or undefined currentDocument().URL is used.`` |
|---|
| | 161 | |
|---|
| | 162 | ***/ |
|---|
| | 163 | if(typeof(url)=="undefined" || url==null){ |
|---|
| | 164 | url=currentDocument().URL; |
|---|
| | 165 | } |
|---|
| | 166 | var scheme = url.split(':',1)[0]; |
|---|
| | 167 | var domain = url.split('/')[2].split(':')[0]; |
|---|
| | 168 | var port = url.split('/')[2].split(':')[1]; |
|---|
| | 169 | var pathparts = url.split('/'); |
|---|
| | 170 | var path = null; |
|---|
| | 171 | if(pathparts.length > 3){ |
|---|
| | 172 | path = pathparts.slice(3, pathparts.length).join('/'); |
|---|
| | 173 | } |
|---|
| | 174 | if(typeof(port)=="undefined" || port == null) |
|---|
| | 175 | port=null; |
|---|
| | 176 | return [scheme, domain, port, path]; |
|---|
| | 177 | }, |
|---|
| | 178 | |
|---|
| | 179 | join_schemedomainandport : function(sdpp){ |
|---|
| | 180 | /*** |
|---|
| | 181 | |
|---|
| | 182 | **Compliment of split_schemedomainandport** |
|---|
| | 183 | |
|---|
| | 184 | ``sdpp: [scheme, domain, port|null, path| null]`` |
|---|
| | 185 | |
|---|
| | 186 | ***/ |
|---|
| | 187 | |
|---|
| | 188 | if(typeof(sdpp[2]) == "undefined" || sdpp[2] == null){ |
|---|
| | 189 | return sdpp[0] + "://" + |
|---|
| | 190 | sdpp[1] + "/" + |
|---|
| | 191 | sdpp.slice(3,sdpp.length).join('/'); |
|---|
| | 192 | } else { |
|---|
| | 193 | return sdpp[0] + "://" + |
|---|
| | 194 | sdpp[1] + ":" + sdpp[2] + "/" + |
|---|
| | 195 | sdpp.slice(3,sdpp.length).join('/'); |
|---|
| | 196 | } |
|---|
| | 197 | }, |
|---|
| | 198 | |
|---|
| | 199 | replace_schemedomainandport_path : function(sdpp, replacement){ |
|---|
| | 200 | /*** |
|---|
| | 201 | |
|---|
| | 202 | **Like, join but** ``replacement`` **clobbers path.** |
|---|
| | 203 | |
|---|
| | 204 | This is a shortcut for:: |
|---|
| | 205 | |
|---|
| | 206 | var url = split_schemedomainandport(url); |
|---|
| | 207 | url[3] = replacement; |
|---|
| | 208 | url = join_schemedomainandport(url); |
|---|
| | 209 | |
|---|
| | 210 | ***/ |
|---|
| | 211 | |
|---|
| | 212 | if(typeof(replacement) == "undefined" || replacement == null) |
|---|
| | 213 | replacement=""; |
|---|
| | 214 | if(typeof(sdpp[2]) == "undefined" || sdpp[2] == null){ |
|---|
| | 215 | return sdpp[0] + "://" + |
|---|
| | 216 | sdpp[1] + "/" + replacement; |
|---|
| | 217 | } else { |
|---|
| | 218 | return sdpp[0] + "://" + |
|---|
| | 219 | sdpp[1] + ":" + sdpp[2] + "/" + replacement; |
|---|
| | 220 | } |
|---|
| | 221 | }, |
|---|
| | 222 | |
|---|
| | 223 | join_json : function (queryitems, responseitems){ |
|---|
| | 224 | /*** |
|---|
| | 225 | |
|---|
| | 226 | **Serialize queued queries.** |
|---|
| | 227 | |
|---|
| | 228 | Into a format appropriate for a ``GET/POST`` request parameter. If you |
|---|
| | 229 | need to escape or otherwise encode data elements, see |
|---|
| | 230 | ``join_json_encodeitems`` |
|---|
| | 231 | |
|---|
| | 232 | ``queryitems: [[queryid1,data1], ... [queryidN,dataN]]`` |
|---|
| | 233 | |
|---|
| | 234 | ``responseitems: [[responseid1,data1], ... [responseidN,dataN]]`` |
|---|
| | 235 | |
|---|
| | 236 | ``rtype: json formated string`` |
|---|
| | 237 | |
|---|
| | 238 | ***/ |
|---|
| | 239 | |
|---|
| | 240 | if (typeof(queryitems) == "undefined" || queryitems == null) |
|---|
| | 241 | var queryitems = []; |
|---|
| | 242 | if (typeof(responseitems) == "undefined" || responseitems == null) |
|---|
| | 243 | var responseitems = []; |
|---|
| | 244 | return "[" + MochiKit.Base.serializeJSON(queryitems) + "," + |
|---|
| | 245 | MochiKit.Base.serializeJSON(responseitems) + "]"; |
|---|
| | 246 | }, |
|---|
| | 247 | |
|---|
| | 248 | join_json_encodeitems : function (queryitems, responseitems, |
|---|
| | 249 | queryitemencoder, responseitemencoder){ |
|---|
| | 250 | /*** |
|---|
| | 251 | |
|---|
| | 252 | **join, with custom item encoding.** |
|---|
| | 253 | |
|---|
| | 254 | See ``join_json`` |
|---|
| | 255 | |
|---|
| | 256 | queryitemencoder: called for each datafield in queryitems, |
|---|
| | 257 | should return ``encode(queryitemdata)``. |
|---|
| | 258 | |
|---|
| | 259 | responseitemencoder: called for each datafield in responseitems, |
|---|
| | 260 | should return ``encode(queryitemdata)``. |
|---|
| | 261 | |
|---|
| | 262 | If ``repsonseitemencoder`` is null or undefined it defaults to |
|---|
| | 263 | ``queryitemencoder``. |
|---|
| | 264 | |
|---|
| | 265 | If both ``responseitemencoder`` and ``queryitemencoder`` are either |
|---|
| | 266 | null or undefined this function short circuits to ``join_json``. |
|---|
| | 267 | |
|---|
| | 268 | ***/ |
|---|
| | 269 | |
|---|
| | 270 | if(typeof(responseitemencoder)=="undefined" |
|---|
| | 271 | || responseitemencoder == null) |
|---|
| | 272 | responseitemencoder = queryitemencoder; |
|---|
| | 273 | if(typeof(queryitemencoder)=="undefined" || queryitemencoder == null) |
|---|
| | 274 | return streamservice.join_json(queryitems, responseitems); |
|---|
| | 275 | if (typeof(queryitems) == "undefined" || queryitems == null) |
|---|
| | 276 | var queryitems = []; |
|---|
| | 277 | if (typeof(responseitems) == "undefined" || responseitems == null) |
|---|
| | 278 | var responseitems = []; |
|---|
| | 279 | |
|---|
| | 280 | var querydata=""; |
|---|
| | 281 | var responsedata=""; |
|---|
| | 282 | |
|---|
| | 283 | if(queryitems.length > 0){ |
|---|
| | 284 | querydata += queryitemencoder(queryitems[0]); |
|---|
| | 285 | if(queryitems.length > 1){ |
|---|
| | 286 | for(var i=1; i < queryitems.length; i++){ |
|---|
| | 287 | querydata += "," + queryitemencoder(queryitems[i]); |
|---|
| | 288 | } |
|---|
| | 289 | } |
|---|
| | 290 | } |
|---|
| | 291 | if(responseitems.length > 0){ |
|---|
| | 292 | responsedata += responseitemencoder(responseitems[0]); |
|---|
| | 293 | if(responseitems.length > 1){ |
|---|
| | 294 | for(var i=1; i < responseitems.length; i++){ |
|---|
| | 295 | responsedata += "," + responseitemencoder(responseitems[i]); |
|---|
| | 296 | } |
|---|
| | 297 | } |
|---|
| | 298 | } |
|---|
| | 299 | return "[[" + querydata + "]" + ",[" + responsedata + "]]"; |
|---|
| | 300 | }, |
|---|
| | 301 | |
|---|
| | 302 | split_json : function(data) { |
|---|
| | 303 | /*** |
|---|
| | 304 | |
|---|
| | 305 | Converse of join_json(queryitems, responseitems). |
|---|
| | 306 | |
|---|
| | 307 | WARNING: uses eval, You need to decide if you trust ``data``. |
|---|
| | 308 | |
|---|
| | 309 | ``data: a json string``, assumed to describe an array with the form |
|---|
| | 310 | |
|---|
| | 311 | | [iterablequeries, iterableresponses] |
|---|
| | 312 | | |
|---|
| | 313 | | [[[queryid1,data1], ... [queryidN,dataN]], |
|---|
| | 314 | | [[responseid1,data1], ... [responseidN,dataN]]] |
|---|
| | 315 | |
|---|
| | 316 | |
|---|
| | 317 | |
|---|
| | 318 | ``rtype: Iter`` |
|---|
| | 319 | |
|---|
| | 320 | ***/ |
|---|
| | 321 | |
|---|
| | 322 | if (typeof(data) == "undefined" || data == null){ |
|---|
| | 323 | return [iter([]), iter([])]; |
|---|
| | 324 | } |
|---|
| | 325 | return eval(data); |
|---|
| | 326 | } |
|---|
| | 327 | |
|---|
| | 328 | /***split_json_decodeitems |
|---|
| | 329 | |
|---|
| | 330 | don't think it makes sense to provide 'split_json_decodeitems' as it |
|---|
| | 331 | would be highly sensitive to different ``join_json_encodeitems`` |
|---|
| | 332 | encoding schemes. If you can't use end to end json, or, more |
|---|
| | 333 | importantly, you decide not to trust eval, then you need to write |
|---|
| | 334 | a custom split for your protocol implementation. |
|---|
| | 335 | |
|---|
| 25 | | if(typeof(url)=="undefined" || url==null){ |
|---|
| 26 | | url=currentDocument().URL; |
|---|
| 27 | | } |
|---|
| 28 | | var scheme = url.split(':',1)[0]; |
|---|
| 29 | | var domain = url.split('/')[2].split(':')[0]; |
|---|
| 30 | | var port = url.split('/')[2].split(':')[1]; |
|---|
| 31 | | var pathparts = url.split('/'); |
|---|
| 32 | | var path = null; |
|---|
| 33 | | if(pathparts.length > 3){ |
|---|
| 34 | | path = pathparts.slice(3, pathparts.length).join('/'); |
|---|
| 35 | | } |
|---|
| 36 | | if(typeof(port)=="undefined" || port == null) |
|---|
| 37 | | port=null; |
|---|
| 38 | | return [scheme, domain, port, path]; |
|---|
| 39 | | } |
|---|
| 40 | | |
|---|
| 41 | | join_schemedomainandport = function(sdpp){ |
|---|
| 42 | | /*** |
|---|
| 43 | | |
|---|
| 44 | | **Compliment of split_schemedomainandport** |
|---|
| 45 | | |
|---|
| 46 | | ``sdpp: [scheme, domain, port|null, path| null]`` |
|---|
| 47 | | |
|---|
| 48 | | ***/ |
|---|
| 49 | | |
|---|
| 50 | | if(typeof(sdpp[2]) == "undefined" || sdpp[2] == null){ |
|---|
| 51 | | return sdpp[0] + "://" + |
|---|
| 52 | | sdpp[1] + "/" + |
|---|
| 53 | | sdpp.slice(3,sdpp.length).join('/'); |
|---|
| 54 | | } else { |
|---|
| 55 | | return sdpp[0] + "://" + |
|---|
| 56 | | sdpp[1] + ":" + sdpp[2] + "/" + |
|---|
| 57 | | sdpp.slice(3,sdpp.length).join('/'); |
|---|
| 58 | | } |
|---|
| 59 | | } |
|---|
| 60 | | |
|---|
| 61 | | replace_schemedomainandport_path = function(sdpp, replacement){ |
|---|
| 62 | | /*** |
|---|
| 63 | | |
|---|
| 64 | | **Like, join but** ``replacement`` **clobbers path.** |
|---|
| 65 | | |
|---|
| 66 | | This is a shortcut for:: |
|---|
| 67 | | |
|---|
| 68 | | var url = split_schemedomainandport(url); |
|---|
| 69 | | url[3] = replacement; |
|---|
| 70 | | url = join_schemedomainandport(url); |
|---|
| 71 | | |
|---|
| 72 | | ***/ |
|---|
| 73 | | |
|---|
| 74 | | if(typeof(replacement) == "undefined" || replacement == null) |
|---|
| 75 | | replacement=""; |
|---|
| 76 | | if(typeof(sdpp[2]) == "undefined" || sdpp[2] == null){ |
|---|
| 77 | | return sdpp[0] + "://" + |
|---|
| 78 | | sdpp[1] + "/" + replacement; |
|---|
| 79 | | } else { |
|---|
| 80 | | return sdpp[0] + "://" + |
|---|
| 81 | | sdpp[1] + ":" + sdpp[2] + "/" + replacement; |
|---|
| 82 | | } |
|---|
| 83 | | } |
|---|
| 84 | | |
|---|
| 85 | | join_json = function (queryitems, responseitems){ |
|---|
| 86 | | /*** |
|---|
| 87 | | |
|---|
| 88 | | **Serialize queued queries.** |
|---|
| 89 | | |
|---|
| 90 | | Into a format appropriate for a ``GET/POST`` request parameter. If you |
|---|
| 91 | | need to escape or otherwise encode data elements, see |
|---|
| 92 | | ``join_json_encodeitems`` |
|---|
| 93 | | |
|---|
| 94 | | ``queryitems: [[queryid1,data1], ... [queryidN,dataN]]`` |
|---|
| 95 | | |
|---|
| 96 | | ``responseitems: [[responseid1,data1], ... [responseidN,dataN]]`` |
|---|
| 97 | | |
|---|
| 98 | | ``rtype: json formated string`` |
|---|
| 99 | | |
|---|
| 100 | | ***/ |
|---|
| 101 | | |
|---|
| 102 | | if (typeof(queryitems) == "undefined" || queryitems == null) |
|---|
| 103 | | var queryitems = []; |
|---|
| 104 | | if (typeof(responseitems) == "undefined" || responseitems == null) |
|---|
| 105 | | var responseitems = []; |
|---|
| 106 | | return "[" + MochiKit.Base.serializeJSON(queryitems) + "," + |
|---|
| 107 | | MochiKit.Base.serializeJSON(responseitems) + "]"; |
|---|
| 108 | | } |
|---|
| 109 | | |
|---|
| 110 | | join_json_encodeitems = function (queryitems, responseitems, |
|---|
| 111 | | queryitemencoder, responseitemencoder){ |
|---|
| 112 | | /*** |
|---|
| 113 | | |
|---|
| 114 | | **join, with custom item encoding.** |
|---|
| 115 | | |
|---|
| 116 | | See ``join_json`` |
|---|
| 117 | | |
|---|
| 118 | | queryitemencoder: called for each datafield in queryitems, |
|---|
| 119 | | should return ``encode(queryitemdata)``. |
|---|
| 120 | | |
|---|
| 121 | | responseitemencoder: called for each datafield in responseitems, |
|---|
| 122 | | should return ``encode(queryitemdata)``. |
|---|
| 123 | | |
|---|
| 124 | | If ``repsonseitemencoder`` is null or undefined it defaults to |
|---|
| 125 | | ``queryitemencoder``. |
|---|
| 126 | | |
|---|
| 127 | | If both ``responseitemencoder`` and ``queryitemencoder`` are either |
|---|
| 128 | | null or undefined this function short circuits to ``join_json``. |
|---|
| 129 | | |
|---|
| 130 | | ***/ |
|---|
| 131 | | |
|---|
| 132 | | if(typeof(responseitemencoder)=="undefined" || responseitemencoder == null) |
|---|
| 133 | | responseitemencoder = queryitemencoder; |
|---|
| 134 | | if(typeof(queryitemencoder)=="undefined" || queryitemencoder == null) |
|---|
| 135 | | return join_json(queryitems, responseitems); |
|---|
| 136 | | if (typeof(queryitems) == "undefined" || queryitems == null) |
|---|
| 137 | | var queryitems = []; |
|---|
| 138 | | if (typeof(responseitems) == "undefined" || responseitems == null) |
|---|
| 139 | | var responseitems = []; |
|---|
| 140 | | |
|---|
| 141 | | var querydata=""; |
|---|
| 142 | | var responsedata=""; |
|---|
| 143 | | |
|---|
| 144 | | if(queryitems.length > 0){ |
|---|
| 145 | | querydata += queryitemencoder(queryitems[0]); |
|---|
| 146 | | if(queryitems.length > 1){ |
|---|
| 147 | | for(var i=1; i < queryitems.length; i++){ |
|---|
| 148 | | querydata += "," + queryitemencoder(queryitems[i]); |
|---|
| 149 | | } |
|---|
| 150 | | } |
|---|
| 151 | | } |
|---|
| 152 | | if(responseitems.length > 0){ |
|---|
| 153 | | responsedata += responseitemencoder(responseitems[0]); |
|---|
| 154 | | if(responseitems.length > 1){ |
|---|
| 155 | | for(var i=1; i < responseitems.length; i++){ |
|---|
| 156 | | responsedata += "," + responseitemencoder(responseitems[i]); |
|---|
| 157 | | } |
|---|
| 158 | | } |
|---|
| 159 | | } |
|---|
| 160 | | return "[[" + querydata + "]" + ",[" + responsedata + "]]"; |
|---|
| 161 | | } |
|---|
| 162 | | |
|---|
| 163 | | split_json = function(data) { |
|---|
| 164 | | /*** |
|---|
| 165 | | |
|---|
| 166 | | Converse of join_json(queryitems, responseitems). |
|---|
| 167 | | |
|---|
| 168 | | WARNING: uses eval, You need to decide if you trust ``data``. |
|---|
| 169 | | |
|---|
| 170 | | ``data: a json string``, assumed to describe an array with the form |
|---|
| 171 | | |
|---|
| 172 | | | [iterablequeries, iterableresponses] |
|---|
| 173 | | | |
|---|
| 174 | | | [[[queryid1,data1], ... [queryidN,dataN]], |
|---|
| 175 | | | [[responseid1,data1], ... [responseidN,dataN]]] |
|---|
| 176 | | |
|---|
| 177 | | |
|---|
| 178 | | |
|---|
| 179 | | ``rtype: Iter`` |
|---|
| 180 | | |
|---|
| 181 | | ***/ |
|---|
| 182 | | |
|---|
| 183 | | if (typeof(data) == "undefined" || data == null){ |
|---|
| 184 | | return [iter([]), iter([])]; |
|---|
| 185 | | } |
|---|
| 186 | | return eval(data); |
|---|
| 187 | | }; |
|---|
| 188 | | |
|---|
| 189 | | /***split_json_decodeitems |
|---|
| 190 | | |
|---|
| 191 | | don't think it makes sense to provide 'split_json_decodeitems' as it |
|---|
| 192 | | would be highly sensitive to different ``join_json_encodeitems`` |
|---|
| 193 | | encoding schemes. If you can't use end to end json, or, more |
|---|
| 194 | | importantly, you decide not to trust eval, then you need to write |
|---|
| 195 | | a custom split for your protocol implementation. |
|---|
| 196 | | |
|---|
| 197 | | ***/ |
|---|
| 198 | | |
|---|
| 199 | | |
|---|
| 200 | | prepare_protocol = function (self, servicepath, |
|---|
| 201 | | dispatchparametername, names, values, sdpp){ |
|---|
| 202 | | if(self == null) |
|---|
| 203 | | self=this; |
|---|
| 204 | | if(typeof(self)=="undefined") |
|---|
| 205 | | self={}; |
|---|
| 206 | | |
|---|
| 207 | | if(typeof(dispatchparametername) == "undefined" || |
|---|
| 208 | | dispatchparametername==null) |
|---|
| 209 | | dispatchparametername="dispatcher"; |
|---|
| 210 | | self.dispatchparametername=dispatchparametername; |
|---|
| 211 | | |
|---|
| 212 | | if(typeof(names) == "undefined" || names==null){ |
|---|
| 213 | | self.queryparameters=parseQueryString( |
|---|
| 214 | | queryString([self.dispatchparametername],["[[],[]]"]), true); |
|---|
| 215 | | /*log("***: self.queryparameters = " + |
|---|
| 216 | | serializeJSON(self.queryparameters));*/ |
|---|
| 217 | | } else { |
|---|
| 218 | | /* normalize parameter representation */ |
|---|
| 219 | | self.queryparameters=parseQueryString(queryString( |
|---|
| 220 | | names, values), true); |
|---|
| 221 | | log("***: self.queryparameters = " + serializeJSON(self.queryparameters)); |
|---|
| 222 | | /* if there is a collision the first element of user specified |
|---|
| 223 | | value is clobbered */ |
|---|
| 224 | | if(typeof(self.queryparameters[self.dispatchparametername]) != "undefined"){ |
|---|
| 225 | | self.queryparameters[self.dispatchparametername][0]="[[],[]]" |
|---|
| 226 | | } |
|---|
| 227 | | else{ |
|---|
| 228 | | self.queryparameters[self.dispatchparametername]=["[[],[]]"]; |
|---|
| 229 | | } |
|---|
| 230 | | } |
|---|
| 231 | | |
|---|
| 232 | | if(typeof(sdpp)=="undefined" || sdpp == null){ |
|---|
| 233 | | self.sdpp=split_schemedomainandport(); |
|---|
| 234 | | } else { |
|---|
| 235 | | self.sdpp = sdpp; |
|---|
| 236 | | } |
|---|
| 237 | | self.baseurl=replace_schemedomainandport_path(self.sdpp, servicepath); |
|---|
| 238 | | self.sdpp[3]=servicepath; |
|---|
| 239 | | |
|---|
| 240 | | /* If interval is null or undefined, the Dispatcher uses its own value. |
|---|
| 241 | | Otherwise it uses this one. */ |
|---|
| 242 | | |
|---|
| 243 | | return self; |
|---|
| 244 | | } |
|---|
| 245 | | |
|---|
| 246 | | XMLHttpRequestProtocol = function (servicepath, |
|---|
| | 337 | |
|---|
| | 338 | |
|---|
| | 339 | |
|---|
| | 340 | }); |
|---|
| | 341 | |
|---|
| | 342 | streamservice.XMLHttpRequestProtocol = function (servicepath, |
|---|
| 254 | | |
|---|
| 255 | | XMLHttpRequestProtocol.prototype.response_error = function(err) { |
|---|
| 256 | | throw err; |
|---|
| 257 | | } |
|---|
| 258 | | |
|---|
| 259 | | XMLHttpRequestProtocol.prototype.poll = function(queryitems, replyitems){ |
|---|
| 260 | | |
|---|
| 261 | | var data = join_json(queryitems, replyitems); |
|---|
| 262 | | |
|---|
| 263 | | try{ |
|---|
| 264 | | this.req.abort(); /* this should allways be benign, the |
|---|
| 265 | | dispatcher doesn't start the next poll until the current |
|---|
| 266 | | poll returns some result or error status */ |
|---|
| 267 | | |
|---|
| 268 | | /* TODO: do I need to care more about sizeof character ? |
|---|
| 269 | | currently assuming sizeof("foo"[0]) <= 2 |
|---|
| 270 | | so if data is unicode we will definitely post |
|---|
| 271 | | if numbytes(data) >= 512 */ |
|---|
| 272 | | |
|---|
| 273 | | var method="GET"; |
|---|
| 274 | | if (data.length >= 128) |
|---|
| 275 | | method="POST"; |
|---|
| 276 | | this.queryparameters[this.dispatchparametername][0]=data |
|---|
| 277 | | var url = this.baseurl + "?" + queryString(this.queryparameters); |
|---|
| 278 | | |
|---|
| 279 | | log("###: POLLING = " + |
|---|
| 280 | | this.queryparameters[this.dispatchparametername][0]); |
|---|
| 281 | | |
|---|
| 282 | | /*log("###: queryitems = " + serializeJSON(queryitems)); |
|---|
| 283 | | log("###: url = " + url);*/ |
|---|
| 284 | | this.queryparameters[this.dispatchparametername][0]="[[][]]"; |
|---|
| 285 | | |
|---|
| 286 | | /* reusing the same request object */ |
|---|
| 287 | | this.req.open(method, url, true); |
|---|
| 288 | | |
|---|
| 289 | | var getresult = function(req){ |
|---|
| 290 | | log("***: req.responseText = " + req.responseText); |
|---|
| 291 | | /* |
|---|
| 292 | | log("***: evalJSONRequest(req) = " + evalJSONRequest(req)); |
|---|
| 293 | | log("***: split_json(req.responseText) = " + split_json( |
|---|
| 294 | | req.responseText));*/ |
|---|
| 295 | | /*return split_json(req.responseText);*/ |
|---|
| 296 | | return evalJSONRequest(req); |
|---|
| 297 | | } |
|---|
| 298 | | return sendXMLHttpRequest(this.req).addCallbacks( |
|---|
| 299 | | getresult, this.response_error); |
|---|
| 300 | | } catch (e){ |
|---|
| 301 | | log("***: error polling " + repr(e)); |
|---|
| 302 | | return fail(e).addBoth(this.response_error); |
|---|
| | 350 | streamservice.XMLHttpRequestProtocol.prototype = { |
|---|
| | 351 | response_error : function(err) { |
|---|
| | 352 | throw err; |
|---|
| | 353 | }, |
|---|
| | 354 | |
|---|
| | 355 | poll : function(queryitems, replyitems){ |
|---|
| | 356 | |
|---|
| | 357 | var data = streamservice.join_json(queryitems, replyitems); |
|---|
| | 358 | |
|---|
| | 359 | try{ |
|---|
| | 360 | this.req.abort(); /* this should allways be benign, the |
|---|
| | 361 | dispatcher doesn't start the next poll until the current |
|---|
| | 362 | poll returns some result or error status */ |
|---|
| | 363 | |
|---|
| | 364 | /* TODO: do I need to care more about sizeof character ? |
|---|
| | 365 | currently assuming sizeof("foo"[0]) <= 2 |
|---|
| | 366 | so if data is unicode we will definitely post |
|---|
| | 367 | if numbytes(data) >= 512 */ |
|---|
| | 368 | |
|---|
| | 369 | var method="GET"; |
|---|
| | 370 | if (data.length >= 128) |
|---|
| | 371 | method="POST"; |
|---|
| | 372 | this.queryparameters[this.dispatchparametername][0]=data |
|---|
| | 373 | var url = this.baseurl + "?" + queryString(this.queryparameters); |
|---|
| | 374 | |
|---|
| | 375 | log("###: POLLING = " + |
|---|
| | 376 | this.queryparameters[this.dispatchparametername][0]); |
|---|
| | 377 | |
|---|
| | 378 | /*log("###: queryitems = " + serializeJSON(queryitems)); |
|---|
| | 379 | log("###: url = " + url);*/ |
|---|
| | 380 | this.queryparameters[this.dispatchparametername][0]="[[][]]"; |
|---|
| | 381 | |
|---|
| | 382 | /* reusing the same request object */ |
|---|
| | 383 | this.req.open(method, url, true); |
|---|
| | 384 | |
|---|
| | 385 | var getresult = function(req){ |
|---|
| | 386 | log("***: req.responseText = " + req.responseText); |
|---|
| | 387 | /* |
|---|
| | 388 | log("***: evalJSONRequest(req) = " + evalJSONRequest(req)); |
|---|
| | 389 | log("***: split_json(req.responseText) = " + split_json( |
|---|
| | 390 | req.responseText));*/ |
|---|
| | 391 | /*return split_json(req.responseText);*/ |
|---|
| | 392 | return evalJSONRequest(req); |
|---|
| | 393 | } |
|---|
| | 394 | return sendXMLHttpRequest(this.req).addCallbacks( |
|---|
| | 395 | getresult, this.response_error); |
|---|
| | 396 | } catch (e){ |
|---|
| | 397 | log("***: error polling " + repr(e)); |
|---|
| | 398 | return fail(e).addBoth(this.response_error); |
|---|
| | 399 | } |
|---|
| 581 | | poll_loopback_json = function( |
|---|
| 582 | | clientdata, |
|---|
| 583 | | latency, |
|---|
| 584 | | emulatedbackendpollresult, |
|---|
| 585 | | ignoreemulatedresponses){ |
|---|
| 586 | | /*** |
|---|
| 587 | | |
|---|
| 588 | | **Loopback implementation for** ``Protocol.poll``. |
|---|
| 589 | | |
|---|
| 590 | | Provided for the benefit of test code. Echos query items, encoded in |
|---|
| 591 | | clientdata, as the loopbackresult. |
|---|
| 592 | | |
|---|
| 593 | | ``clientdata: the serialized and encoded queries & responses`` to |
|---|
| 594 | | submit on the clients behalf. response items in ``clientdata`` |
|---|
| 595 | | are silently ignored. |
|---|
| 596 | | |
|---|
| 597 | | ``latency: how long the poll should take``. the default is 0. *Note* |
|---|
| 598 | | that latency <= 0 is special, it forces synchronous behaviour. |
|---|
| 599 | | |
|---|
| 600 | | ``emulatedbackendpollresult: emulated backend responses``, Serialized |
|---|
| 601 | | and encoded queries & responses fake response to this poll. By |
|---|
| 602 | | default, response items are not included in the items looped back |
|---|
| 603 | | to the client. |
|---|
| 604 | | |
|---|
| 605 | | ``ignoreemulatedresponses: Don't throw away emulated responses``. if this |
|---|
| 606 | | parameter is true then emulated backend responses are included in the |
|---|
| 607 | | loopback result. |
|---|
| 608 | | |
|---|
| 609 | | if latency was zero or unspecified the returned |
|---|
| 610 | | deferred has allready been fired.:: |
|---|
| 611 | | |
|---|
| 612 | | if latency unspecified or latency <= 0 |
|---|
| 613 | | returns succede(loopbackresult) |
|---|
| 614 | | Otherwise: |
|---|
| 615 | | wait(latency, loopbackresult) |
|---|
| 616 | | |
|---|
| 617 | | ``rtype: Deferred`` |
|---|
| 618 | | |
|---|
| 619 | | ***/ |
|---|
| 620 | | |
|---|
| 621 | | if(typeof(latency)=="undefined" || latency==null){ |
|---|
| 622 | | latency=0; |
|---|
| 623 | | } |
|---|
| 624 | | try{ |
|---|
| 625 | | /*log("***:" + clientdata);*/ |
|---|
| 626 | | var sent = split_json(clientdata); |
|---|
| 627 | | var recvd = [null,null]; |
|---|
| 628 | | if( typeof(emulatedbackendpollresult)!="undefined" && |
|---|
| 629 | | emulatedbackendpollresult != null){ |
|---|
| 630 | | /*log("***:" + emulatedbackendpollresult); |
|---|
| 631 | | log("***:" + typeof(emulatedbackendpollresult));*/ |
|---|
| 632 | | recvd = split_json(emulatedbackendpollresult); |
|---|
| 633 | | if(ignoreemulatedresponses != false) |
|---|
| 634 | | recvd = [recvd[0],null]; |
|---|
| 635 | | } |
|---|
| 636 | | /* log("***:" + serializeJSON(recvd)); */ |
|---|
| 637 | | var result = join_json(recvd[0], sent[0]); |
|---|
| 638 | | if(recvd[1] != null){ |
|---|
| 639 | | /* merge the emulated responses in *before* the looped back |
|---|
| 640 | | responses */ |
|---|
| 641 | | result = split_json(result); |
|---|
| 642 | | result = join_json(result[0], extend(recvd[1], result[1])); |
|---|
| 643 | | } |
|---|
| 644 | | return latency <= 0 ? succeed(result) : wait(latency, result); |
|---|
| 645 | | } catch (result){ |
|---|
| 646 | | log("loopback raised:" + result); |
|---|
| 647 | | waitfail = function(seconds, value){ |
|---|
| 648 | | var d = wait(seconds); |
|---|
| 649 | | d.addBoth(partial(function (value){throw value;}, value)); |
|---|
| 650 | | return d; |
|---|
| 651 | | } |
|---|
| 652 | | return latency <= 0 ? fail(result) : waitfail(latency, result); |
|---|
| 653 | | } |
|---|
| 654 | | }; |
|---|
| | 671 | |
|---|