@@ -129,17 +129,51 @@ for status checks and raw-fetch error handling. |
129 | 129 | `containerAttach()` attaches to the container's existing process; it does not |
130 | 130 | create a new command like `containerExec()` followed by `execStart()`. |
131 | 131 |
|
132 | | -The current attach wrapper recognizes HTTP 200 with the exact |
133 | | -`application/vnd.docker.raw-stream` content type and creates a multiplexed |
134 | | -`DockerRawStream`. Unlike the log and exec wrappers, it does not select a |
135 | | -TTY-aware decoder or handle all upgraded-response variants. Do not assume |
136 | | -that terminal output or HTTP 101 will work through this wrapper. |
137 | | - |
138 | | -`containerAttachWebsocket()` uses a separate `AttachWebsocketStream` with |
139 | | -`read()`, `write()` and `close()`, not `onStdout()`/`wait()`. Its response |
140 | | -handling is also narrow, and the existing WebSocket integration test is |
141 | | -skipped. Treat it as a feature requiring validation with your daemon and |
142 | | -transport, not a tested interactive-terminal recipe. |
| 132 | +`containerAttach()` returns a `DockerRawStream` for plain and upgraded |
| 133 | +responses. Docker labels TTY output and framed non-TTY output on plain |
| 134 | +responses with the same content type, so the client inspects the container's |
| 135 | +TTY setting to choose the decoder. TTY output arrives through `onStdout()`. |
| 136 | +Since `3.3.0`, attaching to a TTY container no longer loses its output. |
| 137 | + |
| 138 | +`containerAttachWebsocket()` returns an `AttachWebsocketStream` with `read()`, |
| 139 | +`write()` and `close()`, not `onStdout()`/`wait()`. It is useful when you need |
| 140 | +to write to the container's stdin over the attach connection: |
| 141 | + |
| 142 | +```php |
| 143 | +<?php |
| 144 | + |
| 145 | +require __DIR__ . '/vendor/autoload.php'; |
| 146 | + |
| 147 | +use Docker\Docker; |
| 148 | + |
| 149 | +$docker = Docker::create(); |
| 150 | +$attach = $docker->containerAttachWebsocket('my-container', [ |
| 151 | + 'stream' => true, |
| 152 | + 'stdin' => true, |
| 153 | + 'stdout' => true, |
| 154 | + 'stderr' => true, |
| 155 | +]); |
| 156 | + |
| 157 | +$attach->write("echo hello\n"); |
| 158 | +// Print output until a second passes without any. |
| 159 | +while (is_string($output = $attach->read(1))) { |
| 160 | + echo $output; |
| 161 | +} |
| 162 | +$attach->close(); |
| 163 | +``` |
| 164 | + |
| 165 | +`read()` waits up to the given seconds and microseconds for one frame. It |
| 166 | +returns the frame's bytes, `false` when nothing arrived in time, or `null` once |
| 167 | +Docker has closed the connection. A frame is a chunk of output, not a line. |
| 168 | +Docker mixes stdout and stderr in the same frames, with no marker for which |
| 169 | +stream a chunk came from. The stream answers pings and closes itself when |
| 170 | +Docker sends a close frame. `write()` sends one binary frame. |
| 171 | + |
| 172 | +WebSocket attach needs `3.3.0` or later; earlier clients returned `null` |
| 173 | +instead of a stream. Docker Desktop's socket proxy upgrades the connection but |
| 174 | +does not forward attach output; a Linux daemon or a remote engine works. For |
| 175 | +driving commands, [interactive exec](/guides/interactive-exec) gives separate |
| 176 | +stdout and stderr, exit codes and deadlines. |
143 | 177 |
|
144 | 178 | `DockerRawStream::onStdin()` is an output-channel callback; it is not a method |
145 | 179 | for writing commands into a container. Prefer the [exec recipe](/guides/exec) |
|