diff --git a/lib/captp.js b/lib/captp.js index 7d1e9e71714..161b03f93f1 100644 --- a/lib/captp.js +++ b/lib/captp.js @@ -21,8 +21,9 @@ export function makeCapTP(ourId, send, bootstrapObj = undefined) { let lastQuestionID = 0; const valToSlot = new WeakMap(); - const slotToVal = new Map(); // exports, answers + const slotToVal = new Map(); // exports const questions = new Map(); // chosen by us + const answers = new Map(); // chosen by our peer const imports = new Map(); // chosen by our peer function serializeSlot(val, slots, slotMap) { @@ -70,23 +71,33 @@ export function makeCapTP(ourId, send, bootstrapObj = undefined) { }); } - function makeRemote(slot) { + function makeQuestion() { + lastQuestionID += 1; + const questionID = lastQuestionID; + const pr = makeRemote(questionID); + questions.set(questionID, pr); + return [questionID, pr]; + } + + function makeRemote(target) { const handler = { + GET(_o, prop) { + const [questionID, pr] = makeQuestion(); + send({ + type: 'CTP_CALL', + questionID, + target, + method: serialize(harden([prop])), + }); + return harden(pr.p); + }, POST(_o, prop, args) { // Support: o~.[prop](...args) remote method invocation - // FIXME: Implement a HandledPromise here to support pipelining. - const pr = {}; - pr.p = new Promise((resolve, reject) => { - pr.res = resolve; - pr.rej = reject; - }); - lastQuestionID += 1; - const questionID = lastQuestionID; - questions.set(questionID, pr); + const [questionID, pr] = makeQuestion(); send({ type: 'CTP_CALL', questionID, - target: slot, + target, method: serialize(harden([prop, args])), }); return harden(pr.p); @@ -131,6 +142,7 @@ export function makeCapTP(ourId, send, bootstrapObj = undefined) { const bootstrap = typeof bootstrapObj === 'function' ? bootstrapObj() : bootstrapObj; // console.log('sending bootstrap', bootstrap); + answers.set(questionID, bootstrap); send({ type: 'CTP_RETURN', answerID: questionID, @@ -140,15 +152,23 @@ export function makeCapTP(ourId, send, bootstrapObj = undefined) { CTP_CALL(obj) { const { questionID, target } = obj; const [prop, args] = unserialize(obj.method); - const val = unserialize({ - body: JSON.stringify({ - [QCLASS]: 'slot', - index: 0, - }), - slots: [target], - }); - HandledPromise.applyMethod(val, prop, args) - .then(res => + let val; + if (answers.has(target)) { + val = answers.get(target); + } else { + val = unserialize({ + body: JSON.stringify({ + [QCLASS]: 'slot', + index: 0, + }), + slots: [target], + }); + } + const hp = args + ? HandledPromise.applyMethod(val, prop, args) + : HandledPromise.get(val, prop); + answers.set(questionID, hp); + hp.then(res => send({ type: 'CTP_RETURN', answerID: questionID, @@ -198,14 +218,7 @@ export function makeCapTP(ourId, send, bootstrapObj = undefined) { // Get a reference to the other side's bootstrap object. const getBootstrap = () => { - const pr = {}; - pr.p = new Promise((resolve, reject) => { - pr.res = resolve; - pr.rej = reject; - }); - lastQuestionID += 1; - const questionID = lastQuestionID; - questions.set(questionID, pr); + const [questionID, pr] = makeQuestion(); send({ type: 'CTP_BOOTSTRAP', questionID,