mirror of
https://github.com/YunoHost-Apps/rocketchat_ynh.git
synced 2024-09-03 20:16:25 +02:00
480 lines
43 KiB
JavaScript
480 lines
43 KiB
JavaScript
(function () {
|
|
|
|
/* Imports */
|
|
var Meteor = Package.meteor.Meteor;
|
|
var check = Package.check.check;
|
|
var Match = Package.check.Match;
|
|
var Random = Package.random.Random;
|
|
var EJSON = Package.ejson.EJSON;
|
|
var _ = Package.underscore._;
|
|
var Tracker = Package.tracker.Tracker;
|
|
var Deps = Package.tracker.Deps;
|
|
var Retry = Package.retry.Retry;
|
|
|
|
/* Package-scope variables */
|
|
var DDPCommon;
|
|
|
|
(function(){
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/ddp-common/namespace.js //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
/** // 1
|
|
* @namespace DDPCommon // 2
|
|
* @summary Namespace for DDPCommon-related methods/classes. Shared between // 3
|
|
* `ddp-client` and `ddp-server`, where the ddp-client is the implementation // 4
|
|
* of a ddp client for both client AND server; and the ddp server is the // 5
|
|
* implementation of the livedata server and stream server. Common // 6
|
|
* functionality shared between both can be shared under this namespace // 7
|
|
*/ // 8
|
|
DDPCommon = {}; // 9
|
|
// 10
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/ddp-common/heartbeat.js //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Heartbeat options: // 1
|
|
// heartbeatInterval: interval to send pings, in milliseconds. // 2
|
|
// heartbeatTimeout: timeout to close the connection if a reply isn't // 3
|
|
// received, in milliseconds. // 4
|
|
// sendPing: function to call to send a ping on the connection. // 5
|
|
// onTimeout: function to call to close the connection. // 6
|
|
// 7
|
|
DDPCommon.Heartbeat = function (options) { // 8
|
|
var self = this; // 9
|
|
// 10
|
|
self.heartbeatInterval = options.heartbeatInterval; // 11
|
|
self.heartbeatTimeout = options.heartbeatTimeout; // 12
|
|
self._sendPing = options.sendPing; // 13
|
|
self._onTimeout = options.onTimeout; // 14
|
|
self._seenPacket = false; // 15
|
|
// 16
|
|
self._heartbeatIntervalHandle = null; // 17
|
|
self._heartbeatTimeoutHandle = null; // 18
|
|
}; // 19
|
|
// 20
|
|
_.extend(DDPCommon.Heartbeat.prototype, { // 21
|
|
stop: function () { // 22
|
|
var self = this; // 23
|
|
self._clearHeartbeatIntervalTimer(); // 24
|
|
self._clearHeartbeatTimeoutTimer(); // 25
|
|
}, // 26
|
|
// 27
|
|
start: function () { // 28
|
|
var self = this; // 29
|
|
self.stop(); // 30
|
|
self._startHeartbeatIntervalTimer(); // 31
|
|
}, // 32
|
|
// 33
|
|
_startHeartbeatIntervalTimer: function () { // 34
|
|
var self = this; // 35
|
|
self._heartbeatIntervalHandle = Meteor.setInterval( // 36
|
|
_.bind(self._heartbeatIntervalFired, self), // 37
|
|
self.heartbeatInterval // 38
|
|
); // 39
|
|
}, // 40
|
|
// 41
|
|
_startHeartbeatTimeoutTimer: function () { // 42
|
|
var self = this; // 43
|
|
self._heartbeatTimeoutHandle = Meteor.setTimeout( // 44
|
|
_.bind(self._heartbeatTimeoutFired, self), // 45
|
|
self.heartbeatTimeout // 46
|
|
); // 47
|
|
}, // 48
|
|
// 49
|
|
_clearHeartbeatIntervalTimer: function () { // 50
|
|
var self = this; // 51
|
|
if (self._heartbeatIntervalHandle) { // 52
|
|
Meteor.clearInterval(self._heartbeatIntervalHandle); // 53
|
|
self._heartbeatIntervalHandle = null; // 54
|
|
} // 55
|
|
}, // 56
|
|
// 57
|
|
_clearHeartbeatTimeoutTimer: function () { // 58
|
|
var self = this; // 59
|
|
if (self._heartbeatTimeoutHandle) { // 60
|
|
Meteor.clearTimeout(self._heartbeatTimeoutHandle); // 61
|
|
self._heartbeatTimeoutHandle = null; // 62
|
|
} // 63
|
|
}, // 64
|
|
// 65
|
|
// The heartbeat interval timer is fired when we should send a ping. // 66
|
|
_heartbeatIntervalFired: function () { // 67
|
|
var self = this; // 68
|
|
// don't send ping if we've seen a packet since we last checked, // 69
|
|
// *or* if we have already sent a ping and are awaiting a timeout. // 70
|
|
// That shouldn't happen, but it's possible if // 71
|
|
// `self.heartbeatInterval` is smaller than // 72
|
|
// `self.heartbeatTimeout`. // 73
|
|
if (! self._seenPacket && ! self._heartbeatTimeoutHandle) { // 74
|
|
self._sendPing(); // 75
|
|
// Set up timeout, in case a pong doesn't arrive in time. // 76
|
|
self._startHeartbeatTimeoutTimer(); // 77
|
|
} // 78
|
|
self._seenPacket = false; // 79
|
|
}, // 80
|
|
// 81
|
|
// The heartbeat timeout timer is fired when we sent a ping, but we // 82
|
|
// timed out waiting for the pong. // 83
|
|
_heartbeatTimeoutFired: function () { // 84
|
|
var self = this; // 85
|
|
self._heartbeatTimeoutHandle = null; // 86
|
|
self._onTimeout(); // 87
|
|
}, // 88
|
|
// 89
|
|
messageReceived: function () { // 90
|
|
var self = this; // 91
|
|
// Tell periodic checkin that we have seen a packet, and thus it // 92
|
|
// does not need to send a ping this cycle. // 93
|
|
self._seenPacket = true; // 94
|
|
// If we were waiting for a pong, we got it. // 95
|
|
if (self._heartbeatTimeoutHandle) { // 96
|
|
self._clearHeartbeatTimeoutTimer(); // 97
|
|
} // 98
|
|
} // 99
|
|
}); // 100
|
|
// 101
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/ddp-common/utils.js //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
DDPCommon.SUPPORTED_DDP_VERSIONS = [ '1', 'pre2', 'pre1' ]; // 1
|
|
// 2
|
|
DDPCommon.parseDDP = function (stringMessage) { // 3
|
|
try { // 4
|
|
var msg = JSON.parse(stringMessage); // 5
|
|
} catch (e) { // 6
|
|
Meteor._debug("Discarding message with invalid JSON", stringMessage); // 7
|
|
return null; // 8
|
|
} // 9
|
|
// DDP messages must be objects. // 10
|
|
if (msg === null || typeof msg !== 'object') { // 11
|
|
Meteor._debug("Discarding non-object DDP message", stringMessage); // 12
|
|
return null; // 13
|
|
} // 14
|
|
// 15
|
|
// massage msg to get it into "abstract ddp" rather than "wire ddp" format. // 16
|
|
// 17
|
|
// switch between "cleared" rep of unsetting fields and "undefined" // 18
|
|
// rep of same // 19
|
|
if (_.has(msg, 'cleared')) { // 20
|
|
if (!_.has(msg, 'fields')) // 21
|
|
msg.fields = {}; // 22
|
|
_.each(msg.cleared, function (clearKey) { // 23
|
|
msg.fields[clearKey] = undefined; // 24
|
|
}); // 25
|
|
delete msg.cleared; // 26
|
|
} // 27
|
|
// 28
|
|
_.each(['fields', 'params', 'result'], function (field) { // 29
|
|
if (_.has(msg, field)) // 30
|
|
msg[field] = EJSON._adjustTypesFromJSONValue(msg[field]); // 31
|
|
}); // 32
|
|
// 33
|
|
return msg; // 34
|
|
}; // 35
|
|
// 36
|
|
DDPCommon.stringifyDDP = function (msg) { // 37
|
|
var copy = EJSON.clone(msg); // 38
|
|
// swizzle 'changed' messages from 'fields undefined' rep to 'fields // 39
|
|
// and cleared' rep // 40
|
|
if (_.has(msg, 'fields')) { // 41
|
|
var cleared = []; // 42
|
|
_.each(msg.fields, function (value, key) { // 43
|
|
if (value === undefined) { // 44
|
|
cleared.push(key); // 45
|
|
delete copy.fields[key]; // 46
|
|
} // 47
|
|
}); // 48
|
|
if (!_.isEmpty(cleared)) // 49
|
|
copy.cleared = cleared; // 50
|
|
if (_.isEmpty(copy.fields)) // 51
|
|
delete copy.fields; // 52
|
|
} // 53
|
|
// adjust types to basic // 54
|
|
_.each(['fields', 'params', 'result'], function (field) { // 55
|
|
if (_.has(copy, field)) // 56
|
|
copy[field] = EJSON._adjustTypesToJSONValue(copy[field]); // 57
|
|
}); // 58
|
|
if (msg.id && typeof msg.id !== 'string') { // 59
|
|
throw new Error("Message id is not a string"); // 60
|
|
} // 61
|
|
return JSON.stringify(copy); // 62
|
|
}; // 63
|
|
// 64
|
|
// 65
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/ddp-common/method_invocation.js //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Instance name is this because it is usually referred to as this inside a // 1
|
|
// method definition // 2
|
|
/** // 3
|
|
* @summary The state for a single invocation of a method, referenced by this // 4
|
|
* inside a method definition. // 5
|
|
* @param {Object} options // 6
|
|
* @instanceName this // 7
|
|
*/ // 8
|
|
DDPCommon.MethodInvocation = function (options) { // 9
|
|
var self = this; // 10
|
|
// 11
|
|
// true if we're running not the actual method, but a stub (that is, // 12
|
|
// if we're on a client (which may be a browser, or in the future a // 13
|
|
// server connecting to another server) and presently running a // 14
|
|
// simulation of a server-side method for latency compensation // 15
|
|
// purposes). not currently true except in a client such as a browser, // 16
|
|
// since there's usually no point in running stubs unless you have a // 17
|
|
// zero-latency connection to the user. // 18
|
|
// 19
|
|
/** // 20
|
|
* @summary Access inside a method invocation. Boolean value, true if this invocation is a stub. // 21
|
|
* @locus Anywhere // 22
|
|
* @name isSimulation // 23
|
|
* @memberOf DDPCommon.MethodInvocation // 24
|
|
* @instance // 25
|
|
* @type {Boolean} // 26
|
|
*/ // 27
|
|
this.isSimulation = options.isSimulation; // 28
|
|
// 29
|
|
// call this function to allow other method invocations (from the // 30
|
|
// same client) to continue running without waiting for this one to // 31
|
|
// complete. // 32
|
|
this._unblock = options.unblock || function () {}; // 33
|
|
this._calledUnblock = false; // 34
|
|
// 35
|
|
// current user id // 36
|
|
// 37
|
|
/** // 38
|
|
* @summary The id of the user that made this method call, or `null` if no user was logged in. // 39
|
|
* @locus Anywhere // 40
|
|
* @name userId // 41
|
|
* @memberOf DDPCommon.MethodInvocation // 42
|
|
* @instance // 43
|
|
*/ // 44
|
|
this.userId = options.userId; // 45
|
|
// 46
|
|
// sets current user id in all appropriate server contexts and // 47
|
|
// reruns subscriptions // 48
|
|
this._setUserId = options.setUserId || function () {}; // 49
|
|
// 50
|
|
// On the server, the connection this method call came in on. // 51
|
|
// 52
|
|
/** // 53
|
|
* @summary Access inside a method invocation. The [connection](#meteor_onconnection) that this method was received on. `null` if the method is not associated with a connection, eg. a server initiated method call.
|
|
* @locus Server // 55
|
|
* @name connection // 56
|
|
* @memberOf DDPCommon.MethodInvocation // 57
|
|
* @instance // 58
|
|
*/ // 59
|
|
this.connection = options.connection; // 60
|
|
// 61
|
|
// The seed for randomStream value generation // 62
|
|
this.randomSeed = options.randomSeed; // 63
|
|
// 64
|
|
// This is set by RandomStream.get; and holds the random stream state // 65
|
|
this.randomStream = null; // 66
|
|
}; // 67
|
|
// 68
|
|
_.extend(DDPCommon.MethodInvocation.prototype, { // 69
|
|
/** // 70
|
|
* @summary Call inside a method invocation. Allow subsequent method from this client to begin running in a new fiber.
|
|
* @locus Server // 72
|
|
* @memberOf DDPCommon.MethodInvocation // 73
|
|
* @instance // 74
|
|
*/ // 75
|
|
unblock: function () { // 76
|
|
var self = this; // 77
|
|
self._calledUnblock = true; // 78
|
|
self._unblock(); // 79
|
|
}, // 80
|
|
// 81
|
|
/** // 82
|
|
* @summary Set the logged in user. // 83
|
|
* @locus Server // 84
|
|
* @memberOf DDPCommon.MethodInvocation // 85
|
|
* @instance // 86
|
|
* @param {String | null} userId The value that should be returned by `userId` on this connection.
|
|
*/ // 88
|
|
setUserId: function(userId) { // 89
|
|
var self = this; // 90
|
|
if (self._calledUnblock) // 91
|
|
throw new Error("Can't call setUserId in a method after calling unblock"); // 92
|
|
self.userId = userId; // 93
|
|
self._setUserId(userId); // 94
|
|
} // 95
|
|
}); // 96
|
|
// 97
|
|
// 98
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(function(){
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// packages/ddp-common/random_stream.js //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RandomStream allows for generation of pseudo-random values, from a seed. // 1
|
|
// // 2
|
|
// We use this for consistent 'random' numbers across the client and server. // 3
|
|
// We want to generate probably-unique IDs on the client, and we ideally want // 4
|
|
// the server to generate the same IDs when it executes the method. // 5
|
|
// // 6
|
|
// For generated values to be the same, we must seed ourselves the same way, // 7
|
|
// and we must keep track of the current state of our pseudo-random generators. // 8
|
|
// We call this state the scope. By default, we use the current DDP method // 9
|
|
// invocation as our scope. DDP now allows the client to specify a randomSeed. // 10
|
|
// If a randomSeed is provided it will be used to seed our random sequences. // 11
|
|
// In this way, client and server method calls will generate the same values. // 12
|
|
// // 13
|
|
// We expose multiple named streams; each stream is independent // 14
|
|
// and is seeded differently (but predictably from the name). // 15
|
|
// By using multiple streams, we support reordering of requests, // 16
|
|
// as long as they occur on different streams. // 17
|
|
// // 18
|
|
// @param options {Optional Object} // 19
|
|
// seed: Array or value - Seed value(s) for the generator. // 20
|
|
// If an array, will be used as-is // 21
|
|
// If a value, will be converted to a single-value array // 22
|
|
// If omitted, a random array will be used as the seed. // 23
|
|
DDPCommon.RandomStream = function (options) { // 24
|
|
var self = this; // 25
|
|
// 26
|
|
this.seed = [].concat(options.seed || randomToken()); // 27
|
|
// 28
|
|
this.sequences = {}; // 29
|
|
}; // 30
|
|
// 31
|
|
// Returns a random string of sufficient length for a random seed. // 32
|
|
// This is a placeholder function; a similar function is planned // 33
|
|
// for Random itself; when that is added we should remove this function, // 34
|
|
// and call Random's randomToken instead. // 35
|
|
function randomToken() { // 36
|
|
return Random.hexString(20); // 37
|
|
}; // 38
|
|
// 39
|
|
// Returns the random stream with the specified name, in the specified // 40
|
|
// scope. If a scope is passed, then we use that to seed a (not // 41
|
|
// cryptographically secure) PRNG using the fast Alea algorithm. If // 42
|
|
// scope is null (or otherwise falsey) then we use a generated seed. // 43
|
|
// // 44
|
|
// However, scope will normally be the current DDP method invocation, // 45
|
|
// so we'll use the stream with the specified name, and we should get // 46
|
|
// consistent values on the client and server sides of a method call. // 47
|
|
DDPCommon.RandomStream.get = function (scope, name) { // 48
|
|
if (!name) { // 49
|
|
name = "default"; // 50
|
|
} // 51
|
|
if (!scope) { // 52
|
|
// There was no scope passed in; the sequence won't actually be // 53
|
|
// reproducible. but make it fast (and not cryptographically // 54
|
|
// secure) anyways, so that the behavior is similar to what you'd // 55
|
|
// get by passing in a scope. // 56
|
|
return Random.insecure; // 57
|
|
} // 58
|
|
var randomStream = scope.randomStream; // 59
|
|
if (!randomStream) { // 60
|
|
scope.randomStream = randomStream = new DDPCommon.RandomStream({ // 61
|
|
seed: scope.randomSeed // 62
|
|
}); // 63
|
|
} // 64
|
|
return randomStream._sequence(name); // 65
|
|
}; // 66
|
|
// 67
|
|
// 68
|
|
// Creates a randomSeed for passing to a method call. // 69
|
|
// Note that we take enclosing as an argument, // 70
|
|
// though we expect it to be DDP._CurrentInvocation.get() // 71
|
|
// However, we often evaluate makeRpcSeed lazily, and thus the relevant // 72
|
|
// invocation may not be the one currently in scope. // 73
|
|
// If enclosing is null, we'll use Random and values won't be repeatable. // 74
|
|
DDPCommon.makeRpcSeed = function (enclosing, methodName) { // 75
|
|
var stream = DDPCommon.RandomStream.get(enclosing, '/rpc/' + methodName); // 76
|
|
return stream.hexString(20); // 77
|
|
}; // 78
|
|
// 79
|
|
_.extend(DDPCommon.RandomStream.prototype, { // 80
|
|
// Get a random sequence with the specified name, creating it if does not exist. // 81
|
|
// New sequences are seeded with the seed concatenated with the name. // 82
|
|
// By passing a seed into Random.create, we use the Alea generator. // 83
|
|
_sequence: function (name) { // 84
|
|
var self = this; // 85
|
|
// 86
|
|
var sequence = self.sequences[name] || null; // 87
|
|
if (sequence === null) { // 88
|
|
var sequenceSeed = self.seed.concat(name); // 89
|
|
for (var i = 0; i < sequenceSeed.length; i++) { // 90
|
|
if (_.isFunction(sequenceSeed[i])) { // 91
|
|
sequenceSeed[i] = sequenceSeed[i](); // 92
|
|
} // 93
|
|
} // 94
|
|
self.sequences[name] = sequence = Random.createWithSeeds.apply(null, sequenceSeed); // 95
|
|
} // 96
|
|
return sequence; // 97
|
|
} // 98
|
|
}); // 99
|
|
// 100
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
}).call(this);
|
|
|
|
|
|
/* Exports */
|
|
if (typeof Package === 'undefined') Package = {};
|
|
Package['ddp-common'] = {
|
|
DDPCommon: DDPCommon
|
|
};
|
|
|
|
})();
|
|
|
|
//# sourceMappingURL=ddp-common.js.map
|