alchemymvc 1.2.5 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +0 -0
- package/README.md +0 -0
- package/lib/app/assets/scripts/.gitkeep +0 -0
- package/lib/app/assets/stylesheets/alchemy-info.less +0 -0
- package/lib/app/behaviour/publishable_behaviour.js +0 -0
- package/lib/app/behaviour/revision_behaviour.js +0 -0
- package/lib/app/behaviour/sluggable_behaviour.js +0 -0
- package/lib/app/component/.gitkeep +0 -0
- package/lib/app/conduit/electron_conduit.js +0 -0
- package/lib/app/conduit/http_conduit.js +173 -173
- package/lib/app/conduit/socket_conduit.js +620 -620
- package/lib/app/controller/alchemy_info_controller.js +0 -0
- package/lib/app/datasource/mongo_datasource.js +0 -0
- package/lib/app/helper/client_collection.js +0 -0
- package/lib/app/helper/pagination_helper.js +0 -0
- package/lib/app/helper/router_helper.js +0 -0
- package/lib/app/helper/socket_helper.js +613 -613
- package/lib/app/helper_component/paginate_component.js +0 -0
- package/lib/app/helper_controller/component.js +0 -0
- package/lib/app/helper_controller/conduit.js +0 -0
- package/lib/app/helper_controller/controller.js +0 -0
- package/lib/app/helper_datasource/00-nosql_datasource.js +0 -0
- package/lib/app/helper_datasource/05-fallback_datasource.js +0 -0
- package/lib/app/helper_datasource/idb_datasource.js +0 -0
- package/lib/app/helper_datasource/indexed_db.js +0 -0
- package/lib/app/helper_field/00-objectid_field.js +0 -0
- package/lib/app/helper_field/06-text_field.js +0 -0
- package/lib/app/helper_field/10-number_field.js +0 -0
- package/lib/app/helper_field/boolean_field.js +0 -0
- package/lib/app/helper_field/date_field.js +0 -0
- package/lib/app/helper_field/datetime_field.js +0 -0
- package/lib/app/helper_field/enum_field.js +0 -0
- package/lib/app/helper_field/geopoint_field.js +0 -0
- package/lib/app/helper_field/habtm_field.js +0 -0
- package/lib/app/helper_field/hasoneparent_field.js +0 -0
- package/lib/app/helper_field/html_field.js +0 -0
- package/lib/app/helper_field/integer_field.js +0 -0
- package/lib/app/helper_field/object_field.js +0 -0
- package/lib/app/helper_field/regexp_field.js +0 -0
- package/lib/app/helper_field/schema_field.js +23 -2
- package/lib/app/helper_field/time_field.js +0 -0
- package/lib/app/helper_field/url_field.js +0 -0
- package/lib/app/helper_model/criteria.js +0 -0
- package/lib/app/helper_model/db_query.js +0 -0
- package/lib/app/helper_model/document_list.js +0 -0
- package/lib/app/model/alchemy_task_model.js +0 -0
- package/lib/app/routes.js +0 -0
- package/lib/app/view/alchemy/info.ejs +0 -0
- package/lib/app/view/error/unknown.ejs +0 -0
- package/lib/app/view/paginate/navlist.ejs +0 -0
- package/lib/bootstrap.js +0 -0
- package/lib/class/behaviour.js +0 -0
- package/lib/class/component.js +0 -0
- package/lib/class/conduit.js +2555 -2552
- package/lib/class/controller.js +4 -1
- package/lib/class/document_list.js +0 -0
- package/lib/class/helper.js +0 -0
- package/lib/class/inode.js +0 -0
- package/lib/class/inode_dir.js +0 -0
- package/lib/class/inode_file.js +112 -112
- package/lib/class/inode_list.js +0 -0
- package/lib/class/model.js +1772 -1769
- package/lib/class/path_definition.js +0 -0
- package/lib/class/route.js +0 -0
- package/lib/class/session.js +0 -0
- package/lib/class/task.js +0 -0
- package/lib/core/base.js +50 -9
- package/lib/core/discovery.js +0 -0
- package/lib/core/routing.js +0 -0
- package/lib/core/socket.js +159 -159
- package/lib/init/alchemy.js +1823 -1823
- package/lib/init/constants.js +0 -0
- package/lib/init/functions.js +8 -4
- package/lib/init/load_functions.js +0 -0
- package/lib/init/requirements.js +101 -101
- package/package.json +74 -74
|
@@ -1,614 +1,614 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* See if the given object is a stream
|
|
3
|
-
*
|
|
4
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
5
|
-
* @since 0.2.0
|
|
6
|
-
* @version 1.0.5
|
|
7
|
-
*
|
|
8
|
-
* @return {Boolean}
|
|
9
|
-
*/
|
|
10
|
-
function isStream(obj) {
|
|
11
|
-
return obj && (typeof obj._read == 'function' || typeof obj._write == 'function') && typeof obj.on === 'function';
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* The Linkup class
|
|
16
|
-
*
|
|
17
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
18
|
-
* @since 0.2.0
|
|
19
|
-
* @version 0.2.0
|
|
20
|
-
*
|
|
21
|
-
* @param {String} type
|
|
22
|
-
*/
|
|
23
|
-
var Linkup = Blast.Collection.Function.inherits('Informer', function ClientLinkup(client, type, data) {
|
|
24
|
-
|
|
25
|
-
var server_object,
|
|
26
|
-
id;
|
|
27
|
-
|
|
28
|
-
if (type && typeof type == 'object' && type.id && data == null) {
|
|
29
|
-
server_object = type;
|
|
30
|
-
id = server_object.id;
|
|
31
|
-
type = server_object.type;
|
|
32
|
-
data = server_object.data;
|
|
33
|
-
} else {
|
|
34
|
-
id = type + '-' + Blast.Classes.Crypto.pseudoHex();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// The identifier
|
|
38
|
-
this.id = id;
|
|
39
|
-
|
|
40
|
-
// The typename of the link
|
|
41
|
-
this.type = type;
|
|
42
|
-
|
|
43
|
-
// The initial submitted data
|
|
44
|
-
this.initialData = data;
|
|
45
|
-
|
|
46
|
-
// Make the linkup store itself
|
|
47
|
-
client.linkups[this.id] = this;
|
|
48
|
-
|
|
49
|
-
// The parent server
|
|
50
|
-
this.client = client;
|
|
51
|
-
|
|
52
|
-
if (server_object) {
|
|
53
|
-
this.submit('ready');
|
|
54
|
-
} else {
|
|
55
|
-
// Establish the link
|
|
56
|
-
client._submit('linkup', {type: type, id: this.id, data: data});
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Submit a message to the server on this link
|
|
62
|
-
*
|
|
63
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
64
|
-
* @since 0.2.0
|
|
65
|
-
* @version 0.2.0
|
|
66
|
-
*
|
|
67
|
-
* @param {String} type
|
|
68
|
-
* @param {Object} data
|
|
69
|
-
* @param {Function} callback
|
|
70
|
-
*/
|
|
71
|
-
Linkup.setMethod(function submit(type, data, stream, callback) {
|
|
72
|
-
this.client.submit([this.id, type], data, stream, callback);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Submit a message to the server on this link and return a promise
|
|
77
|
-
*
|
|
78
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
79
|
-
* @since 1.1.2
|
|
80
|
-
* @version 1.1.2
|
|
81
|
-
*
|
|
82
|
-
* @param {String} type
|
|
83
|
-
* @param {Object} data
|
|
84
|
-
*/
|
|
85
|
-
Linkup.setMethod(function demand(type, data, stream) {
|
|
86
|
-
|
|
87
|
-
const that = this;
|
|
88
|
-
|
|
89
|
-
let pledge = new Classes.Pledge(),
|
|
90
|
-
args = [type, data];
|
|
91
|
-
|
|
92
|
-
if (stream) {
|
|
93
|
-
args.push(stream);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
this.submit(...args, function done(err, result) {
|
|
97
|
-
|
|
98
|
-
if (err) {
|
|
99
|
-
return pledge.reject(err);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
pledge.resolve(result);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
return pledge;
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Create a stream
|
|
110
|
-
*
|
|
111
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
112
|
-
* @since 0.2.0
|
|
113
|
-
* @version 0.2.0
|
|
114
|
-
*/
|
|
115
|
-
Linkup.setMethod(function createStream() {
|
|
116
|
-
return this.client.createStream();
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Destroy this linkup
|
|
121
|
-
*
|
|
122
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
123
|
-
* @since 0.2.0
|
|
124
|
-
* @version 0.2.0
|
|
125
|
-
*/
|
|
126
|
-
Linkup.setMethod(function destroy() {
|
|
127
|
-
delete this.client.linkups[this.id];
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Actually make the socket.io connection,
|
|
132
|
-
* this requires the socket.io js to be loaded
|
|
133
|
-
*
|
|
134
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
135
|
-
* @since 0.0.1
|
|
136
|
-
* @version 0.2.0
|
|
137
|
-
*
|
|
138
|
-
* @param {String} address Address to connect to
|
|
139
|
-
* @param {Object} data Announcement data
|
|
140
|
-
* @param {Function} callback
|
|
141
|
-
*/
|
|
142
|
-
var Client = Blast.Collection.Function.inherits('Informer', function ClientSocket() {
|
|
143
|
-
|
|
144
|
-
var that = this;
|
|
145
|
-
|
|
146
|
-
// Connected is false
|
|
147
|
-
this.connected = false;
|
|
148
|
-
|
|
149
|
-
// The packet queue
|
|
150
|
-
this.queue = [];
|
|
151
|
-
|
|
152
|
-
// The callbacks
|
|
153
|
-
this.callbacks = {};
|
|
154
|
-
|
|
155
|
-
// Established linkups
|
|
156
|
-
this.linkups = {};
|
|
157
|
-
|
|
158
|
-
// The client message counter
|
|
159
|
-
this.counter = 0;
|
|
160
|
-
|
|
161
|
-
// The server object
|
|
162
|
-
this.server = null;
|
|
163
|
-
|
|
164
|
-
// The server stream
|
|
165
|
-
this.serverstream = null;
|
|
166
|
-
|
|
167
|
-
// The timesync offset
|
|
168
|
-
this.offset = 0;
|
|
169
|
-
|
|
170
|
-
// The connection latency
|
|
171
|
-
this.latency = 0;
|
|
172
|
-
|
|
173
|
-
// Enable auto reconnect
|
|
174
|
-
this.reconnect = true;
|
|
175
|
-
|
|
176
|
-
// Server-linkup listeners
|
|
177
|
-
this.server_linkup_listeners = {};
|
|
178
|
-
|
|
179
|
-
this.emitPacket = function emitPacket(packet) {
|
|
180
|
-
|
|
181
|
-
var stream;
|
|
182
|
-
|
|
183
|
-
if (packet.stream) {
|
|
184
|
-
stream = packet.stream;
|
|
185
|
-
delete packet.stream;
|
|
186
|
-
that.serverstream.emit('payload', stream, packet);
|
|
187
|
-
} else {
|
|
188
|
-
that.server.emit('payload', packet);
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Get an offset-corrected timestamp
|
|
195
|
-
*
|
|
196
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
197
|
-
* @since 0.2.1
|
|
198
|
-
* @version 0.2.1
|
|
199
|
-
*
|
|
200
|
-
* @return {Number}
|
|
201
|
-
*/
|
|
202
|
-
Client.setMethod(function now() {
|
|
203
|
-
return Date.now() + (this.offset || 0);
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Low level socket emit
|
|
208
|
-
*
|
|
209
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
210
|
-
* @since 0.2.0
|
|
211
|
-
* @version 1.1.0
|
|
212
|
-
*/
|
|
213
|
-
Client.setMethod(function _submit() {
|
|
214
|
-
var that = this,
|
|
215
|
-
args = Array.cast(arguments);
|
|
216
|
-
|
|
217
|
-
this.afterOnce('connected', function connected() {
|
|
218
|
-
that.server.emit.apply(that.server, args);
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Submit method
|
|
224
|
-
*
|
|
225
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
226
|
-
* @since 0.2.0
|
|
227
|
-
* @version 0.2.0
|
|
228
|
-
*
|
|
229
|
-
* @param {String} type
|
|
230
|
-
* @param {Object} data
|
|
231
|
-
* @param {IOStream} stream
|
|
232
|
-
* @param {Function} callback
|
|
233
|
-
*/
|
|
234
|
-
Client.setMethod(function submit(type, data, stream, callback) {
|
|
235
|
-
|
|
236
|
-
var packet = {},
|
|
237
|
-
regular_stream;
|
|
238
|
-
|
|
239
|
-
if (isStream(data)) {
|
|
240
|
-
callback = stream;
|
|
241
|
-
stream = data;
|
|
242
|
-
data = undefined;
|
|
243
|
-
} else if (typeof data === 'function') {
|
|
244
|
-
callback = data;
|
|
245
|
-
data = undefined;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
if (!stream || typeof stream == 'function') {
|
|
249
|
-
callback = stream;
|
|
250
|
-
stream = undefined;
|
|
251
|
-
} else if (stream && stream.constructor.name != 'IOStream') {
|
|
252
|
-
// Keep the regular stream
|
|
253
|
-
regular_stream = stream;
|
|
254
|
-
|
|
255
|
-
// Create an IOStream
|
|
256
|
-
stream = this.createStream();
|
|
257
|
-
|
|
258
|
-
// Pipe the regular stream into the IOStream
|
|
259
|
-
regular_stream.pipe(stream);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if (Array.isArray(type)) {
|
|
263
|
-
packet.link = type[0];
|
|
264
|
-
packet.type = type[1];
|
|
265
|
-
} else {
|
|
266
|
-
packet.type = type;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if (data && data.constructor.name == 'IOStream') {
|
|
270
|
-
stream = data;
|
|
271
|
-
packet.noData = true;
|
|
272
|
-
} else {
|
|
273
|
-
packet.data = data;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
packet.id = 'c' + (++this.counter);
|
|
277
|
-
packet.stream = stream;
|
|
278
|
-
|
|
279
|
-
if (typeof callback == 'function') {
|
|
280
|
-
this.callbacks[packet.id] = callback;
|
|
281
|
-
packet.respond = true;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (this.connected) {
|
|
285
|
-
this.emitPacket(packet);
|
|
286
|
-
} else {
|
|
287
|
-
this.queue.push(packet);
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Create a stream we can send through a websocket connection
|
|
293
|
-
*
|
|
294
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
295
|
-
* @since 0.2.0
|
|
296
|
-
* @version 0.2.0
|
|
297
|
-
*/
|
|
298
|
-
Client.setMethod(function createStream() {
|
|
299
|
-
|
|
300
|
-
var stream;
|
|
301
|
-
|
|
302
|
-
if (Blast.isNode) {
|
|
303
|
-
stream = alchemy.use('socket.io-stream').createStream();
|
|
304
|
-
} else {
|
|
305
|
-
stream = ss.createStream();
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
return stream;
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Make the actual connection
|
|
313
|
-
*
|
|
314
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
315
|
-
* @since 0.2.0
|
|
316
|
-
* @version 1.0.5
|
|
317
|
-
*
|
|
318
|
-
* @param {Function} callback
|
|
319
|
-
*/
|
|
320
|
-
Client.setMethod(function connect(address, data, callback) {
|
|
321
|
-
|
|
322
|
-
var that = this,
|
|
323
|
-
ioServer,
|
|
324
|
-
serverstream,
|
|
325
|
-
config = {},
|
|
326
|
-
server;
|
|
327
|
-
|
|
328
|
-
if (typeof address == 'function') {
|
|
329
|
-
callback = address;
|
|
330
|
-
data = {};
|
|
331
|
-
address = null;
|
|
332
|
-
} else if (typeof data == 'function') {
|
|
333
|
-
callback = data;
|
|
334
|
-
data = {};
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
if (!data || typeof data != 'object') {
|
|
338
|
-
data = {};
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if (typeof io != 'undefined') {
|
|
342
|
-
ioServer = io;
|
|
343
|
-
} else if (typeof alchemy != 'undefined') {
|
|
344
|
-
ioServer = alchemy.use('socket.io-client');
|
|
345
|
-
} else {
|
|
346
|
-
return callback(new Error('Could not find socket.io client library'));
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// The address to connect to
|
|
350
|
-
this.address = address;
|
|
351
|
-
|
|
352
|
-
if (Blast.isNode) {
|
|
353
|
-
data.connection_type = 'node';
|
|
354
|
-
data.discovery = alchemy.discovery_id;
|
|
355
|
-
} else {
|
|
356
|
-
data.connection_type = 'browser';
|
|
357
|
-
data.scene = hawkejs.scene.sceneId;
|
|
358
|
-
data.last_update = alchemy.last_update;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
if (!this.reconnect) {
|
|
362
|
-
config.reconnection = false;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// Create the connection to the server
|
|
366
|
-
if (address) {
|
|
367
|
-
server = ioServer.connect(address, config);
|
|
368
|
-
} else {
|
|
369
|
-
server = ioServer.connect(config);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
if (Blast.isNode) {
|
|
373
|
-
serverstream = alchemy.use('socket.io-stream')(server);
|
|
374
|
-
} else {
|
|
375
|
-
serverstream = ss(server);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
this.server = server;
|
|
379
|
-
this.serverstream = serverstream;
|
|
380
|
-
|
|
381
|
-
// Announce ourselves when we've connected
|
|
382
|
-
server.on('connect', function onConnect() {
|
|
383
|
-
server.emit('announce', data);
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
// Emit the close event once we get disconnected from the server
|
|
387
|
-
server.on('disconnect', function closed() {
|
|
388
|
-
that.connected = false;
|
|
389
|
-
that.emit('close');
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
// Listen to timesync commands
|
|
393
|
-
server.on('timesync', function gotTimesync(data) {
|
|
394
|
-
|
|
395
|
-
// When offset is not defined,
|
|
396
|
-
// the server is actually requesting our timestamp
|
|
397
|
-
if (data.offset == null) {
|
|
398
|
-
data.client_time = Date.now();
|
|
399
|
-
server.emit('timesync', data);
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// If the offset property is set,
|
|
404
|
-
// the timesync procedure has finished
|
|
405
|
-
|
|
406
|
-
// Set the values in this object
|
|
407
|
-
that.offset = data.offset || 0;
|
|
408
|
-
that.latency = data.latency || 0;
|
|
409
|
-
|
|
410
|
-
// Emit it as an event, too
|
|
411
|
-
that.emit('timesynced', that.offset, that.latency);
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
// Listen for the ready event
|
|
415
|
-
server.on('ready', function onReady() {
|
|
416
|
-
|
|
417
|
-
that.connected = true;
|
|
418
|
-
|
|
419
|
-
if (callback) {
|
|
420
|
-
callback();
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
that.emit('connected');
|
|
424
|
-
|
|
425
|
-
// Emit all the queued packets
|
|
426
|
-
that.queue.forEach(that.emitPacket);
|
|
427
|
-
|
|
428
|
-
// Request a timesync
|
|
429
|
-
that.server.emit('timesync', {start: Date.now()});
|
|
430
|
-
|
|
431
|
-
// Reset the queue
|
|
432
|
-
that.queue.length = 0;
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
server.on('error', function(err) {
|
|
436
|
-
console.log('Socket error:', err);
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
// Listen for cookies
|
|
440
|
-
server.on('alchemy-set-cookie', function setCookie(data) {
|
|
441
|
-
if (Blast.isNode) {
|
|
442
|
-
// @TODO: set node cookie?
|
|
443
|
-
} else {
|
|
444
|
-
hawkejs.scene.cookie(data.name, data.value, data.options);
|
|
445
|
-
}
|
|
446
|
-
});
|
|
447
|
-
|
|
448
|
-
// Listen for server initiated linkups
|
|
449
|
-
server.on('linkup', function gotLinkup(config) {
|
|
450
|
-
|
|
451
|
-
var linkup = new Linkup(that, config),
|
|
452
|
-
i;
|
|
453
|
-
|
|
454
|
-
// Look through the server-linkup callbacks
|
|
455
|
-
if (that.server_linkup_listeners[config.type]) {
|
|
456
|
-
for (i = 0; i < that.server_linkup_listeners[config.type].length; i++) {
|
|
457
|
-
that.server_linkup_listeners[config.type][i].call(that, linkup, config.data);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
// Emit it on the client itself
|
|
462
|
-
that.emit(linkup.type, linkup, null);
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
// Listen for payloads
|
|
466
|
-
server.on('payload', onPacket);
|
|
467
|
-
|
|
468
|
-
// Listen for payloads with streams
|
|
469
|
-
serverstream.on('payload', function onPayload(stream, packet) {
|
|
470
|
-
packet.stream = stream;
|
|
471
|
-
onPacket(packet);
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
// Listen for responses with streams
|
|
475
|
-
serverstream.on('response', function onStreamingResponse(stream, packet) {
|
|
476
|
-
packet.stream = stream;
|
|
477
|
-
onResponse(packet);
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
// Listen for responses
|
|
481
|
-
server.on('response', onResponse);
|
|
482
|
-
|
|
483
|
-
// The function that handles responses
|
|
484
|
-
function onResponse(packet) {
|
|
485
|
-
|
|
486
|
-
if (typeof that.callbacks[packet.respond_to] === 'function') {
|
|
487
|
-
|
|
488
|
-
if (packet.err && typeof packet.err == 'object') {
|
|
489
|
-
try {
|
|
490
|
-
packet.err = JSON.undry(packet.err);
|
|
491
|
-
} catch (err) {
|
|
492
|
-
console.log('Error undrying error:', err, packet);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
try {
|
|
497
|
-
if (packet.data && typeof packet.data == 'object') {
|
|
498
|
-
packet.data = JSON.undry(packet.data);
|
|
499
|
-
}
|
|
500
|
-
} catch (err) {
|
|
501
|
-
console.log('ERROR UNDRYING PACKET:', err, packet);
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
if (packet.noData) {
|
|
506
|
-
that.callbacks[packet.respond_to](packet.err, packet.stream);
|
|
507
|
-
} else if (packet.stream) {
|
|
508
|
-
that.callbacks[packet.respond_to](packet.err, packet.data, packet.stream);
|
|
509
|
-
} else {
|
|
510
|
-
that.callbacks[packet.respond_to](packet.err, packet.data);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
delete that.callbacks[packet.respond_to];
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
// The function that handles packets
|
|
518
|
-
function onPacket(packet) {
|
|
519
|
-
|
|
520
|
-
var respond;
|
|
521
|
-
|
|
522
|
-
try {
|
|
523
|
-
if (packet.data && typeof packet.data == 'object') {
|
|
524
|
-
packet.data = JSON.undry(packet.data);
|
|
525
|
-
}
|
|
526
|
-
} catch (err) {
|
|
527
|
-
console.log('ERROR UNDRYING PACKET:', err, packet);
|
|
528
|
-
return;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
if (packet.respond) {
|
|
532
|
-
respond = function respond(err, data) {
|
|
533
|
-
var responsePacket = {};
|
|
534
|
-
|
|
535
|
-
responsePacket.err = err;
|
|
536
|
-
responsePacket.respond_to = packet.id;
|
|
537
|
-
responsePacket.data = data;
|
|
538
|
-
|
|
539
|
-
server.emit('response', responsePacket);
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
// See if this is for a specific linkup
|
|
544
|
-
if (packet.link) {
|
|
545
|
-
if (that.linkups[packet.link]) {
|
|
546
|
-
if (packet.stream) {
|
|
547
|
-
that.linkups[packet.link].emit(packet.type, packet.data, packet.stream, respond, null);
|
|
548
|
-
} else {
|
|
549
|
-
that.linkups[packet.link].emit(packet.type, packet.data, respond, null);
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
return;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
if (packet.stream) {
|
|
557
|
-
that.emit(packet.type, packet.data, packet.stream, respond, null);
|
|
558
|
-
} else {
|
|
559
|
-
that.emit(packet.type, packet.data, respond, null);
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
});
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* Create a namespace and inform the server
|
|
566
|
-
*
|
|
567
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
568
|
-
* @since 0.2.0
|
|
569
|
-
* @version 0.2.0
|
|
570
|
-
*
|
|
571
|
-
* @param {String} type The typename of link to create
|
|
572
|
-
* @param {Object} data The initial data to submit
|
|
573
|
-
* @param {Function} cb Called when link isready
|
|
574
|
-
*
|
|
575
|
-
* @return {Linkup}
|
|
576
|
-
*/
|
|
577
|
-
Client.setMethod(function linkup(type, data, cb) {
|
|
578
|
-
|
|
579
|
-
var link;
|
|
580
|
-
|
|
581
|
-
if (typeof data == 'function') {
|
|
582
|
-
cb = data;
|
|
583
|
-
data = {};
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
link = new Linkup(this, type, data);
|
|
587
|
-
|
|
588
|
-
if (cb) {
|
|
589
|
-
link.once('ready', function whenReady() {
|
|
590
|
-
cb.call(link, link);
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
return link;
|
|
595
|
-
});
|
|
596
|
-
|
|
597
|
-
/**
|
|
598
|
-
* Listen for specific server-initiated linkups
|
|
599
|
-
*
|
|
600
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
601
|
-
* @since 0.2.0
|
|
602
|
-
* @version 0.2.0
|
|
603
|
-
*
|
|
604
|
-
* @param {String} type The typename of link to listen to
|
|
605
|
-
* @param {Function} callback
|
|
606
|
-
*/
|
|
607
|
-
Client.setMethod(function onLinkup(type, callback) {
|
|
608
|
-
|
|
609
|
-
if (this.server_linkup_listeners[type] == null) {
|
|
610
|
-
this.server_linkup_listeners[type] = [];
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
this.server_linkup_listeners[type].push(callback);
|
|
1
|
+
/**
|
|
2
|
+
* See if the given object is a stream
|
|
3
|
+
*
|
|
4
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
5
|
+
* @since 0.2.0
|
|
6
|
+
* @version 1.0.5
|
|
7
|
+
*
|
|
8
|
+
* @return {Boolean}
|
|
9
|
+
*/
|
|
10
|
+
function isStream(obj) {
|
|
11
|
+
return obj && (typeof obj._read == 'function' || typeof obj._write == 'function') && typeof obj.on === 'function';
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The Linkup class
|
|
16
|
+
*
|
|
17
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
18
|
+
* @since 0.2.0
|
|
19
|
+
* @version 0.2.0
|
|
20
|
+
*
|
|
21
|
+
* @param {String} type
|
|
22
|
+
*/
|
|
23
|
+
var Linkup = Blast.Collection.Function.inherits('Informer', function ClientLinkup(client, type, data) {
|
|
24
|
+
|
|
25
|
+
var server_object,
|
|
26
|
+
id;
|
|
27
|
+
|
|
28
|
+
if (type && typeof type == 'object' && type.id && data == null) {
|
|
29
|
+
server_object = type;
|
|
30
|
+
id = server_object.id;
|
|
31
|
+
type = server_object.type;
|
|
32
|
+
data = server_object.data;
|
|
33
|
+
} else {
|
|
34
|
+
id = type + '-' + Blast.Classes.Crypto.pseudoHex();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// The identifier
|
|
38
|
+
this.id = id;
|
|
39
|
+
|
|
40
|
+
// The typename of the link
|
|
41
|
+
this.type = type;
|
|
42
|
+
|
|
43
|
+
// The initial submitted data
|
|
44
|
+
this.initialData = data;
|
|
45
|
+
|
|
46
|
+
// Make the linkup store itself
|
|
47
|
+
client.linkups[this.id] = this;
|
|
48
|
+
|
|
49
|
+
// The parent server
|
|
50
|
+
this.client = client;
|
|
51
|
+
|
|
52
|
+
if (server_object) {
|
|
53
|
+
this.submit('ready');
|
|
54
|
+
} else {
|
|
55
|
+
// Establish the link
|
|
56
|
+
client._submit('linkup', {type: type, id: this.id, data: data});
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Submit a message to the server on this link
|
|
62
|
+
*
|
|
63
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
64
|
+
* @since 0.2.0
|
|
65
|
+
* @version 0.2.0
|
|
66
|
+
*
|
|
67
|
+
* @param {String} type
|
|
68
|
+
* @param {Object} data
|
|
69
|
+
* @param {Function} callback
|
|
70
|
+
*/
|
|
71
|
+
Linkup.setMethod(function submit(type, data, stream, callback) {
|
|
72
|
+
this.client.submit([this.id, type], data, stream, callback);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Submit a message to the server on this link and return a promise
|
|
77
|
+
*
|
|
78
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
79
|
+
* @since 1.1.2
|
|
80
|
+
* @version 1.1.2
|
|
81
|
+
*
|
|
82
|
+
* @param {String} type
|
|
83
|
+
* @param {Object} data
|
|
84
|
+
*/
|
|
85
|
+
Linkup.setMethod(function demand(type, data, stream) {
|
|
86
|
+
|
|
87
|
+
const that = this;
|
|
88
|
+
|
|
89
|
+
let pledge = new Classes.Pledge(),
|
|
90
|
+
args = [type, data];
|
|
91
|
+
|
|
92
|
+
if (stream) {
|
|
93
|
+
args.push(stream);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
this.submit(...args, function done(err, result) {
|
|
97
|
+
|
|
98
|
+
if (err) {
|
|
99
|
+
return pledge.reject(err);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
pledge.resolve(result);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
return pledge;
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Create a stream
|
|
110
|
+
*
|
|
111
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
112
|
+
* @since 0.2.0
|
|
113
|
+
* @version 0.2.0
|
|
114
|
+
*/
|
|
115
|
+
Linkup.setMethod(function createStream() {
|
|
116
|
+
return this.client.createStream();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Destroy this linkup
|
|
121
|
+
*
|
|
122
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
123
|
+
* @since 0.2.0
|
|
124
|
+
* @version 0.2.0
|
|
125
|
+
*/
|
|
126
|
+
Linkup.setMethod(function destroy() {
|
|
127
|
+
delete this.client.linkups[this.id];
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Actually make the socket.io connection,
|
|
132
|
+
* this requires the socket.io js to be loaded
|
|
133
|
+
*
|
|
134
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
135
|
+
* @since 0.0.1
|
|
136
|
+
* @version 0.2.0
|
|
137
|
+
*
|
|
138
|
+
* @param {String} address Address to connect to
|
|
139
|
+
* @param {Object} data Announcement data
|
|
140
|
+
* @param {Function} callback
|
|
141
|
+
*/
|
|
142
|
+
var Client = Blast.Collection.Function.inherits('Informer', function ClientSocket() {
|
|
143
|
+
|
|
144
|
+
var that = this;
|
|
145
|
+
|
|
146
|
+
// Connected is false
|
|
147
|
+
this.connected = false;
|
|
148
|
+
|
|
149
|
+
// The packet queue
|
|
150
|
+
this.queue = [];
|
|
151
|
+
|
|
152
|
+
// The callbacks
|
|
153
|
+
this.callbacks = {};
|
|
154
|
+
|
|
155
|
+
// Established linkups
|
|
156
|
+
this.linkups = {};
|
|
157
|
+
|
|
158
|
+
// The client message counter
|
|
159
|
+
this.counter = 0;
|
|
160
|
+
|
|
161
|
+
// The server object
|
|
162
|
+
this.server = null;
|
|
163
|
+
|
|
164
|
+
// The server stream
|
|
165
|
+
this.serverstream = null;
|
|
166
|
+
|
|
167
|
+
// The timesync offset
|
|
168
|
+
this.offset = 0;
|
|
169
|
+
|
|
170
|
+
// The connection latency
|
|
171
|
+
this.latency = 0;
|
|
172
|
+
|
|
173
|
+
// Enable auto reconnect
|
|
174
|
+
this.reconnect = true;
|
|
175
|
+
|
|
176
|
+
// Server-linkup listeners
|
|
177
|
+
this.server_linkup_listeners = {};
|
|
178
|
+
|
|
179
|
+
this.emitPacket = function emitPacket(packet) {
|
|
180
|
+
|
|
181
|
+
var stream;
|
|
182
|
+
|
|
183
|
+
if (packet.stream) {
|
|
184
|
+
stream = packet.stream;
|
|
185
|
+
delete packet.stream;
|
|
186
|
+
that.serverstream.emit('payload', stream, packet);
|
|
187
|
+
} else {
|
|
188
|
+
that.server.emit('payload', packet);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get an offset-corrected timestamp
|
|
195
|
+
*
|
|
196
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
197
|
+
* @since 0.2.1
|
|
198
|
+
* @version 0.2.1
|
|
199
|
+
*
|
|
200
|
+
* @return {Number}
|
|
201
|
+
*/
|
|
202
|
+
Client.setMethod(function now() {
|
|
203
|
+
return Date.now() + (this.offset || 0);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Low level socket emit
|
|
208
|
+
*
|
|
209
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
210
|
+
* @since 0.2.0
|
|
211
|
+
* @version 1.1.0
|
|
212
|
+
*/
|
|
213
|
+
Client.setMethod(function _submit() {
|
|
214
|
+
var that = this,
|
|
215
|
+
args = Array.cast(arguments);
|
|
216
|
+
|
|
217
|
+
this.afterOnce('connected', function connected() {
|
|
218
|
+
that.server.emit.apply(that.server, args);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Submit method
|
|
224
|
+
*
|
|
225
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
226
|
+
* @since 0.2.0
|
|
227
|
+
* @version 0.2.0
|
|
228
|
+
*
|
|
229
|
+
* @param {String} type
|
|
230
|
+
* @param {Object} data
|
|
231
|
+
* @param {IOStream} stream
|
|
232
|
+
* @param {Function} callback
|
|
233
|
+
*/
|
|
234
|
+
Client.setMethod(function submit(type, data, stream, callback) {
|
|
235
|
+
|
|
236
|
+
var packet = {},
|
|
237
|
+
regular_stream;
|
|
238
|
+
|
|
239
|
+
if (isStream(data)) {
|
|
240
|
+
callback = stream;
|
|
241
|
+
stream = data;
|
|
242
|
+
data = undefined;
|
|
243
|
+
} else if (typeof data === 'function') {
|
|
244
|
+
callback = data;
|
|
245
|
+
data = undefined;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (!stream || typeof stream == 'function') {
|
|
249
|
+
callback = stream;
|
|
250
|
+
stream = undefined;
|
|
251
|
+
} else if (stream && stream.constructor.name != 'IOStream') {
|
|
252
|
+
// Keep the regular stream
|
|
253
|
+
regular_stream = stream;
|
|
254
|
+
|
|
255
|
+
// Create an IOStream
|
|
256
|
+
stream = this.createStream();
|
|
257
|
+
|
|
258
|
+
// Pipe the regular stream into the IOStream
|
|
259
|
+
regular_stream.pipe(stream);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (Array.isArray(type)) {
|
|
263
|
+
packet.link = type[0];
|
|
264
|
+
packet.type = type[1];
|
|
265
|
+
} else {
|
|
266
|
+
packet.type = type;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (data && data.constructor.name == 'IOStream') {
|
|
270
|
+
stream = data;
|
|
271
|
+
packet.noData = true;
|
|
272
|
+
} else {
|
|
273
|
+
packet.data = data;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
packet.id = 'c' + (++this.counter);
|
|
277
|
+
packet.stream = stream;
|
|
278
|
+
|
|
279
|
+
if (typeof callback == 'function') {
|
|
280
|
+
this.callbacks[packet.id] = callback;
|
|
281
|
+
packet.respond = true;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (this.connected) {
|
|
285
|
+
this.emitPacket(packet);
|
|
286
|
+
} else {
|
|
287
|
+
this.queue.push(packet);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Create a stream we can send through a websocket connection
|
|
293
|
+
*
|
|
294
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
295
|
+
* @since 0.2.0
|
|
296
|
+
* @version 0.2.0
|
|
297
|
+
*/
|
|
298
|
+
Client.setMethod(function createStream() {
|
|
299
|
+
|
|
300
|
+
var stream;
|
|
301
|
+
|
|
302
|
+
if (Blast.isNode) {
|
|
303
|
+
stream = alchemy.use('socket.io-stream').createStream();
|
|
304
|
+
} else {
|
|
305
|
+
stream = ss.createStream();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return stream;
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Make the actual connection
|
|
313
|
+
*
|
|
314
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
315
|
+
* @since 0.2.0
|
|
316
|
+
* @version 1.0.5
|
|
317
|
+
*
|
|
318
|
+
* @param {Function} callback
|
|
319
|
+
*/
|
|
320
|
+
Client.setMethod(function connect(address, data, callback) {
|
|
321
|
+
|
|
322
|
+
var that = this,
|
|
323
|
+
ioServer,
|
|
324
|
+
serverstream,
|
|
325
|
+
config = {},
|
|
326
|
+
server;
|
|
327
|
+
|
|
328
|
+
if (typeof address == 'function') {
|
|
329
|
+
callback = address;
|
|
330
|
+
data = {};
|
|
331
|
+
address = null;
|
|
332
|
+
} else if (typeof data == 'function') {
|
|
333
|
+
callback = data;
|
|
334
|
+
data = {};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (!data || typeof data != 'object') {
|
|
338
|
+
data = {};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (typeof io != 'undefined') {
|
|
342
|
+
ioServer = io;
|
|
343
|
+
} else if (typeof alchemy != 'undefined') {
|
|
344
|
+
ioServer = alchemy.use('socket.io-client');
|
|
345
|
+
} else {
|
|
346
|
+
return callback(new Error('Could not find socket.io client library'));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// The address to connect to
|
|
350
|
+
this.address = address;
|
|
351
|
+
|
|
352
|
+
if (Blast.isNode) {
|
|
353
|
+
data.connection_type = 'node';
|
|
354
|
+
data.discovery = alchemy.discovery_id;
|
|
355
|
+
} else {
|
|
356
|
+
data.connection_type = 'browser';
|
|
357
|
+
data.scene = hawkejs.scene.sceneId;
|
|
358
|
+
data.last_update = alchemy.last_update;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (!this.reconnect) {
|
|
362
|
+
config.reconnection = false;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Create the connection to the server
|
|
366
|
+
if (address) {
|
|
367
|
+
server = ioServer.connect(address, config);
|
|
368
|
+
} else {
|
|
369
|
+
server = ioServer.connect(config);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (Blast.isNode) {
|
|
373
|
+
serverstream = alchemy.use('socket.io-stream')(server);
|
|
374
|
+
} else {
|
|
375
|
+
serverstream = ss(server);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
this.server = server;
|
|
379
|
+
this.serverstream = serverstream;
|
|
380
|
+
|
|
381
|
+
// Announce ourselves when we've connected
|
|
382
|
+
server.on('connect', function onConnect() {
|
|
383
|
+
server.emit('announce', data);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// Emit the close event once we get disconnected from the server
|
|
387
|
+
server.on('disconnect', function closed() {
|
|
388
|
+
that.connected = false;
|
|
389
|
+
that.emit('close');
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Listen to timesync commands
|
|
393
|
+
server.on('timesync', function gotTimesync(data) {
|
|
394
|
+
|
|
395
|
+
// When offset is not defined,
|
|
396
|
+
// the server is actually requesting our timestamp
|
|
397
|
+
if (data.offset == null) {
|
|
398
|
+
data.client_time = Date.now();
|
|
399
|
+
server.emit('timesync', data);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// If the offset property is set,
|
|
404
|
+
// the timesync procedure has finished
|
|
405
|
+
|
|
406
|
+
// Set the values in this object
|
|
407
|
+
that.offset = data.offset || 0;
|
|
408
|
+
that.latency = data.latency || 0;
|
|
409
|
+
|
|
410
|
+
// Emit it as an event, too
|
|
411
|
+
that.emit('timesynced', that.offset, that.latency);
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// Listen for the ready event
|
|
415
|
+
server.on('ready', function onReady() {
|
|
416
|
+
|
|
417
|
+
that.connected = true;
|
|
418
|
+
|
|
419
|
+
if (callback) {
|
|
420
|
+
callback();
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
that.emit('connected');
|
|
424
|
+
|
|
425
|
+
// Emit all the queued packets
|
|
426
|
+
that.queue.forEach(that.emitPacket);
|
|
427
|
+
|
|
428
|
+
// Request a timesync
|
|
429
|
+
that.server.emit('timesync', {start: Date.now()});
|
|
430
|
+
|
|
431
|
+
// Reset the queue
|
|
432
|
+
that.queue.length = 0;
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
server.on('error', function(err) {
|
|
436
|
+
console.log('Socket error:', err);
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
// Listen for cookies
|
|
440
|
+
server.on('alchemy-set-cookie', function setCookie(data) {
|
|
441
|
+
if (Blast.isNode) {
|
|
442
|
+
// @TODO: set node cookie?
|
|
443
|
+
} else {
|
|
444
|
+
hawkejs.scene.cookie(data.name, data.value, data.options);
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// Listen for server initiated linkups
|
|
449
|
+
server.on('linkup', function gotLinkup(config) {
|
|
450
|
+
|
|
451
|
+
var linkup = new Linkup(that, config),
|
|
452
|
+
i;
|
|
453
|
+
|
|
454
|
+
// Look through the server-linkup callbacks
|
|
455
|
+
if (that.server_linkup_listeners[config.type]) {
|
|
456
|
+
for (i = 0; i < that.server_linkup_listeners[config.type].length; i++) {
|
|
457
|
+
that.server_linkup_listeners[config.type][i].call(that, linkup, config.data);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Emit it on the client itself
|
|
462
|
+
that.emit(linkup.type, linkup, null);
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
// Listen for payloads
|
|
466
|
+
server.on('payload', onPacket);
|
|
467
|
+
|
|
468
|
+
// Listen for payloads with streams
|
|
469
|
+
serverstream.on('payload', function onPayload(stream, packet) {
|
|
470
|
+
packet.stream = stream;
|
|
471
|
+
onPacket(packet);
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
// Listen for responses with streams
|
|
475
|
+
serverstream.on('response', function onStreamingResponse(stream, packet) {
|
|
476
|
+
packet.stream = stream;
|
|
477
|
+
onResponse(packet);
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
// Listen for responses
|
|
481
|
+
server.on('response', onResponse);
|
|
482
|
+
|
|
483
|
+
// The function that handles responses
|
|
484
|
+
function onResponse(packet) {
|
|
485
|
+
|
|
486
|
+
if (typeof that.callbacks[packet.respond_to] === 'function') {
|
|
487
|
+
|
|
488
|
+
if (packet.err && typeof packet.err == 'object') {
|
|
489
|
+
try {
|
|
490
|
+
packet.err = JSON.undry(packet.err);
|
|
491
|
+
} catch (err) {
|
|
492
|
+
console.log('Error undrying error:', err, packet);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
try {
|
|
497
|
+
if (packet.data && typeof packet.data == 'object') {
|
|
498
|
+
packet.data = JSON.undry(packet.data);
|
|
499
|
+
}
|
|
500
|
+
} catch (err) {
|
|
501
|
+
console.log('ERROR UNDRYING PACKET:', err, packet);
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (packet.noData) {
|
|
506
|
+
that.callbacks[packet.respond_to](packet.err, packet.stream);
|
|
507
|
+
} else if (packet.stream) {
|
|
508
|
+
that.callbacks[packet.respond_to](packet.err, packet.data, packet.stream);
|
|
509
|
+
} else {
|
|
510
|
+
that.callbacks[packet.respond_to](packet.err, packet.data);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
delete that.callbacks[packet.respond_to];
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// The function that handles packets
|
|
518
|
+
function onPacket(packet) {
|
|
519
|
+
|
|
520
|
+
var respond;
|
|
521
|
+
|
|
522
|
+
try {
|
|
523
|
+
if (packet.data && typeof packet.data == 'object') {
|
|
524
|
+
packet.data = JSON.undry(packet.data);
|
|
525
|
+
}
|
|
526
|
+
} catch (err) {
|
|
527
|
+
console.log('ERROR UNDRYING PACKET:', err, packet);
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (packet.respond) {
|
|
532
|
+
respond = function respond(err, data) {
|
|
533
|
+
var responsePacket = {};
|
|
534
|
+
|
|
535
|
+
responsePacket.err = err;
|
|
536
|
+
responsePacket.respond_to = packet.id;
|
|
537
|
+
responsePacket.data = data;
|
|
538
|
+
|
|
539
|
+
server.emit('response', responsePacket);
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// See if this is for a specific linkup
|
|
544
|
+
if (packet.link) {
|
|
545
|
+
if (that.linkups[packet.link]) {
|
|
546
|
+
if (packet.stream) {
|
|
547
|
+
that.linkups[packet.link].emit(packet.type, packet.data, packet.stream, respond, null);
|
|
548
|
+
} else {
|
|
549
|
+
that.linkups[packet.link].emit(packet.type, packet.data, respond, null);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
if (packet.stream) {
|
|
557
|
+
that.emit(packet.type, packet.data, packet.stream, respond, null);
|
|
558
|
+
} else {
|
|
559
|
+
that.emit(packet.type, packet.data, respond, null);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Create a namespace and inform the server
|
|
566
|
+
*
|
|
567
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
568
|
+
* @since 0.2.0
|
|
569
|
+
* @version 0.2.0
|
|
570
|
+
*
|
|
571
|
+
* @param {String} type The typename of link to create
|
|
572
|
+
* @param {Object} data The initial data to submit
|
|
573
|
+
* @param {Function} cb Called when link isready
|
|
574
|
+
*
|
|
575
|
+
* @return {Linkup}
|
|
576
|
+
*/
|
|
577
|
+
Client.setMethod(function linkup(type, data, cb) {
|
|
578
|
+
|
|
579
|
+
var link;
|
|
580
|
+
|
|
581
|
+
if (typeof data == 'function') {
|
|
582
|
+
cb = data;
|
|
583
|
+
data = {};
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
link = new Linkup(this, type, data);
|
|
587
|
+
|
|
588
|
+
if (cb) {
|
|
589
|
+
link.once('ready', function whenReady() {
|
|
590
|
+
cb.call(link, link);
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
return link;
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Listen for specific server-initiated linkups
|
|
599
|
+
*
|
|
600
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
601
|
+
* @since 0.2.0
|
|
602
|
+
* @version 0.2.0
|
|
603
|
+
*
|
|
604
|
+
* @param {String} type The typename of link to listen to
|
|
605
|
+
* @param {Function} callback
|
|
606
|
+
*/
|
|
607
|
+
Client.setMethod(function onLinkup(type, callback) {
|
|
608
|
+
|
|
609
|
+
if (this.server_linkup_listeners[type] == null) {
|
|
610
|
+
this.server_linkup_listeners[type] = [];
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
this.server_linkup_listeners[type].push(callback);
|
|
614
614
|
});
|