corrade-nucleus-nucleons – Blame information for rev 22

Subversion Repositories:
Rev:
Rev Author Line No. Line
22 office 1 /**
2 * Socket implementation that uses flash SocketPool class as a backend.
3 *
4 * @author Dave Longley
5 *
6 * Copyright (c) 2010-2013 Digital Bazaar, Inc.
7 */
8 var forge = require('./forge');
9 require('./util');
10  
11 // define net namespace
12 var net = module.exports = forge.net = forge.net || {};
13  
14 // map of flash ID to socket pool
15 net.socketPools = {};
16  
17 /**
18 * Creates a flash socket pool.
19 *
20 * @param options:
21 * flashId: the dom ID for the flash object element.
22 * policyPort: the default policy port for sockets, 0 to use the
23 * flash default.
24 * policyUrl: the default policy file URL for sockets (if provided
25 * used instead of a policy port).
26 * msie: true if the browser is msie, false if not.
27 *
28 * @return the created socket pool.
29 */
30 net.createSocketPool = function(options) {
31 // set default
32 options.msie = options.msie || false;
33  
34 // initialize the flash interface
35 var spId = options.flashId;
36 var api = document.getElementById(spId);
37 api.init({marshallExceptions: !options.msie});
38  
39 // create socket pool entry
40 var sp = {
41 // ID of the socket pool
42 id: spId,
43 // flash interface
44 flashApi: api,
45 // map of socket ID to sockets
46 sockets: {},
47 // default policy port
48 policyPort: options.policyPort || 0,
49 // default policy URL
50 policyUrl: options.policyUrl || null
51 };
52 net.socketPools[spId] = sp;
53  
54 // create event handler, subscribe to flash events
55 if(options.msie === true) {
56 sp.handler = function(e) {
57 if(e.id in sp.sockets) {
58 // get handler function
59 var f;
60 switch(e.type) {
61 case 'connect':
62 f = 'connected';
63 break;
64 case 'close':
65 f = 'closed';
66 break;
67 case 'socketData':
68 f = 'data';
69 break;
70 default:
71 f = 'error';
72 break;
73 }
74 /* IE calls javascript on the thread of the external object
75 that triggered the event (in this case flash) ... which will
76 either run concurrently with other javascript or pre-empt any
77 running javascript in the middle of its execution (BAD!) ...
78 calling setTimeout() will schedule the javascript to run on
79 the javascript thread and solve this EVIL problem. */
80 setTimeout(function() {sp.sockets[e.id][f](e);}, 0);
81 }
82 };
83 } else {
84 sp.handler = function(e) {
85 if(e.id in sp.sockets) {
86 // get handler function
87 var f;
88 switch(e.type) {
89 case 'connect':
90 f = 'connected';
91 break;
92 case 'close':
93 f = 'closed';
94 break;
95 case 'socketData':
96 f = 'data';
97 break;
98 default:
99 f = 'error';
100 break;
101 }
102 sp.sockets[e.id][f](e);
103 }
104 };
105 }
106 var handler = 'forge.net.socketPools[\'' + spId + '\'].handler';
107 api.subscribe('connect', handler);
108 api.subscribe('close', handler);
109 api.subscribe('socketData', handler);
110 api.subscribe('ioError', handler);
111 api.subscribe('securityError', handler);
112  
113 /**
114 * Destroys a socket pool. The socket pool still needs to be cleaned
115 * up via net.cleanup().
116 */
117 sp.destroy = function() {
118 delete net.socketPools[options.flashId];
119 for(var id in sp.sockets) {
120 sp.sockets[id].destroy();
121 }
122 sp.sockets = {};
123 api.cleanup();
124 };
125  
126 /**
127 * Creates a new socket.
128 *
129 * @param options:
130 * connected: function(event) called when the socket connects.
131 * closed: function(event) called when the socket closes.
132 * data: function(event) called when socket data has arrived,
133 * it can be read from the socket using receive().
134 * error: function(event) called when a socket error occurs.
135 */
136 sp.createSocket = function(options) {
137 // default to empty options
138 options = options || {};
139  
140 // create flash socket
141 var id = api.create();
142  
143 // create javascript socket wrapper
144 var socket = {
145 id: id,
146 // set handlers
147 connected: options.connected || function(e) {},
148 closed: options.closed || function(e) {},
149 data: options.data || function(e) {},
150 error: options.error || function(e) {}
151 };
152  
153 /**
154 * Destroys this socket.
155 */
156 socket.destroy = function() {
157 api.destroy(id);
158 delete sp.sockets[id];
159 };
160  
161 /**
162 * Connects this socket.
163 *
164 * @param options:
165 * host: the host to connect to.
166 * port: the port to connect to.
167 * policyPort: the policy port to use (if non-default), 0 to
168 * use the flash default.
169 * policyUrl: the policy file URL to use (instead of port).
170 */
171 socket.connect = function(options) {
172 // give precedence to policy URL over policy port
173 // if no policy URL and passed port isn't 0, use default port,
174 // otherwise use 0 for the port
175 var policyUrl = options.policyUrl || null;
176 var policyPort = 0;
177 if(policyUrl === null && options.policyPort !== 0) {
178 policyPort = options.policyPort || sp.policyPort;
179 }
180 api.connect(id, options.host, options.port, policyPort, policyUrl);
181 };
182  
183 /**
184 * Closes this socket.
185 */
186 socket.close = function() {
187 api.close(id);
188 socket.closed({
189 id: socket.id,
190 type: 'close',
191 bytesAvailable: 0
192 });
193 };
194  
195 /**
196 * Determines if the socket is connected or not.
197 *
198 * @return true if connected, false if not.
199 */
200 socket.isConnected = function() {
201 return api.isConnected(id);
202 };
203  
204 /**
205 * Writes bytes to this socket.
206 *
207 * @param bytes the bytes (as a string) to write.
208 *
209 * @return true on success, false on failure.
210 */
211 socket.send = function(bytes) {
212 return api.send(id, forge.util.encode64(bytes));
213 };
214  
215 /**
216 * Reads bytes from this socket (non-blocking). Fewer than the number
217 * of bytes requested may be read if enough bytes are not available.
218 *
219 * This method should be called from the data handler if there are
220 * enough bytes available. To see how many bytes are available, check
221 * the 'bytesAvailable' property on the event in the data handler or
222 * call the bytesAvailable() function on the socket. If the browser is
223 * msie, then the bytesAvailable() function should be used to avoid
224 * race conditions. Otherwise, using the property on the data handler's
225 * event may be quicker.
226 *
227 * @param count the maximum number of bytes to read.
228 *
229 * @return the bytes read (as a string) or null on error.
230 */
231 socket.receive = function(count) {
232 var rval = api.receive(id, count).rval;
233 return (rval === null) ? null : forge.util.decode64(rval);
234 };
235  
236 /**
237 * Gets the number of bytes available for receiving on the socket.
238 *
239 * @return the number of bytes available for receiving.
240 */
241 socket.bytesAvailable = function() {
242 return api.getBytesAvailable(id);
243 };
244  
245 // store and return socket
246 sp.sockets[id] = socket;
247 return socket;
248 };
249  
250 return sp;
251 };
252  
253 /**
254 * Destroys a flash socket pool.
255 *
256 * @param options:
257 * flashId: the dom ID for the flash object element.
258 */
259 net.destroySocketPool = function(options) {
260 if(options.flashId in net.socketPools) {
261 var sp = net.socketPools[options.flashId];
262 sp.destroy();
263 }
264 };
265  
266 /**
267 * Creates a new socket.
268 *
269 * @param options:
270 * flashId: the dom ID for the flash object element.
271 * connected: function(event) called when the socket connects.
272 * closed: function(event) called when the socket closes.
273 * data: function(event) called when socket data has arrived, it
274 * can be read from the socket using receive().
275 * error: function(event) called when a socket error occurs.
276 *
277 * @return the created socket.
278 */
279 net.createSocket = function(options) {
280 var socket = null;
281 if(options.flashId in net.socketPools) {
282 // get related socket pool
283 var sp = net.socketPools[options.flashId];
284 socket = sp.createSocket(options);
285 }
286 return socket;
287 };