mongodb-livedata-server 0.0.4 → 0.0.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.
Files changed (93) hide show
  1. package/{livedata_server.ts → dist/livedata_server.d.ts} +1 -1
  2. package/dist/livedata_server.js +3 -1
  3. package/dist/meteor/binary-heap/max_heap.d.ts +31 -0
  4. package/dist/meteor/binary-heap/min_heap.d.ts +6 -0
  5. package/dist/meteor/binary-heap/min_max_heap.d.ts +11 -0
  6. package/dist/meteor/callback-hook/hook.d.ts +11 -0
  7. package/dist/meteor/ddp/crossbar.d.ts +15 -0
  8. package/dist/meteor/ddp/heartbeat.d.ts +19 -0
  9. package/dist/meteor/ddp/livedata_server.d.ts +141 -0
  10. package/dist/meteor/ddp/method-invocation.d.ts +25 -0
  11. package/dist/meteor/ddp/random-stream.d.ts +8 -0
  12. package/dist/meteor/ddp/session-collection-view.d.ts +27 -0
  13. package/dist/meteor/ddp/session-document-view.d.ts +8 -0
  14. package/dist/meteor/ddp/session.d.ts +69 -0
  15. package/dist/meteor/ddp/stream_server.d.ts +21 -0
  16. package/dist/meteor/ddp/subscription.d.ts +89 -0
  17. package/dist/meteor/ddp/utils.d.ts +8 -0
  18. package/dist/meteor/ddp/writefence.d.ts +20 -0
  19. package/dist/meteor/diff-sequence/diff.d.ts +13 -0
  20. package/dist/meteor/ejson/ejson.d.ts +82 -0
  21. package/dist/meteor/ejson/stringify.d.ts +2 -0
  22. package/dist/meteor/ejson/utils.d.ts +12 -0
  23. package/dist/meteor/id-map/id_map.d.ts +16 -0
  24. package/dist/meteor/mongo/caching_change_observer.d.ts +16 -0
  25. package/dist/meteor/mongo/doc_fetcher.d.ts +7 -0
  26. package/dist/meteor/mongo/geojson_utils.d.ts +3 -0
  27. package/dist/meteor/mongo/live_connection.d.ts +27 -0
  28. package/dist/meteor/mongo/live_cursor.d.ts +25 -0
  29. package/dist/meteor/mongo/minimongo_common.d.ts +84 -0
  30. package/dist/meteor/mongo/minimongo_matcher.d.ts +22 -0
  31. package/dist/meteor/mongo/minimongo_sorter.d.ts +16 -0
  32. package/dist/meteor/mongo/observe_driver_utils.d.ts +9 -0
  33. package/dist/meteor/mongo/observe_multiplexer.d.ts +36 -0
  34. package/dist/meteor/mongo/oplog-observe-driver.d.ts +67 -0
  35. package/dist/meteor/mongo/oplog_tailing.d.ts +35 -0
  36. package/dist/meteor/mongo/oplog_v2_converter.d.ts +1 -0
  37. package/dist/meteor/mongo/polling_observe_driver.d.ts +30 -0
  38. package/dist/meteor/mongo/synchronous-cursor.d.ts +17 -0
  39. package/dist/meteor/mongo/synchronous-queue.d.ts +14 -0
  40. package/dist/meteor/ordered-dict/ordered_dict.d.ts +31 -0
  41. package/dist/meteor/random/AbstractRandomGenerator.d.ts +42 -0
  42. package/dist/meteor/random/AleaRandomGenerator.d.ts +13 -0
  43. package/dist/meteor/random/NodeRandomGenerator.d.ts +16 -0
  44. package/dist/meteor/random/createAleaGenerator.d.ts +2 -0
  45. package/dist/meteor/random/createRandom.d.ts +1 -0
  46. package/dist/meteor/random/main.d.ts +1 -0
  47. package/package.json +2 -2
  48. package/meteor/LICENSE +0 -28
  49. package/meteor/binary-heap/max_heap.ts +0 -225
  50. package/meteor/binary-heap/min_heap.ts +0 -15
  51. package/meteor/binary-heap/min_max_heap.ts +0 -53
  52. package/meteor/callback-hook/hook.ts +0 -85
  53. package/meteor/ddp/crossbar.ts +0 -148
  54. package/meteor/ddp/heartbeat.ts +0 -97
  55. package/meteor/ddp/livedata_server.ts +0 -474
  56. package/meteor/ddp/method-invocation.ts +0 -86
  57. package/meteor/ddp/random-stream.ts +0 -102
  58. package/meteor/ddp/session-collection-view.ts +0 -119
  59. package/meteor/ddp/session-document-view.ts +0 -92
  60. package/meteor/ddp/session.ts +0 -708
  61. package/meteor/ddp/stream_server.ts +0 -204
  62. package/meteor/ddp/subscription.ts +0 -392
  63. package/meteor/ddp/utils.ts +0 -119
  64. package/meteor/ddp/writefence.ts +0 -130
  65. package/meteor/diff-sequence/diff.ts +0 -295
  66. package/meteor/ejson/ejson.ts +0 -601
  67. package/meteor/ejson/stringify.ts +0 -122
  68. package/meteor/ejson/utils.ts +0 -38
  69. package/meteor/id-map/id_map.ts +0 -84
  70. package/meteor/mongo/caching_change_observer.ts +0 -120
  71. package/meteor/mongo/doc_fetcher.ts +0 -52
  72. package/meteor/mongo/geojson_utils.ts +0 -42
  73. package/meteor/mongo/live_connection.ts +0 -302
  74. package/meteor/mongo/live_cursor.ts +0 -79
  75. package/meteor/mongo/minimongo_common.ts +0 -2440
  76. package/meteor/mongo/minimongo_matcher.ts +0 -275
  77. package/meteor/mongo/minimongo_sorter.ts +0 -331
  78. package/meteor/mongo/observe_driver_utils.ts +0 -79
  79. package/meteor/mongo/observe_multiplexer.ts +0 -256
  80. package/meteor/mongo/oplog-observe-driver.ts +0 -1049
  81. package/meteor/mongo/oplog_tailing.ts +0 -414
  82. package/meteor/mongo/oplog_v2_converter.ts +0 -124
  83. package/meteor/mongo/polling_observe_driver.ts +0 -247
  84. package/meteor/mongo/synchronous-cursor.ts +0 -293
  85. package/meteor/mongo/synchronous-queue.ts +0 -119
  86. package/meteor/ordered-dict/ordered_dict.ts +0 -229
  87. package/meteor/random/AbstractRandomGenerator.ts +0 -99
  88. package/meteor/random/AleaRandomGenerator.ts +0 -96
  89. package/meteor/random/NodeRandomGenerator.ts +0 -37
  90. package/meteor/random/createAleaGenerator.ts +0 -31
  91. package/meteor/random/createRandom.ts +0 -19
  92. package/meteor/random/main.ts +0 -8
  93. package/tsconfig.json +0 -10
