| 203 | // receiveText reads the whole incoming stream into memory and shows |
| 204 | // it as copyable text under the connection's list item. |
| 205 | async function receiveText(conn, li, progress) { |
| 206 | try { |
| 207 | const chunks = []; |
| 208 | let n = 0; |
| 209 | for (let chunk; (chunk = await conn.read()) !== null; ) { |
| 210 | chunks.push(chunk); |
| 211 | n += chunk.length; |
| 212 | progress.textContent = `${n} bytes`; |
| 213 | } |
| 214 | conn.close(); |
| 215 | const all = new Uint8Array(n); |
| 216 | let off = 0; |
| 217 | for (const c of chunks) { |
| 218 | all.set(c, off); |
| 219 | off += c.length; |
| 220 | } |
| 221 | const text = new TextDecoder().decode(all); |
| 222 | const box = document.createElement("code"); |
| 223 | box.className = "recv-text"; |
| 224 | box.textContent = text; |
| 225 | const copyBtn = document.createElement("button"); |
| 226 | copyBtn.textContent = "Copy"; |
| 227 | copyBtn.onclick = () => navigator.clipboard.writeText(text); |
| 228 | li.append(box, copyBtn); |
| 229 | progress.textContent = `done, ${n} bytes`; |
| 230 | } catch (err) { |
| 231 | conn.close(); |
| 232 | progress.textContent = "failed: " + err.message; |
| 233 | window.tcTest.errors.push(String(err)); |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | // hashSink is the test-mode receiver: instead of the file picker |
| 238 | // (which needs a user gesture that headless Chrome can't provide), it |