aboutsummaryrefslogtreecommitdiffhomepage
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/dev/php-rpc.md9
-rw-r--r--docs/dev/plugin-class-classification.md20
2 files changed, 22 insertions, 7 deletions
diff --git a/docs/dev/php-rpc.md b/docs/dev/php-rpc.md
index 6aa1d737..d2ce4ae5 100644
--- a/docs/dev/php-rpc.md
+++ b/docs/dev/php-rpc.md
@@ -167,9 +167,12 @@ Notable internal helpers:
`selfDir`/`installedIsLocalDir` restore) into the worker; skipped only when the class is not
even autoloadable there, i.e. no Composer PHP runtime and therefore no observer code.
- `__shirabe_resolved_promise` — wraps a value in `\React\Promise\resolve()`, so a Rust method
- whose PHP signature declares `PromiseInterface` (the `DownloadManager` surface) can answer
- with the object type the caller expects. The Rust future has already run to completion by
- then; deferred resolution across the boundary does not exist yet.
+ whose PHP signature declares `PromiseInterface` (the `DownloadManager` and `HttpDownloader`
+ surfaces) can answer with the object type the caller expects. The Rust future has already run
+ to completion by then; deferred resolution across the boundary does not exist yet.
+- `__shirabe_rejected_promise` — the failure half of the same: `\React\Promise\reject()` over
+ the exception a `Throw` frame's four fields describe, so a failed request reaches the caller
+ as a rejection it handles rather than as a throw out of the call that started it.
- `__shirabe_settle_promise` — the inverse: drains a promise a plugin returned to Rust. React
settles synchronously, so an already-settled promise yields its value here (a rejection is
re-thrown as the Throw reply); one that is still pending is an explicit error.
diff --git a/docs/dev/plugin-class-classification.md b/docs/dev/plugin-class-classification.md
index a383f7c6..5cb8fd6e 100644
--- a/docs/dev/plugin-class-classification.md
+++ b/docs/dev/plugin-class-classification.md
@@ -415,10 +415,22 @@ its options, its TLS defaults and the authentication it collects into the
run's IO are state the two worlds have to share, and a plugin-`new`ed one
allocates a Rust-side entity rather than a second downloader the graph knows
nothing about. `get()` and `copy()` answer with a
-`Composer\Util\Http\Response` the child holds as a value (see below); the
-async surface — `add()`, `addCopy()`, `wait()`, `enableAsync()`,
-`countActiveJobs()` — is still an explicit error, because driving it needs a
-promise representation that crosses the boundary unresolved.
+`Composer\Util\Http\Response` the child holds as a value (see below), and the
+async surface answers too, with the future driven to completion before the
+promise is handed over. Requests a plugin starts together therefore run one
+after another rather than overlapping; overlapping them needs a promise
+representation that crosses the boundary unresolved. Everything else the async
+surface does is preserved: `add()` still refuses a downloader outside a `Loop`,
+a failed request still arrives as a rejection rather than as a throw, and
+`wait()` and `countActiveJobs()` still answer for a downloader that holds no
+outstanding job — which, once every request settles before its call returns, it
+never does.
+
+This is where `ProcessExecutor` and `HttpDownloader` part company. The
+executor's async surface stays an explicit error because `executeAsync()`
+resolves its promise with a `Symfony\Component\Process\Process`, whose state
+is the `proc_open()` resource of whichever process called `start()`; a request
+resolves its promise with a `Response`, which is data.
`Loop` remains guarded, so `Composer::getLoop()` is still an explicit error
and neither the graph's own executor nor its downloader is reachable through