]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | Copyright 2012 Google Inc. | |
3 | ||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | you may not use this file except in compliance with the License. | |
6 | You may obtain a copy of the License at | |
7 | ||
8 | http://www.apache.org/licenses/LICENSE-2.0 | |
9 | ||
10 | Unless required by applicable law or agreed to in writing, software | |
11 | distributed under the License is distributed on an "AS IS" BASIS, | |
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | See the License for the specific language governing permissions and | |
14 | limitations under the License. | |
15 | ||
16 | Author: Boris Smus (smus@chromium.org) | |
17 | */ | |
18 | ||
19 | (function(exports) { | |
20 | ||
21 | // Define some local variables here. | |
22 | var socket = chrome.socket; | |
23 | ||
24 | /** | |
25 | * Creates an instance of the client | |
26 | * | |
27 | * @param {String} host The remote host to connect to | |
28 | * @param {Number} port The port to connect to at the remote host | |
29 | */ | |
30 | function TcpClient(host, port) { | |
31 | this.host = host; | |
32 | this.port = port; | |
33 | ||
34 | // Callback functions. | |
35 | this.callbacks = { | |
36 | connect: null, // Called when socket is connected. | |
37 | disconnect: null, // Called when socket is disconnected. | |
38 | recv: null, // Called when client receives data from server. | |
39 | sent: null // Called when client sends data to server. | |
40 | }; | |
41 | ||
42 | // Socket. | |
43 | this.socketId = null; | |
44 | this.isConnected = false; | |
45 | this.pollerId = null; | |
46 | ||
47 | log('initialized tcp client'); | |
48 | } | |
49 | ||
50 | /** | |
51 | * Connects to the TCP socket, and creates an open socket. | |
52 | * | |
53 | * @see http://developer.chrome.com/apps/socket.html#method-create | |
54 | * @param {Function} callback The function to call on connection | |
55 | */ | |
56 | TcpClient.prototype.connect = function(callback) { | |
57 | socket.create('tcp', {}, this._onCreate.bind(this)); | |
58 | ||
59 | // Register connect callback. | |
60 | this.callbacks.connect = callback; | |
61 | }; | |
62 | ||
63 | /** | |
64 | * Sends a message down the wire to the remote side | |
65 | * | |
66 | * @see http://developer.chrome.com/apps/socket.html#method-write | |
67 | * @param {String} msg The message to send | |
68 | * @param {Function} callback The function to call when the message has sent | |
69 | */ | |
70 | TcpClient.prototype.sendMessage = function(msg, callback) { | |
71 | this._stringToArrayBuffer(msg + '\n', function(arrayBuffer) { | |
72 | socket.write(this.socketId, arrayBuffer, this._onWriteComplete.bind(this)); | |
73 | }.bind(this)); | |
74 | ||
75 | // Register sent callback. | |
76 | this.callbacks.sent = callback; | |
77 | }; | |
78 | ||
79 | /** | |
80 | * Sets the callback for when a message is received | |
81 | * | |
82 | * @param {Function} callback The function to call when a message has arrived | |
83 | */ | |
84 | TcpClient.prototype.addResponseListener = function(callback) { | |
85 | // Register received callback. | |
86 | this.callbacks.recv = callback; | |
87 | }; | |
88 | ||
89 | /** | |
90 | * Disconnects from the remote side | |
91 | * | |
92 | * @see http://developer.chrome.com/apps/socket.html#method-disconnect | |
93 | */ | |
94 | TcpClient.prototype.disconnect = function() { | |
95 | socket.disconnect(this.socketId); | |
96 | clearInterval(this.pollerId); | |
97 | this.pollerId = null; | |
98 | this.isConnected = false; | |
99 | }; | |
100 | ||
101 | /** | |
102 | * The callback function used for when we attempt to have Chrome | |
103 | * create a socket. If the socket is successfully created | |
104 | * we go ahead and connect to the remote side. | |
105 | * | |
106 | * @private | |
107 | * @see http://developer.chrome.com/apps/socket.html#method-connect | |
108 | * @param {Object} createInfo The socket details | |
109 | */ | |
110 | TcpClient.prototype._onCreate = function(createInfo) { | |
111 | this.socketId = createInfo.socketId; | |
112 | if (this.socketId > 0) { | |
113 | socket.connect(this.socketId, this.host, this.port, this._onConnectComplete.bind(this)); | |
114 | this.isConnected = true; | |
115 | } else { | |
116 | error('Unable to create socket'); | |
117 | } | |
118 | }; | |
119 | ||
120 | /** | |
121 | * The callback function used for when we attempt to have Chrome | |
122 | * connect to the remote side. If a successful connection is | |
123 | * made then polling starts to check for data to read | |
124 | * | |
125 | * @private | |
126 | * @param {Number} resultCode Indicates whether the connection was successful | |
127 | */ | |
128 | TcpClient.prototype._onConnectComplete = function(resultCode) { | |
129 | // Start polling for reads. | |
130 | clearInterval(this.pollerId); | |
131 | this.pollerId = setInterval(this.poll.bind(this), 500); | |
132 | ||
133 | if (this.callbacks.connect) { | |
134 | log('connect complete'); | |
135 | this.callbacks.connect(); | |
136 | } | |
137 | log('onConnectComplete'); | |
138 | }; | |
139 | ||
140 | /** | |
141 | * Checks for new data to read from the socket | |
142 | * | |
143 | * @see http://developer.chrome.com/apps/socket.html#method-read | |
144 | */ | |
145 | TcpClient.prototype.poll = function() { | |
146 | socket.read(this.socketId, null, this._onDataRead.bind(this)); | |
147 | }; | |
148 | ||
149 | /** | |
150 | * Callback function for when data has been read from the socket. | |
151 | * Converts the array buffer that is read in to a string | |
152 | * and sends it on for further processing by passing it to | |
153 | * the previously assigned callback function. | |
154 | * | |
155 | * @private | |
156 | * @see TcpClient.prototype.addResponseListener | |
157 | * @param {Object} readInfo The incoming message | |
158 | */ | |
159 | TcpClient.prototype._onDataRead = function(readInfo) { | |
160 | // Call received callback if there's data in the response. | |
161 | if (readInfo.resultCode > 0 && this.callbacks.recv) { | |
162 | log('onDataRead'); | |
163 | // Convert ArrayBuffer to string. | |
164 | this._arrayBufferToString(readInfo.data, function(str) { | |
165 | this.callbacks.recv(str); | |
166 | }.bind(this)); | |
167 | } | |
168 | }; | |
169 | ||
170 | /** | |
171 | * Callback for when data has been successfully | |
172 | * written to the socket. | |
173 | * | |
174 | * @private | |
175 | * @param {Object} writeInfo The outgoing message | |
176 | */ | |
177 | TcpClient.prototype._onWriteComplete = function(writeInfo) { | |
178 | log('onWriteComplete'); | |
179 | // Call sent callback. | |
180 | if (this.callbacks.sent) { | |
181 | this.callbacks.sent(writeInfo); | |
182 | } | |
183 | }; | |
184 | ||
185 | /** | |
186 | * Converts an array buffer to a string | |
187 | * | |
188 | * @private | |
189 | * @param {ArrayBuffer} buf The buffer to convert | |
190 | * @param {Function} callback The function to call when conversion is complete | |
191 | */ | |
192 | TcpClient.prototype._arrayBufferToString = function(buf, callback) { | |
193 | var bb = new Blob([new Uint8Array(buf)]); | |
194 | var f = new FileReader(); | |
195 | f.onload = function(e) { | |
196 | callback(e.target.result); | |
197 | }; | |
198 | f.readAsText(bb); | |
199 | }; | |
200 | ||
201 | /** | |
202 | * Converts a string to an array buffer | |
203 | * | |
204 | * @private | |
205 | * @param {String} str The string to convert | |
206 | * @param {Function} callback The function to call when conversion is complete | |
207 | */ | |
208 | TcpClient.prototype._stringToArrayBuffer = function(str, callback) { | |
209 | var bb = new Blob([str]); | |
210 | var f = new FileReader(); | |
211 | f.onload = function(e) { | |
212 | callback(e.target.result); | |
213 | }; | |
214 | f.readAsArrayBuffer(bb); | |
215 | }; | |
216 | ||
217 | /** | |
218 | * Wrapper function for logging | |
219 | */ | |
220 | function log(msg) { | |
221 | //console.log('tcp-client: ', msg); | |
222 | } | |
223 | ||
224 | /** | |
225 | * Wrapper function for error logging | |
226 | */ | |
227 | function error(msg) { | |
228 | console.error('tcp-client: ', msg); | |
229 | } | |
230 | ||
231 | exports.TcpClient = TcpClient; | |
232 | ||
233 | })(window); |