11d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman/* 21d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg HartmanCopyright 2012 Google Inc. 31d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 41d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg HartmanLicensed under the Apache License, Version 2.0 (the "License"); 51d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartmanyou may not use this file except in compliance with the License. 61d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg HartmanYou may obtain a copy of the License at 71d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 81d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman http://www.apache.org/licenses/LICENSE-2.0 91d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 101d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg HartmanUnless required by applicable law or agreed to in writing, software 111d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartmandistributed under the License is distributed on an "AS IS" BASIS, 121d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg HartmanWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg HartmanSee the License for the specific language governing permissions and 141d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartmanlimitations under the License. 151d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 161d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg HartmanAuthor: Boris Smus (smus@chromium.org) 171d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman*/ 181d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 191d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman(function(exports) { 201d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 211d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Define some local variables here. 221d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var socket = chrome.socket || chrome.experimental.socket; 231d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var dns = chrome.experimental.dns; 241d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 251d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 261d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Creates an instance of the client 271d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 281d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {String} host The remote host to connect to 291d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {Number} port The port to connect to at the remote host 301d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 311d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman function TcpClient(host, port, pollInterval) { 321d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.host = host; 331d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.port = port; 341d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.pollInterval = pollInterval || 15; 351d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 361d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Callback functions. 371d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.callbacks = { 381d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman connect: null, // Called when socket is connected. 391d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman disconnect: null, // Called when socket is disconnected. 401d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman recvBuffer: null, // Called (as ArrayBuffer) when client receives data from server. 411d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman recvString: null, // Called (as string) when client receives data from server. 421d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman sent: null // Called when client sends data to server. 431d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 441d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 451d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Socket. 461d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.socketId = null; 471d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.isConnected = false; 481d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 491d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman log('initialized tcp client'); 501d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 511d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 521d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 531d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Connects to the TCP socket, and creates an open socket. 541d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 551d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @see http://developer.chrome.com/trunk/apps/socket.html#method-create 561d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {Function} callback The function to call on connection 571d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 581d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TcpClient.prototype.connect = function(callback) { 591d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // First resolve the hostname to an IP. 601d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman dns.resolve(this.host, function(result) { 611d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.addr = result.address; 621d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman socket.create('tcp', {}, this._onCreate.bind(this)); 631d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 641d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Register connect callback. 651d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.callbacks.connect = callback; 661d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }.bind(this)); 671d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 681d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 691d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 701d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Sends an arraybuffer/view down the wire to the remote side 711d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 721d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @see http://developer.chrome.com/trunk/apps/socket.html#method-write 731d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {String} msg The arraybuffer/view to send 741d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {Function} callback The function to call when the message has sent 751d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 761d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TcpClient.prototype.sendBuffer = function(buf, callback) { 771d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (buf.buffer) { 781d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman buf = buf.buffer; 791d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 801d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 811d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /* 821d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Debug 831d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var bytes = [], u8 = new Uint8Array(buf); 841d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman for (var i = 0; i < u8.length; i++) { 851d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman bytes.push(u8[i]); 861d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 871d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman log("sending bytes: " + (bytes.join(','))); 881d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 891d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 901d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman socket.write(this.socketId, buf, this._onWriteComplete.bind(this)); 911d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 921d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Register sent callback. 931d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.callbacks.sent = callback; 941d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 951d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 961d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 971d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Sends a string down the wire to the remote side 981d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 991d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @see http://developer.chrome.com/trunk/apps/socket.html#method-write 1001d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {String} msg The string to send 1011d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {Function} callback The function to call when the message has sent 1021d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 1031d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TcpClient.prototype.sendString = function(msg, callback) { 1041d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /* 1051d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Debug 1061d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman log("sending string: " + msg); 1071d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 1081d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1091d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._stringToArrayBuffer(msg, function(arrayBuffer) { 1101d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman socket.write(this.socketId, arrayBuffer, this._onWriteComplete.bind(this)); 1111d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }.bind(this)); 1121d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1131d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Register sent callback. 1141d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.callbacks.sent = callback; 1151d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 1161d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1171d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 1181d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Sets the callback for when a message is received 1191d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 1201d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {Function} callback The function to call when a message has arrived 1211d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {String} type The callback argument type: "arraybuffer" or "string" 1221d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 1231d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TcpClient.prototype.addResponseListener = function(callback, type) { 1241d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (typeof type === "undefined") { 1251d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman type = "arraybuffer"; 1261d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 1271d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Register received callback. 1281d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (type === "string") { 1291d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.callbacks.recvString = callback; 1301d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } else { 1311d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.callbacks.recvBuffer = callback; 1321d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 1331d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 1341d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1351d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 1361d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Sets the callback for when the socket disconnects 1371d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 1381d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {Function} callback The function to call when the socket disconnects 1391d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {String} type The callback argument type: "arraybuffer" or "string" 1401d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 1411d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TcpClient.prototype.addDisconnectListener = function(callback) { 1421d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Register disconnect callback. 1431d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.callbacks.disconnect = callback; 1441d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 1451d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1461d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 1471d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Disconnects from the remote side 1481d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 1491d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @see http://developer.chrome.com/trunk/apps/socket.html#method-disconnect 1501d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 1511d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TcpClient.prototype.disconnect = function() { 1521d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this.isConnected) { 1531d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.isConnected = false; 1541d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman socket.disconnect(this.socketId); 1551d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this.callbacks.disconnect) { 1561d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.callbacks.disconnect(); 1571d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 1581d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman log('socket disconnected'); 1591d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 1601d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 1611d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1621d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 1631d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * The callback function used for when we attempt to have Chrome 1641d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * create a socket. If the socket is successfully created 1651d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * we go ahead and connect to the remote side. 1661d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 1671d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @private 1681d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @see http://developer.chrome.com/trunk/apps/socket.html#method-connect 1691d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {Object} createInfo The socket details 1701d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 1711d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TcpClient.prototype._onCreate = function(createInfo) { 1721d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.socketId = createInfo.socketId; 1731d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this.socketId > 0) { 1741d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman socket.connect(this.socketId, this.addr, this.port, this._onConnectComplete.bind(this)); 1751d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } else { 1761d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman error('Unable to create socket'); 1771d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 1781d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 1791d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1801d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 1811d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * The callback function used for when we attempt to have Chrome 1821d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * connect to the remote side. If a successful connection is 1831d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * made then polling starts to check for data to read 1841d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 1851d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @private 1861d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {Number} resultCode Indicates whether the connection was successful 1871d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 1881d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TcpClient.prototype._onConnectComplete = function(resultCode) { 1891d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Start polling for reads. 1901d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.isConnected = true; 1911d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman setTimeout(this._periodicallyRead.bind(this), this.pollInterval); 1921d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 1931d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this.callbacks.connect) { 1941d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman log('connect complete'); 1951d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.callbacks.connect(); 1961d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 1971d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman log('onConnectComplete'); 1981d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 1991d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2001d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 2011d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Checks for new data to read from the socket 2021d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 2031d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @see http://developer.chrome.com/trunk/apps/socket.html#method-read 2041d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 2051d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TcpClient.prototype._periodicallyRead = function() { 2061d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var that = this; 2071d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman socket.getInfo(this.socketId, function (info) { 2081d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (info.connected) { 2091d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman setTimeout(that._periodicallyRead.bind(that), that.pollInterval); 2101d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman socket.read(that.socketId, null, that._onDataRead.bind(that)); 2111d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } else if (that.isConnected) { 2121d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman log('socket disconnect detected'); 2131d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman that.disconnect(); 2141d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 2151d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }); 2161d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 2171d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2181d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 2191d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Callback function for when data has been read from the socket. 2201d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Converts the array buffer that is read in to a string 2211d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * and sends it on for further processing by passing it to 2221d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * the previously assigned callback function. 2231d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 2241d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @private 2251d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @see TcpClient.prototype.addResponseListener 2261d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {Object} readInfo The incoming message 2271d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 2281d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TcpClient.prototype._onDataRead = function(readInfo) { 2291d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Call received callback if there's data in the response. 2301d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (readInfo.resultCode > 0) { 2311d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman log('onDataRead'); 2321d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2331d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /* 2341d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Debug 2351d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var bytes = [], u8 = new Uint8Array(readInfo.data); 2361d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman for (var i = 0; i < u8.length; i++) { 2371d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman bytes.push(u8[i]); 2381d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 2391d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman log("received bytes: " + (bytes.join(','))); 2401d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 2411d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2421d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this.callbacks.recvBuffer) { 2431d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Return raw ArrayBuffer directly. 2441d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.callbacks.recvBuffer(readInfo.data); 2451d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 2461d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this.callbacks.recvString) { 2471d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Convert ArrayBuffer to string. 2481d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this._arrayBufferToString(readInfo.data, function(str) { 2491d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.callbacks.recvString(str); 2501d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }.bind(this)); 2511d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 2521d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2531d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Trigger another read right away 2541d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman setTimeout(this._periodicallyRead.bind(this), 0); 2551d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 2561d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 2571d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2581d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 2591d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Callback for when data has been successfully 2601d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * written to the socket. 2611d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 2621d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @private 2631d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {Object} writeInfo The outgoing message 2641d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 2651d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TcpClient.prototype._onWriteComplete = function(writeInfo) { 2661d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman log('onWriteComplete'); 2671d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman // Call sent callback. 2681d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman if (this.callbacks.sent) { 2691d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman this.callbacks.sent(writeInfo); 2701d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 2711d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 2721d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2731d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 2741d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Converts an array buffer to a string 2751d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 2761d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @private 2771d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {ArrayBuffer} buf The buffer to convert 2781d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {Function} callback The function to call when conversion is complete 2791d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 2801d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TcpClient.prototype._arrayBufferToString = function(buf, callback) { 2811d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var bb = new Blob([new Uint8Array(buf)]); 2821d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var f = new FileReader(); 2831d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman f.onload = function(e) { 2841d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman callback(e.target.result); 2851d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 2861d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman f.readAsText(bb); 2871d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 2881d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 2891d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 2901d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Converts a string to an array buffer 2911d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * 2921d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @private 2931d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {String} str The string to convert 2941d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * @param {Function} callback The function to call when conversion is complete 2951d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 2961d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman TcpClient.prototype._stringToArrayBuffer = function(str, callback) { 2971d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var bb = new Blob([str]); 2981d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman var f = new FileReader(); 2991d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman f.onload = function(e) { 3001d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman callback(e.target.result); 3011d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 3021d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman f.readAsArrayBuffer(bb); 3031d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman }; 3041d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 3051d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 3061d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Wrapper function for logging 3071d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 3081d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman function log(msg) { 3091d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman console.log(msg); 3101d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 3111d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 3121d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman /** 3131d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman * Wrapper function for error logging 3141d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman */ 3151d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman function error(msg) { 3161d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman console.error(msg); 3171d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman } 3181d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 3191d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman exports.TcpClient = TcpClient; 3201d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman 3211d80c6a8d34f59543f7df1963c22d7efa292bcb0Greg Hartman})(window); 322