Wentao Shang | c0311e5 | 2012-12-03 10:38:23 -0800 | [diff] [blame] | 1 | /** |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 2 | * @author: Wentao Shang |
| 3 | * See COPYING for copyright and distribution information. |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 4 | */ |
| 5 | |
| 6 | var WebSocketTransport = function WebSocketTransport() { |
| 7 | this.ws = null; |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 8 | this.maxBufferSize = 10000; // Currently support 10000 bytes data input, consistent with BinaryXMLEncoder |
| 9 | this.buffer = new Uint8Array(this.maxBufferSize); |
Wentao Shang | 2b740e6 | 2012-12-07 00:02:53 -0800 | [diff] [blame] | 10 | this.bufferOffset = 0; |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 11 | this.structureDecoder = new BinaryXMLStructureDecoder(); |
Jeff Thompson | c881b55 | 2012-12-14 01:29:12 -0800 | [diff] [blame] | 12 | this.defaultGetHostAndPort = NDN.makeShuffledGetHostAndPort |
| 13 | (["A.ws.ndn.ucla.edu", "B.ws.ndn.ucla.edu", "C.ws.ndn.ucla.edu", "D.ws.ndn.ucla.edu", |
| 14 | "E.ws.ndn.ucla.edu"], |
| 15 | 9696); |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 16 | }; |
| 17 | |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 18 | WebSocketTransport.prototype.connectWebSocket = function(ndn) { |
| 19 | if (this.ws != null) |
| 20 | delete this.ws; |
| 21 | |
| 22 | this.ws = new WebSocket('ws://' + ndn.host + ':' + ndn.port); |
Jeff Thompson | 3c26381 | 2012-12-01 17:20:28 -0800 | [diff] [blame] | 23 | if (LOG > 0) console.log('ws connection created.'); |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 24 | |
| 25 | this.ws.binaryType = "arraybuffer"; |
| 26 | |
| 27 | var self = this; |
| 28 | this.ws.onmessage = function(ev) { |
| 29 | var result = ev.data; |
| 30 | //console.log('RecvHandle called.'); |
| 31 | |
| 32 | if(result == null || result == undefined || result == "" ) { |
| 33 | console.log('INVALID ANSWER'); |
| 34 | } else if (result instanceof ArrayBuffer) { |
| 35 | var bytearray = new Uint8Array(result); |
| 36 | |
Jeff Thompson | 13c2e7b | 2012-12-01 17:33:30 -0800 | [diff] [blame] | 37 | if (LOG>3) console.log('BINARY RESPONSE IS ' + DataUtils.toHex(bytearray)); |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 38 | |
| 39 | try { |
Wentao Shang | 2b740e6 | 2012-12-07 00:02:53 -0800 | [diff] [blame] | 40 | if (bytearray.length + self.bufferOffset >= self.buffer.byteLength) { |
| 41 | if (LOG>3) { |
| 42 | console.log("NDN.ws.onmessage: buffer overflow. Accumulate received length: " + self.bufferOffset |
| 43 | + ". Current packet length: " + bytearray.length + "."); |
| 44 | } |
| 45 | |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 46 | // Purge and quit. |
| 47 | delete self.structureDecoder; |
| 48 | delete self.buffer; |
| 49 | self.structureDecoder = new BinaryXMLStructureDecoder(); |
| 50 | self.buffer = new Uint8Array(self.maxBufferSize); |
Wentao Shang | 2b740e6 | 2012-12-07 00:02:53 -0800 | [diff] [blame] | 51 | self.bufferOffset = 0; |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 52 | return; |
| 53 | } |
| 54 | |
| 55 | /*for (var i = 0; i < bytearray.length; i++) { |
| 56 | self.buffer.push(bytearray[i]); |
| 57 | }*/ |
Wentao Shang | 2b740e6 | 2012-12-07 00:02:53 -0800 | [diff] [blame] | 58 | self.buffer.set(bytearray, self.bufferOffset); |
| 59 | self.bufferOffset += bytearray.length; |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 60 | |
Wentao Shang | 2b740e6 | 2012-12-07 00:02:53 -0800 | [diff] [blame] | 61 | if (!self.structureDecoder.findElementEnd(self.buffer.subarray(0, self.bufferOffset))) { |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 62 | // Need more data to decode |
Wentao Shang | 2b740e6 | 2012-12-07 00:02:53 -0800 | [diff] [blame] | 63 | if (LOG>3) console.log('Incomplete packet received. Length ' + bytearray.length + '. Wait for more input.'); |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 64 | return; |
| 65 | } |
Wentao Shang | 2b740e6 | 2012-12-07 00:02:53 -0800 | [diff] [blame] | 66 | if (LOG>3) console.log('Complete packet received. Length ' + bytearray.length + '. Start decoding.'); |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 67 | } catch (ex) { |
| 68 | console.log("NDN.ws.onmessage exception: " + ex); |
| 69 | return; |
| 70 | } |
| 71 | |
Jeff Thompson | 75771cb | 2013-01-20 23:27:38 -0800 | [diff] [blame^] | 72 | ndn.onReceivedElement(self.buffer); |
| 73 | |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 74 | // Renew StrcutureDecoder and buffer after we process a full packet |
| 75 | delete self.structureDecoder; |
| 76 | delete self.buffer; |
| 77 | self.structureDecoder = new BinaryXMLStructureDecoder(); |
| 78 | self.buffer = new Uint8Array(self.maxBufferSize); |
Wentao Shang | 2b740e6 | 2012-12-07 00:02:53 -0800 | [diff] [blame] | 79 | self.bufferOffset = 0; |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 80 | } |
| 81 | } |
| 82 | |
| 83 | this.ws.onopen = function(ev) { |
Jeff Thompson | 3c26381 | 2012-12-01 17:20:28 -0800 | [diff] [blame] | 84 | if (LOG > 3) console.log(ev); |
| 85 | if (LOG > 3) console.log('ws.onopen: WebSocket connection opened.'); |
| 86 | if (LOG > 3) console.log('ws.onopen: ReadyState: ' + this.readyState); |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 87 | |
| 88 | // Fetch ccndid now |
Wentao Shang | e0d7f05 | 2013-01-05 16:37:02 -0800 | [diff] [blame] | 89 | var interest = new Interest(NDN.ccndIdFetcher); |
Jeff Thompson | 42806a1 | 2012-12-29 18:19:39 -0800 | [diff] [blame] | 90 | interest.interestLifetime = 4000; // milliseconds |
Jeff Thompson | 75771cb | 2013-01-20 23:27:38 -0800 | [diff] [blame^] | 91 | this.send(encodeToBinaryInterest(interest)); |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | this.ws.onerror = function(ev) { |
| 95 | console.log('ws.onerror: ReadyState: ' + this.readyState); |
| 96 | console.log(ev); |
| 97 | console.log('ws.onerror: WebSocket error: ' + ev.data); |
| 98 | } |
| 99 | |
| 100 | this.ws.onclose = function(ev) { |
| 101 | console.log('ws.onclose: WebSocket connection closed.'); |
| 102 | self.ws = null; |
Wentao Shang | 0e291c8 | 2012-12-02 23:36:29 -0800 | [diff] [blame] | 103 | |
| 104 | // Close NDN when WebSocket is closed |
| 105 | ndn.readyStatus = NDN.CLOSED; |
| 106 | ndn.onclose(); |
Wentao Shang | af25c6b | 2012-12-03 00:09:30 -0800 | [diff] [blame] | 107 | //console.log("NDN.onclose event fired."); |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 108 | } |
Jeff Thompson | be85be6 | 2012-12-13 22:32:01 -0800 | [diff] [blame] | 109 | }; |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 110 | |
Jeff Thompson | 75771cb | 2013-01-20 23:27:38 -0800 | [diff] [blame^] | 111 | /* |
| 112 | * Send the Uint8Array data. |
| 113 | */ |
| 114 | WebSocketTransport.prototype.send = function(data) { |
Wentao Shang | c0311e5 | 2012-12-03 10:38:23 -0800 | [diff] [blame] | 115 | if (this.ws != null) { |
Jeff Thompson | 75771cb | 2013-01-20 23:27:38 -0800 | [diff] [blame^] | 116 | // If we directly use data.buffer to feed ws.send(), |
| 117 | // WebSocket may end up sending a packet with 10000 bytes of data. |
| 118 | // That is, WebSocket will flush the entire buffer |
| 119 | // regardless of the offset of the Uint8Array. So we have to create |
| 120 | // a new Uint8Array buffer with just the right size and copy the |
| 121 | // content from binaryInterest to the new buffer. |
| 122 | // ---Wentao |
| 123 | var bytearray = new Uint8Array(data.length); |
| 124 | bytearray.set(data); |
| 125 | this.ws.send(bytearray.buffer); |
Wentao Shang | c0311e5 | 2012-12-03 10:38:23 -0800 | [diff] [blame] | 126 | if (LOG > 3) console.log('ws.send() returned.'); |
Wentao Shang | c0311e5 | 2012-12-03 10:38:23 -0800 | [diff] [blame] | 127 | } |
| 128 | else |
| 129 | console.log('WebSocket connection is not established.'); |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 130 | } |
| 131 | |
Jeff Thompson | 75771cb | 2013-01-20 23:27:38 -0800 | [diff] [blame^] | 132 | WebSocketTransport.prototype.expressInterest = function(ndn, interest, closure) { |
| 133 | if (ndn.readyStatus != NDN.OPENED) { |
| 134 | console.log('Connection is not established.'); |
| 135 | return; |
| 136 | } |
| 137 | |
| 138 | //TODO: check local content store first |
| 139 | if (closure != null) { |
| 140 | var pitEntry = new PITEntry(interest, closure); |
| 141 | // TODO: This needs to be a single thread-safe transaction on a global object. |
| 142 | NDN.PITTable.push(pitEntry); |
| 143 | closure.pitEntry = pitEntry; |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 144 | } |
Jeff Thompson | 75771cb | 2013-01-20 23:27:38 -0800 | [diff] [blame^] | 145 | |
| 146 | // Set interest timer |
| 147 | if (closure != null) { |
| 148 | pitEntry.timerID = setTimeout(function() { |
| 149 | if (LOG > 3) console.log("Interest time out."); |
| 150 | |
| 151 | // Remove PIT entry from NDN.PITTable. |
| 152 | // TODO: Make this a thread-safe operation on the global PITTable. |
| 153 | var index = NDN.PITTable.indexOf(pitEntry); |
| 154 | //console.log(NDN.PITTable); |
| 155 | if (index >= 0) |
| 156 | NDN.PITTable.splice(index, 1); |
| 157 | //console.log(NDN.PITTable); |
| 158 | //console.log(pitEntry.interest.name.getName()); |
| 159 | |
| 160 | // Raise closure callback |
| 161 | closure.upcall(Closure.UPCALL_INTEREST_TIMED_OUT, new UpcallInfo(ndn, interest, 0, null)); |
| 162 | }, interest.interestLifetime); // interestLifetime is in milliseconds. |
| 163 | //console.log(closure.timerID); |
| 164 | } |
| 165 | |
| 166 | this.send(encodeToBinaryInterest(interest)); |
Jeff Thompson | be85be6 | 2012-12-13 22:32:01 -0800 | [diff] [blame] | 167 | }; |
Jeff Thompson | 5b265a7 | 2012-11-12 01:13:08 -0800 | [diff] [blame] | 168 | |