Failed attempt at using method calls to manage awaited method
This commit is contained in:
@@ -1,28 +1,90 @@
|
||||
import ActiveActions from '/imports/api/creature/actions/ActiveActions';
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
import { ValidatedMethod } from 'meteor/mdg:validated-method';
|
||||
import { RateLimiterMixin } from 'ddp-rate-limiter-mixin';
|
||||
import { set } from 'lodash';
|
||||
|
||||
// Reminder: throwStubExceptions: true is the default, and only
|
||||
// possible when run() is not async
|
||||
// For async run() stub exceptions never stop the client from sending
|
||||
// the call to the server
|
||||
|
||||
// Dict of invocationId: {steps: {earlyAnswers, resolve, reject}}
|
||||
// either resolve functions waiting for the user's input or early answers that were provided
|
||||
// before the resolves could be set up
|
||||
let userInputRequests = {};
|
||||
let provideUserInput;
|
||||
|
||||
if (Meteor.isClient) {
|
||||
provideUserInput = function (invocationId, step, answers, callback) {
|
||||
Meteor.call('answerUserInputRequest', { invocationId, step, answers }, callback);
|
||||
// Do the same work on the client without using a stub
|
||||
answerInputRequestWork({ invocationId, step, answers });
|
||||
}
|
||||
}
|
||||
|
||||
export { userInputRequests, provideUserInput };
|
||||
|
||||
export default async function getUserInput(questions, actionContext) {
|
||||
const activeActionId = actionContext.activeActionId;
|
||||
// Set the questions on the active action
|
||||
ActiveActions.update(activeActionId, {
|
||||
$set: { questions },
|
||||
$unset: { answers: 1 },
|
||||
});
|
||||
// Wait for answers
|
||||
// get the invocation details from the action context
|
||||
const invocationId = actionContext.invocationId;
|
||||
const step = actionContext.userInputStep;
|
||||
actionContext.userInputStep += 1; // increment userInput step every time
|
||||
|
||||
// If the answers are already waiting, just return them
|
||||
if (userInputRequests[invocationId]?.[step]?.earlyAnswers) {
|
||||
return userInputRequests[invocationId][step].earlyAnswers;
|
||||
}
|
||||
// On the client, store the questions to be answered
|
||||
if (Meteor.isClient) {
|
||||
set(userInputRequests, `${invocationId}[${step}]`, { questions });
|
||||
}
|
||||
// Create a place for the answers to go when they are provided
|
||||
return new Promise((resolve, reject) => {
|
||||
const observerHandle = ActiveActions.find({
|
||||
_id: activeActionId
|
||||
}).observeChanges({
|
||||
changed(id, fields) {
|
||||
// Only watch for answers
|
||||
if (!fields.answers) return;
|
||||
// Stop watching
|
||||
observerHandle.stop();
|
||||
// Give answers
|
||||
resolve(fields.answers);
|
||||
},
|
||||
removed() {
|
||||
reject('Active action was deleted')
|
||||
},
|
||||
});
|
||||
set(userInputRequests, `${invocationId}[${step}]`, { resolve, reject });
|
||||
});
|
||||
}
|
||||
|
||||
function answerInputRequestWork({ invocationId, step, answers }) {
|
||||
console.log('running answerUserInputRequest');
|
||||
const invocation = userInputRequests[invocationId];
|
||||
if (!invocation) {
|
||||
// Call order on the server is guaranteed, so the invocation must have been created
|
||||
// Before we can update it
|
||||
throw new Meteor.Error('Not found', 'The method this answer is updating does not exist');
|
||||
}
|
||||
if (invocation[step]?.resolve) {
|
||||
// If there is a resolve waiting for this response, provide it
|
||||
invocation[step].resolve(answers);
|
||||
} else {
|
||||
// Otherwise just store the response as early answers
|
||||
invocation[step] = {
|
||||
earlyAnswers: answers
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (Meteor.isServer) {
|
||||
// This function is not defined on the client so that it has no stub function
|
||||
// This allows it to be called while still simulating an awaited async method
|
||||
// See https://guide.meteor.com/2.8-migration.html#the-limitations
|
||||
new ValidatedMethod({
|
||||
name: 'answerUserInputRequest',
|
||||
validate: new SimpleSchema({
|
||||
invocationId: SimpleSchema.RegEx.Id,
|
||||
step: SimpleSchema.Integer,
|
||||
answers: {
|
||||
type: Object,
|
||||
blackbox: true,
|
||||
},
|
||||
}).validator(),
|
||||
applyOptions: {
|
||||
throwStubExceptions: false,
|
||||
},
|
||||
mixins: [RateLimiterMixin],
|
||||
rateLimit: {
|
||||
numRequests: 20,
|
||||
timeInterval: 5000,
|
||||
},
|
||||
run: answerInputRequestWork,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user