| 567 | } |
| 568 | |
| 569 | private ensureResolvingExport(exportId: ExportId) { |
| 570 | let exp = this.exports[exportId]; |
| 571 | if (!exp) { |
| 572 | throw new Error(`no such export ID: ${exportId}`); |
| 573 | } |
| 574 | if (!exp.pull) { |
| 575 | let resolve = async () => { |
| 576 | let hook = exp.hook; |
| 577 | for (;;) { |
| 578 | let payload = await hook.pull(); |
| 579 | if (payload.value instanceof RpcStub) { |
| 580 | let {hook: inner, pathIfPromise} = unwrapStubAndPath(payload.value); |
| 581 | if (pathIfPromise && pathIfPromise.length == 0) { |
| 582 | if (this.getImport(hook) === undefined) { |
| 583 | // Optimization: The resolution is just another promise, and it is not a promise |
| 584 | // pointing back to the peer. So if we send a resolve message, it's just going to |
| 585 | // resolve to another new promise export, which is just going to have to wait for |
| 586 | // another resolve message later. This intermediate resolve message gives the peer |
| 587 | // no useful information, so let's skip it and just wait for the chained |
| 588 | // resolution. |
| 589 | hook = inner; |
| 590 | continue; |
| 591 | } |
| 592 | } |
| 593 | } |
| 594 | |
| 595 | return payload; |
| 596 | } |
| 597 | }; |
| 598 | |
| 599 | let autoRelease = exp.autoRelease; |
| 600 | |
| 601 | ++this.pullCount; |
| 602 | exp.pull = resolve().then( |
| 603 | payload => { |
| 604 | // We don't transfer ownership of stubs in the payload since the payload |
| 605 | // belongs to the hook which sticks around to handle pipelined requests. |
| 606 | let value = Devaluator.devaluate(payload.value, undefined, this, payload, this.encodingLevel); |
| 607 | this.send(["resolve", exportId, value]); |
| 608 | if (autoRelease) this.releaseExport(exportId, 1); |
| 609 | }, |
| 610 | error => { |
| 611 | this.send(["reject", exportId, Devaluator.devaluate(error, undefined, this, undefined, this.encodingLevel)]); |
| 612 | if (autoRelease) this.releaseExport(exportId, 1); |
| 613 | } |
| 614 | ).catch( |
| 615 | error => { |
| 616 | // If serialization failed, report the serialization error, which should |
| 617 | // itself always be serializable. |
| 618 | try { |
| 619 | this.send(["reject", exportId, Devaluator.devaluate(error, undefined, this, undefined, this.encodingLevel)]); |
| 620 | if (autoRelease) this.releaseExport(exportId, 1); |
| 621 | } catch (error2) { |
| 622 | // TODO: Shouldn't happen, now what? |
| 623 | this.abort(error2); |
| 624 | } |
| 625 | } |
| 626 | ).finally(() => { |