]>
Commit | Line | Data |
---|---|---|
50dafc4c MF |
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 | ||
46 | log('initialized tcp client'); | |
47 | } | |
48 | ||
49 | /** | |
50 | * Connects to the TCP socket, and creates an open socket. | |
51 | * | |
d4a26e73 | 52 | * @see http://developer.chrome.com/apps/socket.html#method-create |
50dafc4c MF |
53 | * @param {Function} callback The function to call on connection |
54 | */ | |
55 | TcpClient.prototype.connect = function(callback) { | |
56 | socket.create('tcp', {}, this._onCreate.bind(this)); | |
57 | ||
58 | // Register connect callback. | |
59 | this.callbacks.connect = callback; | |
60 | }; | |
61 | ||
62 | /** | |
63 | * Sends a message down the wire to the remote side | |
64 | * | |
d4a26e73 | 65 | * @see http://developer.chrome.com/apps/socket.html#method-write |
50dafc4c MF |
66 | * @param {String} msg The message to send |
67 | * @param {Function} callback The function to call when the message has sent | |
68 | */ | |
69 | TcpClient.prototype.sendMessage = function(msg, callback) { | |
70 | this._stringToArrayBuffer(msg + '\n', function(arrayBuffer) { | |
71 | socket.write(this.socketId, arrayBuffer, this._onWriteComplete.bind(this)); | |
72 | }.bind(this)); | |
73 | ||
74 | // Register sent callback. | |
75 | this.callbacks.sent = callback; | |
76 | }; | |
77 | ||
78 | /** | |
79 | * Sets the callback for when a message is received | |
80 | * | |
81 | * @param {Function} callback The function to call when a message has arrived | |
82 | */ | |
83 | TcpClient.prototype.addResponseListener = function(callback) { | |
84 | // Register received callback. | |
85 | this.callbacks.recv = callback; | |
86 | }; | |
87 | ||
88 | /** | |
89 | * Disconnects from the remote side | |
90 | * | |
d4a26e73 | 91 | * @see http://developer.chrome.com/apps/socket.html#method-disconnect |
50dafc4c MF |
92 | */ |
93 | TcpClient.prototype.disconnect = function() { | |
94 | socket.disconnect(this.socketId); | |
95 | this.isConnected = false; | |
96 | }; | |
97 | ||
98 | /** | |
99 | * The callback function used for when we attempt to have Chrome | |
100 | * create a socket. If the socket is successfully created | |
101 | * we go ahead and connect to the remote side. | |
102 | * | |
103 | * @private | |
d4a26e73 | 104 | * @see http://developer.chrome.com/apps/socket.html#method-connect |
50dafc4c MF |
105 | * @param {Object} createInfo The socket details |
106 | */ | |
107 | TcpClient.prototype._onCreate = function(createInfo) { | |
108 | this.socketId = createInfo.socketId; | |
109 | if (this.socketId > 0) { | |
110 | socket.connect(this.socketId, this.host, this.port, this._onConnectComplete.bind(this)); | |
111 | this.isConnected = true; | |
112 | } else { | |
113 | error('Unable to create socket'); | |
114 | } | |
115 | }; | |
116 | ||
117 | /** | |
118 | * The callback function used for when we attempt to have Chrome | |
119 | * connect to the remote side. If a successful connection is | |
120 | * made then polling starts to check for data to read | |
121 | * | |
122 | * @private | |
123 | * @param {Number} resultCode Indicates whether the connection was successful | |
124 | */ | |
125 | TcpClient.prototype._onConnectComplete = function(resultCode) { | |
126 | // Start polling for reads. | |
0a3a435e | 127 | setInterval(this.poll.bind(this), 500); |
50dafc4c MF |
128 | |
129 | if (this.callbacks.connect) { | |
130 | log('connect complete'); | |
131 | this.callbacks.connect(); | |
132 | } | |
133 | log('onConnectComplete'); | |
134 | }; | |
135 | ||
136 | /** | |
137 | * Checks for new data to read from the socket | |
138 | * | |
d4a26e73 | 139 | * @see http://developer.chrome.com/apps/socket.html#method-read |
50dafc4c | 140 | */ |
0a3a435e | 141 | TcpClient.prototype.poll = function() { |
50dafc4c MF |
142 | socket.read(this.socketId, null, this._onDataRead.bind(this)); |
143 | }; | |
144 | ||
145 | /** | |
146 | * Callback function for when data has been read from the socket. | |
147 | * Converts the array buffer that is read in to a string | |
148 | * and sends it on for further processing by passing it to | |
149 | * the previously assigned callback function. | |
150 | * | |
151 | * @private | |
152 | * @see TcpClient.prototype.addResponseListener | |
153 | * @param {Object} readInfo The incoming message | |
154 | */ | |
155 | TcpClient.prototype._onDataRead = function(readInfo) { | |
156 | // Call received callback if there's data in the response. | |
157 | if (readInfo.resultCode > 0 && this.callbacks.recv) { | |
158 | log('onDataRead'); | |
159 | // Convert ArrayBuffer to string. | |
160 | this._arrayBufferToString(readInfo.data, function(str) { | |
161 | this.callbacks.recv(str); | |
162 | }.bind(this)); | |
163 | } | |
164 | }; | |
165 | ||
166 | /** | |
167 | * Callback for when data has been successfully | |
168 | * written to the socket. | |
169 | * | |
170 | * @private | |
171 | * @param {Object} writeInfo The outgoing message | |
172 | */ | |
173 | TcpClient.prototype._onWriteComplete = function(writeInfo) { | |
174 | log('onWriteComplete'); | |
175 | // Call sent callback. | |
176 | if (this.callbacks.sent) { | |
177 | this.callbacks.sent(writeInfo); | |
178 | } | |
179 | }; | |
180 | ||
181 | /** | |
182 | * Converts an array buffer to a string | |
183 | * | |
184 | * @private | |
185 | * @param {ArrayBuffer} buf The buffer to convert | |
186 | * @param {Function} callback The function to call when conversion is complete | |
187 | */ | |
188 | TcpClient.prototype._arrayBufferToString = function(buf, callback) { | |
189 | var bb = new Blob([new Uint8Array(buf)]); | |
190 | var f = new FileReader(); | |
191 | f.onload = function(e) { | |
192 | callback(e.target.result); | |
193 | }; | |
194 | f.readAsText(bb); | |
195 | }; | |
196 | ||
197 | /** | |
198 | * Converts a string to an array buffer | |
199 | * | |
200 | * @private | |
201 | * @param {String} str The string to convert | |
202 | * @param {Function} callback The function to call when conversion is complete | |
203 | */ | |
204 | TcpClient.prototype._stringToArrayBuffer = function(str, callback) { | |
205 | var bb = new Blob([str]); | |
206 | var f = new FileReader(); | |
207 | f.onload = function(e) { | |
208 | callback(e.target.result); | |
209 | }; | |
210 | f.readAsArrayBuffer(bb); | |
211 | }; | |
212 | ||
213 | /** | |
214 | * Wrapper function for logging | |
215 | */ | |
216 | function log(msg) { | |
217 | //console.log('tcp-client: ', msg); | |
218 | } | |
219 | ||
220 | /** | |
221 | * Wrapper function for error logging | |
222 | */ | |
223 | function error(msg) { | |
224 | console.error('tcp-client: ', msg); | |
225 | } | |
226 | ||
227 | exports.TcpClient = TcpClient; | |
228 | ||
229 | })(window); |