mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
86 lines
3.4 KiB
JavaScript
86 lines
3.4 KiB
JavaScript
// A MethodInvoker manages sending a method to the server and calling the user's
|
|
// callbacks. On construction, it registers itself in the connection's
|
|
// _methodInvokers map; it removes itself once the method is fully finished and
|
|
// the callback is invoked. This occurs when it has both received a result,
|
|
// and the data written by it is fully visible.
|
|
export default class MethodInvoker {
|
|
constructor(options) {
|
|
// Public (within this file) fields.
|
|
this.methodId = options.methodId;
|
|
this.sentMessage = false;
|
|
|
|
this._callback = options.callback;
|
|
this._connection = options.connection;
|
|
this._message = options.message;
|
|
this._onResultReceived = options.onResultReceived || (() => {});
|
|
this._wait = options.wait;
|
|
this.noRetry = options.noRetry;
|
|
this._methodResult = null;
|
|
this._dataVisible = false;
|
|
|
|
// Register with the connection.
|
|
this._connection._methodInvokers[this.methodId] = this;
|
|
}
|
|
// Sends the method message to the server. May be called additional times if
|
|
// we lose the connection and reconnect before receiving a result.
|
|
sendMessage() {
|
|
// This function is called before sending a method (including resending on
|
|
// reconnect). We should only (re)send methods where we don't already have a
|
|
// result!
|
|
if (this.gotResult())
|
|
throw new Error('sendingMethod is called on method with result');
|
|
|
|
// If we're re-sending it, it doesn't matter if data was written the first
|
|
// time.
|
|
this._dataVisible = false;
|
|
this.sentMessage = true;
|
|
|
|
// If this is a wait method, make all data messages be buffered until it is
|
|
// done.
|
|
if (this._wait)
|
|
this._connection._methodsBlockingQuiescence[this.methodId] = true;
|
|
|
|
// Actually send the message.
|
|
this._connection._send(this._message);
|
|
}
|
|
// Invoke the callback, if we have both a result and know that all data has
|
|
// been written to the local cache.
|
|
_maybeInvokeCallback() {
|
|
if (this._methodResult && this._dataVisible) {
|
|
// Call the callback. (This won't throw: the callback was wrapped with
|
|
// bindEnvironment.)
|
|
this._callback(this._methodResult[0], this._methodResult[1]);
|
|
|
|
// Forget about this method.
|
|
delete this._connection._methodInvokers[this.methodId];
|
|
|
|
// Let the connection know that this method is finished, so it can try to
|
|
// move on to the next block of methods.
|
|
this._connection._outstandingMethodFinished();
|
|
}
|
|
}
|
|
// Call with the result of the method from the server. Only may be called
|
|
// once; once it is called, you should not call sendMessage again.
|
|
// If the user provided an onResultReceived callback, call it immediately.
|
|
// Then invoke the main callback if data is also visible.
|
|
receiveResult(err, result) {
|
|
if (this.gotResult())
|
|
throw new Error('Methods should only receive results once');
|
|
this._methodResult = [err, result];
|
|
this._onResultReceived(err, result);
|
|
this._maybeInvokeCallback();
|
|
}
|
|
// Call this when all data written by the method is visible. This means that
|
|
// the method has returns its "data is done" message *AND* all server
|
|
// documents that are buffered at that time have been written to the local
|
|
// cache. Invokes the main callback if the result has been received.
|
|
dataVisible() {
|
|
this._dataVisible = true;
|
|
this._maybeInvokeCallback();
|
|
}
|
|
// True if receiveResult has been called.
|
|
gotResult() {
|
|
return !!this._methodResult;
|
|
}
|
|
}
|