alchemymvc 1.1.7 → 1.2.0
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/lib/app/behaviour/sluggable_behaviour.js +2 -4
- package/lib/app/conduit/http_conduit.js +173 -192
- package/lib/app/conduit/loopback_conduit.js +0 -0
- package/lib/app/conduit/socket_conduit.js +620 -620
- package/lib/app/datasource/mongo_datasource.js +75 -10
- package/lib/app/element/time_ago.js +0 -0
- package/lib/app/helper/socket_helper.js +613 -613
- package/lib/app/helper_datasource/00-nosql_datasource.js +73 -19
- package/lib/app/helper_datasource/remote_datasource.js +0 -0
- package/lib/app/helper_field/05-string_field.js +0 -0
- package/lib/app/helper_field/schema_field.js +7 -2
- package/lib/app/helper_model/criteria.js +76 -18
- package/lib/app/helper_model/field_config.js +24 -5
- package/lib/app/helper_model/model.js +65 -7
- package/lib/app/model/alchemy_migration_model.js +33 -0
- package/lib/bootstrap.js +9 -0
- package/lib/class/conduit.js +2474 -2412
- package/lib/class/datasource.js +8 -8
- package/lib/class/field.js +7 -1
- package/lib/class/inode.js +62 -0
- package/lib/class/inode_dir.js +115 -0
- package/lib/class/inode_file.js +112 -111
- package/lib/class/migration.js +138 -0
- package/lib/class/model.js +1765 -1772
- package/lib/class/reciprocal.js +8 -2
- package/lib/class/router.js +0 -0
- package/lib/class/schema.js +14 -12
- package/lib/core/base.js +37 -10
- package/lib/core/client_base.js +1 -9
- package/lib/core/middleware.js +4 -8
- package/lib/core/socket.js +159 -159
- package/lib/init/alchemy.js +1779 -1779
- package/lib/init/devwatch.js +1 -1
- package/lib/init/functions.js +2 -56
- package/lib/init/load_functions.js +8 -2
- package/lib/init/requirements.js +101 -96
- package/lib/stages.js +12 -0
- package/package.json +74 -76
- package/CHANGELOG.md +0 -445
package/lib/class/reciprocal.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* A Reciprocal instance creates a named channel on an IPC link.
|
|
3
|
+
*
|
|
4
|
+
* This link instance has to implement the `message` event and the `send` method,
|
|
5
|
+
* this will most probably be a ChildProcess but can also be used for socket.io
|
|
3
6
|
*
|
|
4
7
|
* @constructor
|
|
5
8
|
*
|
|
6
|
-
* @author Jelle De Loecker <jelle@
|
|
9
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
7
10
|
* @since 1.1.0
|
|
8
11
|
* @version 1.1.0
|
|
12
|
+
*
|
|
13
|
+
* @param {ChildProcess} link
|
|
14
|
+
* @param {string} identifier
|
|
9
15
|
*/
|
|
10
16
|
const Reciprocal = Function.inherits('Alchemy.Base', 'Alchemy.Reciprocal', function Reciprocal(link, identifier) {
|
|
11
17
|
|
package/lib/class/router.js
CHANGED
|
File without changes
|
package/lib/class/schema.js
CHANGED
|
@@ -184,7 +184,7 @@ Schema.setMethod(function eachAlternateIndex(data, fnc) {
|
|
|
184
184
|
*
|
|
185
185
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
186
186
|
* @since 1.1.0
|
|
187
|
-
* @version 1.
|
|
187
|
+
* @version 1.2.0
|
|
188
188
|
*
|
|
189
189
|
* @return {Pledge}
|
|
190
190
|
*/
|
|
@@ -192,20 +192,24 @@ Schema.setMethod(function getDatasource() {
|
|
|
192
192
|
|
|
193
193
|
var that = this;
|
|
194
194
|
|
|
195
|
-
return Function.
|
|
196
|
-
that.afterOnce('has_model_class',
|
|
197
|
-
next();
|
|
198
|
-
});
|
|
195
|
+
return Function.series(function waitForModelClass(next) {
|
|
196
|
+
that.afterOnce('has_model_class', next);
|
|
199
197
|
}, function waitForDatasources(next) {
|
|
200
198
|
|
|
201
199
|
alchemy.sputnik.after('datasources', function afterDs() {
|
|
202
200
|
|
|
203
|
-
|
|
201
|
+
let datasource;
|
|
204
202
|
|
|
205
|
-
if (
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
if (that.model_class) {
|
|
204
|
+
datasource = Datasource.get(that.model_class.prototype.dbConfig);
|
|
205
|
+
|
|
206
|
+
if (!datasource) {
|
|
207
|
+
console.log('Failed to get', that.model_class.prototype.dbConfig, 'datasource?');
|
|
208
|
+
return next(new Error('Could not get datasource "' + that.model_class.prototype.dbConfig + '"'));
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
return next(new Error('Unable to get datasource for this sub-schema'));
|
|
212
|
+
}
|
|
209
213
|
|
|
210
214
|
next(null, datasource);
|
|
211
215
|
});
|
|
@@ -218,8 +222,6 @@ Schema.setMethod(function getDatasource() {
|
|
|
218
222
|
|
|
219
223
|
return result[1];
|
|
220
224
|
});
|
|
221
|
-
|
|
222
|
-
return pledge;
|
|
223
225
|
});
|
|
224
226
|
|
|
225
227
|
/**
|
package/lib/core/base.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
const CONDUIT = Symbol('conduit');
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Alchemy's Base class
|
|
@@ -339,6 +340,40 @@ Base.setStatic('is_abstract_class', true, false);
|
|
|
339
340
|
*/
|
|
340
341
|
Base.setStatic('starts_new_group', false);
|
|
341
342
|
|
|
343
|
+
/**
|
|
344
|
+
* Get the attached conduit
|
|
345
|
+
*
|
|
346
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
347
|
+
* @since 1.1.8
|
|
348
|
+
* @version 1.1.8
|
|
349
|
+
*
|
|
350
|
+
* @type {Conduit}
|
|
351
|
+
*/
|
|
352
|
+
Base.setProperty(function conduit() {
|
|
353
|
+
|
|
354
|
+
if (this[CONDUIT]) {
|
|
355
|
+
return this[CONDUIT];
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
let renderer = this.renderer || this.view || this.hawkejs_view,
|
|
359
|
+
result;
|
|
360
|
+
|
|
361
|
+
if (renderer && renderer.conduit) {
|
|
362
|
+
result = renderer.conduit;
|
|
363
|
+
} else if (renderer && renderer.root_renderer && renderer.root_renderer.conduit) {
|
|
364
|
+
result = renderer.root_renderer.conduit;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (!conduit && renderer && renderer.server_var) {
|
|
368
|
+
result = renderer.server_var('conduit');
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return result;
|
|
372
|
+
|
|
373
|
+
}, function setConduit(conduit) {
|
|
374
|
+
return this[CONDUIT] = conduit;
|
|
375
|
+
});
|
|
376
|
+
|
|
342
377
|
/**
|
|
343
378
|
* Enable all inherited classes to get a class group
|
|
344
379
|
*
|
|
@@ -420,9 +455,9 @@ Base.setMethod(function attachConduit(conduit) {
|
|
|
420
455
|
/**
|
|
421
456
|
* Get a model, attach a conduit if possible
|
|
422
457
|
*
|
|
423
|
-
* @author Jelle De Loecker <jelle@
|
|
458
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
424
459
|
* @since 0.3.0
|
|
425
|
-
* @version 1.1.
|
|
460
|
+
* @version 1.1.8
|
|
426
461
|
*
|
|
427
462
|
* @param {String} name The name of the model to get
|
|
428
463
|
* @param {Boolean} init Initialize the class [true]
|
|
@@ -457,14 +492,6 @@ Base.setMethod(function getModel(name, init, options) {
|
|
|
457
492
|
|
|
458
493
|
let conduit = this.conduit;
|
|
459
494
|
|
|
460
|
-
if (!conduit) {
|
|
461
|
-
if (this.view && this.view.conduit) {
|
|
462
|
-
conduit = this.view.conduit;
|
|
463
|
-
} else if (this.view && this.view.root_renderer && this.view.root_renderer.conduit) {
|
|
464
|
-
conduit = this.view.root_renderer.conduit;
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
|
|
468
495
|
// If an instance already exists on this item,
|
|
469
496
|
// and it has the same conduit (or none), return that
|
|
470
497
|
if (instance && (instance.conduit == conduit)) {
|
package/lib/core/client_base.js
CHANGED
|
@@ -233,7 +233,7 @@ ClientBase.setStatic(function mapEventToMethod(event_name, method_name) {
|
|
|
233
233
|
*
|
|
234
234
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
235
235
|
* @since 1.0.0
|
|
236
|
-
* @version 1.1.
|
|
236
|
+
* @version 1.1.8
|
|
237
237
|
*
|
|
238
238
|
* @param {String} name
|
|
239
239
|
* @param {Object} options
|
|
@@ -272,14 +272,6 @@ ClientBase.setMethod(function getModel(name, init, options) {
|
|
|
272
272
|
|
|
273
273
|
let conduit = this.conduit;
|
|
274
274
|
|
|
275
|
-
if (!conduit) {
|
|
276
|
-
if (this.view && this.view.conduit) {
|
|
277
|
-
conduit = this.view.conduit;
|
|
278
|
-
} else if (this.view && this.view.root_renderer && this.view.root_renderer.conduit) {
|
|
279
|
-
conduit = this.view.root_renderer.conduit;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
275
|
if (conduit) {
|
|
284
276
|
instance.conduit = conduit;
|
|
285
277
|
}
|
package/lib/core/middleware.js
CHANGED
|
@@ -22,19 +22,15 @@ var publicDirs = alchemy.shared('public.directories', new Deck()),
|
|
|
22
22
|
postcss,
|
|
23
23
|
babel,
|
|
24
24
|
sass,
|
|
25
|
-
temp = alchemy.use('temp'),
|
|
26
25
|
less,
|
|
27
26
|
fs = alchemy.use('fs');
|
|
28
27
|
|
|
29
|
-
// Remove temporary files on exit
|
|
30
|
-
temp.track();
|
|
31
|
-
|
|
32
28
|
if (alchemy.settings.css_less !== false) {
|
|
33
29
|
less = alchemy.use('less');
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
if (alchemy.settings.css_sass) {
|
|
37
|
-
sass = alchemy.use('
|
|
33
|
+
sass = alchemy.use('sass');
|
|
38
34
|
}
|
|
39
35
|
|
|
40
36
|
if (alchemy.settings.css_post !== false) {
|
|
@@ -410,7 +406,7 @@ Alchemy.setMethod(function minifyScript(path, options, callback) {
|
|
|
410
406
|
}
|
|
411
407
|
|
|
412
408
|
// Open a temp js file
|
|
413
|
-
|
|
409
|
+
Blast.openTempFile({suffix: '.js'}, function getTempFile(err, info) {
|
|
414
410
|
|
|
415
411
|
var js_buffer;
|
|
416
412
|
|
|
@@ -900,7 +896,7 @@ Alchemy.setMethod(function getCompiledLessPath(lessPath, options, callback) {
|
|
|
900
896
|
// @todo: add minify options
|
|
901
897
|
css = cssTree.css;
|
|
902
898
|
|
|
903
|
-
|
|
899
|
+
Blast.openTempFile({suffix: '.css'}, function getTempFile(err, info) {
|
|
904
900
|
|
|
905
901
|
var cssBuffer;
|
|
906
902
|
|
|
@@ -989,7 +985,7 @@ Alchemy.setMethod(function getCompiledSassPath(sassPath, options, callback) {
|
|
|
989
985
|
});
|
|
990
986
|
|
|
991
987
|
function writeToTemp(content) {
|
|
992
|
-
|
|
988
|
+
Blast.openTempFile({suffix: '.css'}, function getTempFile(err, info) {
|
|
993
989
|
|
|
994
990
|
if (err) {
|
|
995
991
|
return callback(err);
|
package/lib/core/socket.js
CHANGED
|
@@ -1,160 +1,160 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var types = alchemy.shared('Socket.types'),
|
|
4
|
-
iostream,
|
|
5
|
-
path = alchemy.use('path'),
|
|
6
|
-
fs = alchemy.use('fs');
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* The "socket" stage:
|
|
10
|
-
*
|
|
11
|
-
* Create the socket.io listener
|
|
12
|
-
*
|
|
13
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
14
|
-
* @since 0.1.0
|
|
15
|
-
* @version 1.1.3
|
|
16
|
-
*/
|
|
17
|
-
alchemy.sputnik.add(function socket() {
|
|
18
|
-
|
|
19
|
-
var clientPath,
|
|
20
|
-
streamPath,
|
|
21
|
-
io;
|
|
22
|
-
|
|
23
|
-
if (!alchemy.settings.websockets) {
|
|
24
|
-
log.info('Websockets have been disabled');
|
|
25
|
-
return;
|
|
26
|
-
} else {
|
|
27
|
-
if (alchemy.settings.websockets == 'optional') {
|
|
28
|
-
log.info('Websockets have been enabled optionally');
|
|
29
|
-
} else {
|
|
30
|
-
log.info('Websockets have been enabled, clients will automatically connect');
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
io = alchemy.use('socket.io');
|
|
35
|
-
|
|
36
|
-
if (!io) {
|
|
37
|
-
return log.error('Could not load socket.io!');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
iostream = alchemy.use('socket.io-stream');
|
|
41
|
-
|
|
42
|
-
// Create the Socket.io listener
|
|
43
|
-
alchemy.io = io.listen(alchemy.server, {serveClient: false});
|
|
44
|
-
|
|
45
|
-
// Get the core client path
|
|
46
|
-
clientPath = path.dirname(alchemy.findModule('socket.io-client').module_path);
|
|
47
|
-
clientPath = path.resolve(clientPath, '..', 'dist', 'socket.io.slim.js');
|
|
48
|
-
|
|
49
|
-
// Get the stream client path
|
|
50
|
-
streamPath = path.dirname(alchemy.findModule('socket.io-stream').module_path);
|
|
51
|
-
streamPath = path.resolve(streamPath, 'socket.io-stream.js');
|
|
52
|
-
|
|
53
|
-
// Serve the socket io core file
|
|
54
|
-
Router.use('/scripts/socket.io.js', function getSocketIo(req, res, next) {
|
|
55
|
-
alchemy.minifyScript(clientPath, function gotMinifiedPath(err, mpath) {
|
|
56
|
-
req.conduit.serveFile(mpath || clientPath);
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Serve the socket io stream file
|
|
61
|
-
Router.use('/scripts/socket.io-stream.js', function getSocketStream(req, res, next) {
|
|
62
|
-
alchemy.minifyScript(streamPath, function gotMinifiedPath(err, mpath) {
|
|
63
|
-
req.conduit.serveFile(mpath || streamPath);
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Handle connections
|
|
69
|
-
*
|
|
70
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
71
|
-
* @since 0.0.1
|
|
72
|
-
* @version 0.2.0
|
|
73
|
-
*/
|
|
74
|
-
alchemy.io.sockets.on('connection', function onConnect(socket){
|
|
75
|
-
|
|
76
|
-
var syncs = {},
|
|
77
|
-
latencies = [],
|
|
78
|
-
latency_avg = 2,
|
|
79
|
-
offset = 0;
|
|
80
|
-
|
|
81
|
-
socket.on('timesync', function gotTimesyncRequest(data) {
|
|
82
|
-
|
|
83
|
-
var received = Date.now(),
|
|
84
|
-
latency;
|
|
85
|
-
|
|
86
|
-
// This is the initial request
|
|
87
|
-
if (data.count == null) {
|
|
88
|
-
data.count = 0;
|
|
89
|
-
data.latency_trip = 0;
|
|
90
|
-
|
|
91
|
-
// Reset the latencies array
|
|
92
|
-
latencies.length = 0;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Do 8 round trips to determine latency
|
|
96
|
-
if (data.latency_trip <= 8) {
|
|
97
|
-
|
|
98
|
-
if (data.last_sent) {
|
|
99
|
-
|
|
100
|
-
// Latency is the timestamp when we received the response
|
|
101
|
-
// minus the timestamp when we sent the request
|
|
102
|
-
latency = received - data.last_sent;
|
|
103
|
-
latencies.push(latency);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Wait before responding
|
|
107
|
-
setTimeout(function waitForLatency() {
|
|
108
|
-
data.last_sent = Date.now();
|
|
109
|
-
socket.emit('timesync', data);
|
|
110
|
-
}, 100 + (data.latency_trip * 150));
|
|
111
|
-
|
|
112
|
-
data.latency_trip++;
|
|
113
|
-
} else if (data.latency_trip) {
|
|
114
|
-
|
|
115
|
-
latency_avg = ~~(Math.median(latencies) / 2);
|
|
116
|
-
offset = (received - latency_avg) - data.client_time;
|
|
117
|
-
|
|
118
|
-
socket.emit('timesync', {offset: offset, latency: latency_avg});
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
// Wait for the announcement
|
|
123
|
-
socket.once('announce', function gotAnnouncement(data) {
|
|
124
|
-
|
|
125
|
-
var SocketClass,
|
|
126
|
-
class_name;
|
|
127
|
-
|
|
128
|
-
// Try getting the socket class of this type
|
|
129
|
-
if (typeof data.type == 'string') {
|
|
130
|
-
class_name = data.type.classify();
|
|
131
|
-
SocketClass = Classes.Alchemy.Conduit[class_name + 'Socket'];
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// If no socket class was found get the regular class
|
|
135
|
-
if (!SocketClass) {
|
|
136
|
-
SocketClass = Classes.Alchemy.Conduit.Socket;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
new SocketClass(socket, data);
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Connect to another alchemy instance
|
|
146
|
-
*
|
|
147
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
148
|
-
* @since 0.1.0
|
|
149
|
-
* @version 0.4.0
|
|
150
|
-
*/
|
|
151
|
-
Alchemy.setMethod(function callServer(address, data, callback) {
|
|
152
|
-
|
|
153
|
-
var server = new Classes.ClientSocket();
|
|
154
|
-
|
|
155
|
-
server.reconnect = false;
|
|
156
|
-
|
|
157
|
-
server.connect(address, data, callback);
|
|
158
|
-
|
|
159
|
-
return server;
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var types = alchemy.shared('Socket.types'),
|
|
4
|
+
iostream,
|
|
5
|
+
path = alchemy.use('path'),
|
|
6
|
+
fs = alchemy.use('fs');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The "socket" stage:
|
|
10
|
+
*
|
|
11
|
+
* Create the socket.io listener
|
|
12
|
+
*
|
|
13
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
14
|
+
* @since 0.1.0
|
|
15
|
+
* @version 1.1.3
|
|
16
|
+
*/
|
|
17
|
+
alchemy.sputnik.add(function socket() {
|
|
18
|
+
|
|
19
|
+
var clientPath,
|
|
20
|
+
streamPath,
|
|
21
|
+
io;
|
|
22
|
+
|
|
23
|
+
if (!alchemy.settings.websockets) {
|
|
24
|
+
log.info('Websockets have been disabled');
|
|
25
|
+
return;
|
|
26
|
+
} else {
|
|
27
|
+
if (alchemy.settings.websockets == 'optional') {
|
|
28
|
+
log.info('Websockets have been enabled optionally');
|
|
29
|
+
} else {
|
|
30
|
+
log.info('Websockets have been enabled, clients will automatically connect');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
io = alchemy.use('socket.io');
|
|
35
|
+
|
|
36
|
+
if (!io) {
|
|
37
|
+
return log.error('Could not load socket.io!');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
iostream = alchemy.use('socket.io-stream');
|
|
41
|
+
|
|
42
|
+
// Create the Socket.io listener
|
|
43
|
+
alchemy.io = io.listen(alchemy.server, {serveClient: false});
|
|
44
|
+
|
|
45
|
+
// Get the core client path
|
|
46
|
+
clientPath = path.dirname(alchemy.findModule('socket.io-client').module_path);
|
|
47
|
+
clientPath = path.resolve(clientPath, '..', 'dist', 'socket.io.slim.js');
|
|
48
|
+
|
|
49
|
+
// Get the stream client path
|
|
50
|
+
streamPath = path.dirname(alchemy.findModule('@11ways/socket.io-stream').module_path);
|
|
51
|
+
streamPath = path.resolve(streamPath, 'socket.io-stream.js');
|
|
52
|
+
|
|
53
|
+
// Serve the socket io core file
|
|
54
|
+
Router.use('/scripts/socket.io.js', function getSocketIo(req, res, next) {
|
|
55
|
+
alchemy.minifyScript(clientPath, function gotMinifiedPath(err, mpath) {
|
|
56
|
+
req.conduit.serveFile(mpath || clientPath);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Serve the socket io stream file
|
|
61
|
+
Router.use('/scripts/socket.io-stream.js', function getSocketStream(req, res, next) {
|
|
62
|
+
alchemy.minifyScript(streamPath, function gotMinifiedPath(err, mpath) {
|
|
63
|
+
req.conduit.serveFile(mpath || streamPath);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Handle connections
|
|
69
|
+
*
|
|
70
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
71
|
+
* @since 0.0.1
|
|
72
|
+
* @version 0.2.0
|
|
73
|
+
*/
|
|
74
|
+
alchemy.io.sockets.on('connection', function onConnect(socket){
|
|
75
|
+
|
|
76
|
+
var syncs = {},
|
|
77
|
+
latencies = [],
|
|
78
|
+
latency_avg = 2,
|
|
79
|
+
offset = 0;
|
|
80
|
+
|
|
81
|
+
socket.on('timesync', function gotTimesyncRequest(data) {
|
|
82
|
+
|
|
83
|
+
var received = Date.now(),
|
|
84
|
+
latency;
|
|
85
|
+
|
|
86
|
+
// This is the initial request
|
|
87
|
+
if (data.count == null) {
|
|
88
|
+
data.count = 0;
|
|
89
|
+
data.latency_trip = 0;
|
|
90
|
+
|
|
91
|
+
// Reset the latencies array
|
|
92
|
+
latencies.length = 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Do 8 round trips to determine latency
|
|
96
|
+
if (data.latency_trip <= 8) {
|
|
97
|
+
|
|
98
|
+
if (data.last_sent) {
|
|
99
|
+
|
|
100
|
+
// Latency is the timestamp when we received the response
|
|
101
|
+
// minus the timestamp when we sent the request
|
|
102
|
+
latency = received - data.last_sent;
|
|
103
|
+
latencies.push(latency);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Wait before responding
|
|
107
|
+
setTimeout(function waitForLatency() {
|
|
108
|
+
data.last_sent = Date.now();
|
|
109
|
+
socket.emit('timesync', data);
|
|
110
|
+
}, 100 + (data.latency_trip * 150));
|
|
111
|
+
|
|
112
|
+
data.latency_trip++;
|
|
113
|
+
} else if (data.latency_trip) {
|
|
114
|
+
|
|
115
|
+
latency_avg = ~~(Math.median(latencies) / 2);
|
|
116
|
+
offset = (received - latency_avg) - data.client_time;
|
|
117
|
+
|
|
118
|
+
socket.emit('timesync', {offset: offset, latency: latency_avg});
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Wait for the announcement
|
|
123
|
+
socket.once('announce', function gotAnnouncement(data) {
|
|
124
|
+
|
|
125
|
+
var SocketClass,
|
|
126
|
+
class_name;
|
|
127
|
+
|
|
128
|
+
// Try getting the socket class of this type
|
|
129
|
+
if (typeof data.type == 'string') {
|
|
130
|
+
class_name = data.type.classify();
|
|
131
|
+
SocketClass = Classes.Alchemy.Conduit[class_name + 'Socket'];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// If no socket class was found get the regular class
|
|
135
|
+
if (!SocketClass) {
|
|
136
|
+
SocketClass = Classes.Alchemy.Conduit.Socket;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
new SocketClass(socket, data);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Connect to another alchemy instance
|
|
146
|
+
*
|
|
147
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
148
|
+
* @since 0.1.0
|
|
149
|
+
* @version 0.4.0
|
|
150
|
+
*/
|
|
151
|
+
Alchemy.setMethod(function callServer(address, data, callback) {
|
|
152
|
+
|
|
153
|
+
var server = new Classes.ClientSocket();
|
|
154
|
+
|
|
155
|
+
server.reconnect = false;
|
|
156
|
+
|
|
157
|
+
server.connect(address, data, callback);
|
|
158
|
+
|
|
159
|
+
return server;
|
|
160
160
|
});
|