@@ -1,474 +0,0 @@
1
- import { MethodInvocation } from "./method-invocation";
2
- import { StreamServer, StreamServerSocket } from "./stream_server";
3
- import { DDPSession, SessionConnectionHandle } from "./session";
4
- import { Server } from "http";
5
- import { parseDDP, stringifyDDP, SUPPORTED_DDP_VERSIONS } from "./utils";
6
- import { makeRpcSeed } from "./random-stream";
7
- import { clone } from "../ejson/ejson";
8
- import { Hook } from "../callback-hook/hook";
9
- import { Subscription } from "./subscription";
10
-
11
- export const DDP: {
12
- _CurrentPublicationInvocation: Subscription,
13
- _CurrentMethodInvocation: MethodInvocation
14
- } = {} as any;
15
-
16
- // This file contains classes:
17
- // * Session - The server's connection to a single DDP client
18
- // * Subscription - A single subscription for a single client
19
- // * Server - An entire server that may talk to > 1 client. A DDP endpoint.
20
- //
21
- // Session and Subscription are file scope. For now, until we freeze
22
- // the interface, Server is package scope (in the future it should be
23
- // exported).
24
-
25
-
26
- /******************************************************************************/
27
- /* Server */
28
- /******************************************************************************/
29
-
30
- interface PublicationStrategy {
31
- useCollectionView: boolean;
32
- doAccountingForCollection: boolean;
33
- }
34
-
35
- export class DDPServer {
36
- private options: {
37
- heartbeatInterval: number;
38
- heartbeatTimeout: number;
39
- // For testing, allow responding to pings to be disabled.
40
- respondToPings: boolean;
41
- defaultPublicationStrategy: PublicationStrategy;
42
- };
43
-
44
- private onConnectionHook: Hook;
45
- private onMessageHook: Hook;
46
-
47
- private publish_handlers: Record<string, any> = {};
48
- private universal_publish_handlers = [];
49
- private method_handlers = {};
50
- private _publicationStrategies = {};
51
- private sessions = new Map<string, DDPSession>(); // map from id to session
52
- private stream_server: StreamServer;
53
-
54
- constructor (options = {}, httpServer: Server) {
55
- var self = this;
56
-
57
- // The default heartbeat interval is 30 seconds on the server and 35
58
- // seconds on the client. Since the client doesn't need to send a
59
- // ping as long as it is receiving pings, this means that pings
60
- // normally go from the server to the client.
61
- //
62
- // Note: Troposphere depends on the ability to mutate
63
- // Meteor.server.options.heartbeatTimeout! This is a hack, but it's life.
64
- self.options = {
65
- heartbeatInterval: 15000,
66
- heartbeatTimeout: 15000,
67
- // For testing, allow responding to pings to be disabled.
68
- respondToPings: true,
69
- defaultPublicationStrategy: DDPServer.publicationStrategies.SERVER_MERGE,
70
- ...options,
71
- };
72
-
73
- // Map of callbacks to call when a new connection comes in to the
74
- // server and completes DDP version negotiation. Use an object instead
75
- // of an array so we can safely remove one from the list while
76
- // iterating over it.
77
- self.onConnectionHook = new Hook({
78
- debugPrintExceptions: "onConnection callback"
79
- });
80
-
81
- // Map of callbacks to call when a new message comes in.
82
- self.onMessageHook = new Hook({
83
- debugPrintExceptions: "onMessage callback"
84
- });
85
-
86
-
87
- self.stream_server = new StreamServer(httpServer);
88
-
89
- self.stream_server.register(function (socket) {
90
- // socket implements the SockJSConnection interface
91
- socket._meteorSession = null;
92
-
93
- var sendError = function (reason, offendingMessage?) {
94
- var msg = { msg: 'error', reason, offendingMessage };
95
- socket.send(stringifyDDP(msg));
96
- };
97
-
98
- socket.on('data', async function (raw_msg) {
99
- try {
100
- try {
101
- var msg = parseDDP(raw_msg);
102
- } catch (err) {
103
- sendError('Parse error');
104
- return;
105
- }
106
- if (msg === null || !msg.msg) {
107
- sendError('Bad request', msg);
108
- return;
109
- }
110
-
111
- if (msg.msg === 'connect') {
112
- if (socket._meteorSession) {
113
- sendError("Already connected", msg);
114
- return;
115
- }
116
- self._handleConnect(socket, msg);
117
- return;
118
- }
119
-
120
- if (!socket._meteorSession) {
121
- sendError('Must connect first', msg);
122
- return;
123
- }
124
- await socket._meteorSession.processMessage(msg);
125
- } catch (e) {
126
- // XXX print stack nicely
127
- console.log("Internal exception while processing message", msg, e);
128
- }
129
- });
130
-
131
- socket.on('close', function () {
132
- if (socket._meteorSession) {
133
- socket._meteorSession.close();
134
- }
135
- });
136
- });
137
- }
138
-
139
- // Publication strategies define how we handle data from published cursors at the collection level
140
- // This allows someone to:
141
- // - Choose a trade-off between client-server bandwidth and server memory usage
142
- // - Implement special (non-mongo) collections like volatile message queues
143
- public static publicationStrategies = {
144
- // SERVER_MERGE is the default strategy.
145
- // When using this strategy, the server maintains a copy of all data a connection is subscribed to.
146
- // This allows us to only send deltas over multiple publications.
147
- SERVER_MERGE: {
148
- useCollectionView: true,
149
- doAccountingForCollection: true,
150
- },
151
- // The NO_MERGE_NO_HISTORY strategy results in the server sending all publication data
152
- // directly to the client. It does not remember what it has previously sent
153
- // to it will not trigger removed messages when a subscription is stopped.
154
- // This should only be chosen for special use cases like send-and-forget queues.
155
- NO_MERGE_NO_HISTORY: {
156
- useCollectionView: false,
157
- doAccountingForCollection: false,
158
- },
159
- // NO_MERGE is similar to NO_MERGE_NO_HISTORY but the server will remember the IDs it has
160
- // sent to the client so it can remove them when a subscription is stopped.
161
- // This strategy can be used when a collection is only used in a single publication.
162
- NO_MERGE: {
163
- useCollectionView: false,
164
- doAccountingForCollection: true,
165
- }
166
- }
167
-
168
- /**
169
- * @summary Register a callback to be called when a new DDP connection is made to the server.
170
- * @locus Server
171
- * @param {function} callback The function to call when a new DDP connection is established.
172
- * @memberOf Meteor
173
- * @importFromPackage meteor
174
- */
175
- onConnection(fn: (conn: SessionConnectionHandle) => void) {
176
- var self = this;
177
- return self.onConnectionHook.register(fn);
178
- }
179
-
180
- /**
181
- * @summary Set publication strategy for the given publication. Publications strategies are available from `DDPServer.publicationStrategies`. You call this method from `Meteor.server`, like `Meteor.server.setPublicationStrategy()`
182
- * @locus Server
183
- * @alias setPublicationStrategy
184
- * @param publicationName {String}
185
- * @param strategy {{useCollectionView: boolean, doAccountingForCollection: boolean}}
186
- * @memberOf Meteor.server
187
- * @importFromPackage meteor
188
- */
189
- setPublicationStrategy(publicationName: string, strategy: PublicationStrategy) {
190
- if (!Object.values(DDPServer.publicationStrategies).includes(strategy)) {
191
- throw new Error(`Invalid merge strategy: ${strategy}
192
- for collection ${publicationName}`);
193
- }
194
- this._publicationStrategies[publicationName] = strategy;
195
- }
196
-
197
- /**
198
- * @summary Gets the publication strategy for the requested publication. You call this method from `Meteor.server`, like `Meteor.server.getPublicationStrategy()`
199
- * @locus Server
200
- * @alias getPublicationStrategy
201
- * @param publicationName {String}
202
- * @memberOf Meteor.server
203
- * @importFromPackage meteor
204
- * @return {{useCollectionView: boolean, doAccountingForCollection: boolean}}
205
- */
206
- getPublicationStrategy(publicationName: string): PublicationStrategy {
207
- return this._publicationStrategies[publicationName]
208
- || this.options.defaultPublicationStrategy;
209
- }
210
-
211
- /**
212
- * @summary Register a callback to be called when a new DDP message is received.
213
- * @locus Server
214
- * @param {function} callback The function to call when a new DDP message is received.
215
- * @memberOf Meteor
216
- * @importFromPackage meteor
217
- */
218
- onMessage(fn) {
219
- var self = this;
220
- return self.onMessageHook.register(fn);
221
- }
222
-
223
- _handleConnect(socket: StreamServerSocket, msg: any) {
224
- var self = this;
225
-
226
- // The connect message must specify a version and an array of supported
227
- // versions, and it must claim to support what it is proposing.
228
- if (!(
229
- typeof (msg.version) === 'string' &&
230
- Array.isArray(msg.support) &&
231
- msg.support.every(s => typeof s === "string") &&
232
- msg.support.includes(msg.version)
233
- ))
234
- {
235
- socket.send(stringifyDDP({
236
- msg: 'failed',
237
- version: SUPPORTED_DDP_VERSIONS[0]
238
- }));
239
- socket.close();
240
- return;
241
- }
242
-
243
- // In the future, handle session resumption: something like:
244
- // socket._meteorSession = self.sessions[msg.session]
245
- var version = _calculateVersion(msg.support, SUPPORTED_DDP_VERSIONS);
246
-
247
- if (msg.version !== version) {
248
- // The best version to use (according to the client's stated preferences)
249
- // is not the one the client is trying to use. Inform them about the best
250
- // version to use.
251
- socket.send(stringifyDDP({ msg: 'failed', version: version }));
252
- socket.close();
253
- return;
254
- }
255
-
256
- // Yay, version matches! Create a new session.
257
- // Note: Troposphere depends on the ability to mutate
258
- // Meteor.server.options.heartbeatTimeout! This is a hack, but it's life.
259
- socket._meteorSession = new DDPSession(self, version, socket, self.options);
260
- self.sessions.set(socket._meteorSession.id, socket._meteorSession);
261
- self.onConnectionHook.each(function (callback) {
262
- if (socket._meteorSession)
263
- callback(socket._meteorSession.connectionHandle);
264
- return true;
265
- });
266
- }
267
-
268
- /**
269
- * Register a publish handler function.
270
- *
271
- * @param name {String} identifier for query
272
- * @param handler {Function} publish handler
273
- *
274
- * Server will call handler function on each new subscription,
275
- * either when receiving DDP sub message for a named subscription, or on
276
- * DDP connect for a universal subscription.
277
- *
278
- * If name is null, this will be a subscription that is
279
- * automatically established and permanently on for all connected
280
- * client, instead of a subscription that can be turned on and off
281
- * with subscribe().
282
- *
283
- */
284
-
285
- /**
286
- * @summary Publish a record set.
287
- * @memberOf Meteor
288
- * @importFromPackage meteor
289
- * @locus Server
290
- * @param {String|Object} name If String, name of the record set. If Object, publications Dictionary of publish functions by name. If `null`, the set has no name, and the record set is automatically sent to all connected clients.
291
- * @param {Function} func Function called on the server each time a client subscribes. Inside the function, `this` is the publish handler object, described below. If the client passed arguments to `subscribe`, the function is called with the same arguments.
292
- */
293
- publish(name: string | Record<string, (this: MethodInvocation, ...args: any[]) => Promise<any>> | null, handler?: (this: MethodInvocation, ...args: any[]) => Promise<any>) {
294
- var self = this;
295
-
296
- if (typeof name === "string") {
297
- if (name in self.publish_handlers) {
298
- console.log("Ignoring duplicate publish named '" + name + "'");
299
- return;
300
- }
301
-
302
- self.publish_handlers[name] = handler;
303
- } else if (name == null) {
304
- self.universal_publish_handlers.push(handler);
305
- // Spin up the new publisher on any existing session too. Run each
306
- // session's subscription in a new Fiber, so that there's no change for
307
- // self.sessions to change while we're running this loop.
308
- self.sessions.forEach(function (session) {
309
- if (!session._dontStartNewUniversalSubs) {
310
- session._startSubscription(handler);
311
- }
312
- });
313
- }
314
- else {
315
- for (const [key, value] of Object.entries(name)) {
316
- self.publish(key, value);
317
- }
318
- }
319
- }
320
-
321
- _removeSession(session: DDPSession) {
322
- this.sessions.delete(session.id);
323
- }
324
-
325
- /**
326
- * @summary Defines functions that can be invoked over the network by clients.
327
- * @locus Anywhere
328
- * @param {Object} methods Dictionary whose keys are method names and values are functions.
329
- * @memberOf Meteor
330
- * @importFromPackage meteor
331
- */
332
- methods(methods: Record<string, (this: MethodInvocation, ...args: any[]) => Promise<any>>) {
333
- var self = this;
334
- for (const [name, func] of Object.entries(methods)) {
335
- if (typeof func !== 'function')
336
- throw new Error("Method '" + name + "' must be a function");
337
- if (self.method_handlers[name])
338
- throw new Error("A method named '" + name + "' is already defined");
339
- self.method_handlers[name] = func;
340
- }
341
- }
342
-
343
- // A version of the call method that always returns a Promise.
344
- callAsync(name: string, ...args: any[]) {
345
- return this.applyAsync(name, args);
346
- }
347
-
348
- // @param options {Optional Object}
349
- applyAsync(name: string, args: any[]) {
350
- // Run the handler
351
- var handler = this.method_handlers[name];
352
- if (!handler) {
353
- return Promise.reject(
354
- ddpError(404, `Method '${name}' not found`)
355
- );
356
- }
357
-
358
- // If this is a method call from within another method or publish function,
359
- // get the user state from the outer method or publish function, otherwise
360
- // don't allow setUserId to be called
361
- var userId = null;
362
- var setUserId: (userId: string) => void = function () {
363
- throw new Error("Can't call setUserId on a server initiated method call");
364
- };
365
- var connection = null;
366
- var currentMethodInvocation = DDP._CurrentMethodInvocation;
367
- var currentPublicationInvocation = DDP._CurrentPublicationInvocation;
368
- var randomSeed = null;
369
- if (currentMethodInvocation) {
370
- userId = currentMethodInvocation.userId;
371
- setUserId = function (userId) {
372
- currentMethodInvocation.setUserId(userId);
373
- };
374
- connection = currentMethodInvocation.connection;
375
- randomSeed = makeRpcSeed(currentMethodInvocation, name);
376
- } else if (currentPublicationInvocation) {
377
- userId = currentPublicationInvocation.userId;
378
- setUserId = function (userId) {
379
- currentPublicationInvocation._session._setUserId(userId);
380
- };
381
- connection = currentPublicationInvocation.connection;
382
- }
383
-
384
- var invocation = new MethodInvocation({
385
- isSimulation: false,
386
- userId,
387
- setUserId,
388
- connection,
389
- randomSeed
390
- });
391
-
392
- return new Promise(resolve => {
393
- const oldInvocation = DDP._CurrentMethodInvocation;
394
- try {
395
- DDP._CurrentMethodInvocation = invocation;
396
- const result = maybeAuditArgumentChecks(handler, invocation, clone(args), "internal call to '" + name + "'");
397
- resolve(result);
398
- } finally {
399
- DDP._CurrentMethodInvocation = oldInvocation;
400
- }
401
- }).then(clone);
402
- }
403
-
404
- _urlForSession(sessionId) {
405
- var self = this;
406
- var session = self.sessions.get(sessionId);
407
- if (session)
408
- return session._socketUrl;
409
- else
410
- return null;
411
- }
412
- }
413
-
414
- export function _calculateVersion(clientSupportedVersions, serverSupportedVersions) {
415
- var correctVersion = clientSupportedVersions.find(version => serverSupportedVersions.includes(version));
416
- if (!correctVersion) {
417
- correctVersion = serverSupportedVersions[0];
418
- }
419
- return correctVersion;
420
- };
421
-
422
-
423
- // "blind" exceptions other than those that were deliberately thrown to signal
424
- // errors to the client
425
- export function wrapInternalException(exception, context) {
426
- if (!exception) return exception;
427
-
428
- // To allow packages to throw errors intended for the client but not have to
429
- // depend on the Meteor.Error class, `isClientSafe` can be set to true on any
430
- // error before it is thrown.
431
- if (exception.isClientSafe) {
432
- if (!(exception instanceof ClientSafeError)) {
433
- const originalMessage = exception.message;
434
- exception = ddpError(exception.error, exception.reason, exception.details);
435
- exception.message = originalMessage;
436
- }
437
- return exception;
438
- }
439
-
440
- // Did the error contain more details that could have been useful if caught in
441
- // server code (or if thrown from non-client-originated code), but also
442
- // provided a "sanitized" version with more context than 500 Internal server
443
- // error? Use that.
444
- if (exception.sanitizedError) {
445
- if (exception.sanitizedError.isClientSafe)
446
- return exception.sanitizedError;
447
- }
448
-
449
- return ddpError(500, "Internal server error");
450
- };
451
-
452
-
453
- // Audit argument checks, if the audit-argument-checks package exists (it is a
454
- // weak dependency of this package).
455
- export function maybeAuditArgumentChecks(f: Function, context: any, args: any[] | null, description: string) {
456
- args = args || [];
457
- /*if (Package['audit-argument-checks']) {
458
- return Match._failIfArgumentsAreNotAllChecked(
459
- f, context, args, description);
460
- }*/
461
- return f.apply(context, args);
462
- };
463
-
464
- export function ddpError(error: string | number, reason?: string, details?: string) {
465
- return { isClientSafe: true, error, reason, message: (reason ? reason + " " : "") + "[" + error + "]", errorType: "Meteor.Error" };
466
- }
467
-
468
- export class ClientSafeError extends Error {
469
- constructor(public error: string | number, public reason?: string, public details?: string) {
470
- super((reason ? reason + " " : "") + "[" + error + "]");
471
- }
472
- public isClientSafe = true;
473
- public errorType = "Meteor.Error";
474
- }
@@ -1,86 +0,0 @@
1
- // Instance name is this because it is usually referred to as this inside a
2
- // method definition
3
- /**
4
- * @summary The state for a single invocation of a method, referenced by this
5
- * inside a method definition.
6
- * @param {Object} options
7
- * @instanceName this
8
- * @showInstanceName true
9
- */
10
- export class MethodInvocation {
11
- public userId: string;
12
- public connection: any;
13
-
14
- private isSimulation: boolean;
15
- private _isFromCallAsync: boolean;
16
- private _setUserId: Function;
17
- private randomSeed: number;
18
- private randomStream: any;
19
-
20
- constructor(options) {
21
- // true if we're running not the actual method, but a stub (that is,
22
- // if we're on a client (which may be a browser, or in the future a
23
- // server connecting to another server) and presently running a
24
- // simulation of a server-side method for latency compensation
25
- // purposes). not currently true except in a client such as a browser,
26
- // since there's usually no point in running stubs unless you have a
27
- // zero-latency connection to the user.
28
-
29
- /**
30
- * @summary Access inside a method invocation. Boolean value, true if this invocation is a stub.
31
- * @locus Anywhere
32
- * @name isSimulation
33
- * @memberOf DDPCommon.MethodInvocation
34
- * @instance
35
- * @type {Boolean}
36
- */
37
- this.isSimulation = options.isSimulation;
38
-
39
- // used to know when the function apply was called by callAsync
40
- this._isFromCallAsync = options.isFromCallAsync;
41
-
42
- // current user id
43
-
44
- /**
45
- * @summary The id of the user that made this method call, or `null` if no user was logged in.
46
- * @locus Anywhere
47
- * @name userId
48
- * @memberOf DDPCommon.MethodInvocation
49
- * @instance
50
- */
51
- this.userId = options.userId;
52
-
53
- // sets current user id in all appropriate server contexts and
54
- // reruns subscriptions
55
- this._setUserId = options.setUserId || function () {};
56
-
57
- // On the server, the connection this method call came in on.
58
-
59
- /**
60
- * @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. Calls to methods made from a server method which was in turn initiated from the client share the same `connection`.
61
- * @locus Server
62
- * @name connection
63
- * @memberOf DDPCommon.MethodInvocation
64
- * @instance
65
- */
66
- this.connection = options.connection;
67
-
68
- // The seed for randomStream value generation
69
- this.randomSeed = options.randomSeed;
70
-
71
- // This is set by RandomStream.get; and holds the random stream state
72
- this.randomStream = null;
73
- }
74
-
75
- /**
76
- * @summary Set the logged in user.
77
- * @locus Server
78
- * @memberOf DDPCommon.MethodInvocation
79
- * @instance
80
- * @param {String | null} userId The value that should be returned by `userId` on this connection.
81
- */
82
- setUserId(userId: string | null) {
83
- this.userId = userId;
84
- this._setUserId(userId);
85
- }
86
- };
@@ -1,102 +0,0 @@
1
- // RandomStream allows for generation of pseudo-random values, from a seed.
2
- //
3
- // We use this for consistent 'random' numbers across the client and server.
4
- // We want to generate probably-unique IDs on the client, and we ideally want
5
- // the server to generate the same IDs when it executes the method.
6
- //
7
- // For generated values to be the same, we must seed ourselves the same way,
8
- // and we must keep track of the current state of our pseudo-random generators.
9
- // We call this state the scope. By default, we use the current DDP method
10
- // invocation as our scope. DDP now allows the client to specify a randomSeed.
11
- // If a randomSeed is provided it will be used to seed our random sequences.
12
- // In this way, client and server method calls will generate the same values.
13
- //
14
- // We expose multiple named streams; each stream is independent
15
- // and is seeded differently (but predictably from the name).
16
- // By using multiple streams, we support reordering of requests,
17
- // as long as they occur on different streams.
18
- //
19
- // @param options {Optional Object}
20
- // seed: Array or value - Seed value(s) for the generator.
21
- // If an array, will be used as-is
22
- // If a value, will be converted to a single-value array
23
-
24
- import { Random } from "../random/main";
25
-
26
- // If omitted, a random array will be used as the seed.
27
- export class RandomStream {
28
- private seed: Function[];
29
- private sequences: Object;
30
-
31
- constructor(options) {
32
- this.seed = [].concat(options.seed || randomToken());
33
- this.sequences = Object.create(null);
34
- }
35
-
36
- // Get a random sequence with the specified name, creating it if does not exist.
37
- // New sequences are seeded with the seed concatenated with the name.
38
- // By passing a seed into Random.create, we use the Alea generator.
39
- _sequence(name) {
40
- var self = this;
41
-
42
- var sequence = self.sequences[name] || null;
43
- if (sequence === null) {
44
- var sequenceSeed = self.seed.concat(name);
45
- for (var i = 0; i < sequenceSeed.length; i++) {
46
- if (typeof sequenceSeed[i] === "function") {
47
- sequenceSeed[i] = sequenceSeed[i]();
48
- }
49
- }
50
- self.sequences[name] = sequence = Random.createWithSeeds.apply(null, sequenceSeed);
51
- }
52
- return sequence;
53
- }
54
-
55
- // Returns the random stream with the specified name, in the specified
56
- // scope. If a scope is passed, then we use that to seed a (not
57
- // cryptographically secure) PRNG using the fast Alea algorithm. If
58
- // scope is null (or otherwise falsey) then we use a generated seed.
59
- //
60
- // However, scope will normally be the current DDP method invocation,
61
- // so we'll use the stream with the specified name, and we should get
62
- // consistent values on the client and server sides of a method call.
63
- static get(scope, name) {
64
- if (!name) {
65
- name = "default";
66
- }
67
- if (!scope) {
68
- // There was no scope passed in; the sequence won't actually be
69
- // reproducible. but make it fast (and not cryptographically
70
- // secure) anyways, so that the behavior is similar to what you'd
71
- // get by passing in a scope.
72
- return Random.insecure;
73
- }
74
- var randomStream = scope.randomStream;
75
- if (!randomStream) {
76
- scope.randomStream = randomStream = new RandomStream({
77
- seed: scope.randomSeed
78
- });
79
- }
80
- return randomStream._sequence(name);
81
- };
82
-
83
- };
84
-
85
- // Returns a random string of sufficient length for a random seed.
86
- // This is a placeholder function; a similar function is planned
87
- // for Random itself; when that is added we should remove this function,
88
- // and call Random's randomToken instead.
89
- function randomToken() {
90
- return Random.hexString(20);
91
- };
92
-
93
- // Creates a randomSeed for passing to a method call.
94
- // Note that we take enclosing as an argument,
95
- // though we expect it to be DDP._CurrentMethodInvocation.get()
96
- // However, we often evaluate makeRpcSeed lazily, and thus the relevant
97
- // invocation may not be the one currently in scope.
98
- // If enclosing is null, we'll use Random and values won't be repeatable.
99
- export function makeRpcSeed(enclosing, methodName) {
100
- var stream = RandomStream.get(enclosing, '/rpc/' + methodName);
101
- return stream.hexString(20);
102
- };