diff --git a/browser-video-streaming/index.html b/browser-video-streaming/index.html index 2b33f7de..29b2cac7 100644 --- a/browser-video-streaming/index.html +++ b/browser-video-streaming/index.html @@ -2,7 +2,7 @@ - + diff --git a/browser-video-streaming/streaming.js b/browser-video-streaming/streaming.js index d42631a7..27814196 100644 --- a/browser-video-streaming/streaming.js +++ b/browser-video-streaming/streaming.js @@ -2,7 +2,6 @@ /* global Hls Ipfs HlsjsIpfsLoader */ /* eslint-env browser */ - document.addEventListener('DOMContentLoaded', async () => { const testHash = 'QmdpAidwAsBGptFB3b6A9Pyi5coEbgjHrL3K2Qrsutmj9K' const repoPath = 'ipfs-' + Math.random() diff --git a/circuit-relaying/package.json b/circuit-relaying/package.json index 7261bfa8..e317e9d1 100644 --- a/circuit-relaying/package.json +++ b/circuit-relaying/package.json @@ -15,7 +15,7 @@ "license": "MIT", "dependencies": { "ipfs": "file:../../", - "ipfs-pubsub-room": "^1.4.0" + "ipfs-pubsub-room": "^2.0.1" }, "devDependencies": { "aegir": "^20.0.0", diff --git a/circuit-relaying/src/helpers.js b/circuit-relaying/src/helpers.js index 26a277ef..61330bf2 100644 --- a/circuit-relaying/src/helpers.js +++ b/circuit-relaying/src/helpers.js @@ -15,7 +15,7 @@ const mkRoomName = (name) => { module.exports = (ipfs, peersSet) => { const createRoom = (name) => { - const room = Room(ipfs, mkRoomName(name)) + const room = new Room(ipfs, mkRoomName(name)) room.on('peer joined', (peer) => { console.log('peer ' + peer + ' joined') diff --git a/circuit-relaying/test.js b/circuit-relaying/test.js index 499abc69..955f6580 100644 --- a/circuit-relaying/test.js +++ b/circuit-relaying/test.js @@ -66,7 +66,9 @@ async function runTest () { try { const id = await ipfsd.api.id() - const address = id.addresses.filter(addr => addr.includes('/ws/ipfs/Qm')).pop() + const address = id.addresses + .map(ma => ma.toString()) + .find(addr => addr.includes('/ws/p2p/Qm')) if (!address) { throw new Error(`Could not find web socket address in ${id.addresses}`) diff --git a/custom-ipfs-repo/index.js b/custom-ipfs-repo/index.js index 8458bf72..058bbd2e 100644 --- a/custom-ipfs-repo/index.js +++ b/custom-ipfs-repo/index.js @@ -3,6 +3,7 @@ const IPFS = require('ipfs') const Repo = require('ipfs-repo') const fsLock = require('ipfs-repo/src/lock') +const all = require('it-all') // Create our custom options const customRepositoryOptions = { @@ -79,19 +80,19 @@ async function main () { console.log('Version:', version) // Once we have the version, let's add a file to IPFS - const filesAdded = await node.add({ + for await (const file of node.add({ path: 'test-data.txt', content: Buffer.from('We are using a customized repo!') - }) - - // Log out the added files metadata and cat the file from IPFS - console.log('\nAdded file:', filesAdded[0].path, filesAdded[0].hash) + })) { + // Log out the added files metadata and cat the file from IPFS + console.log('\nAdded file:', file.path, file.cid) - const data = await node.cat(filesAdded[0].hash) + const data = Buffer.concat(await all(node.cat(file.cid))) - // Print out the files contents to console - console.log('\nFetched file content:') - process.stdout.write(data) + // Print out the files contents to console + console.log('\nFetched file content:') + process.stdout.write(data) + } // After everything is done, shut the node down console.log('\n\nStopping the node') diff --git a/custom-ipfs-repo/package.json b/custom-ipfs-repo/package.json index f7289d7b..7e52503e 100644 --- a/custom-ipfs-repo/package.json +++ b/custom-ipfs-repo/package.json @@ -11,7 +11,8 @@ "dependencies": { "datastore-fs": "^0.9.1", "ipfs": "file:../../", - "ipfs-repo": "^0.28.0" + "ipfs-repo": "^0.28.0", + "it-all": "^1.0.1" }, "devDependencies": { "execa": "^3.2.0" diff --git a/custom-libp2p/index.js b/custom-libp2p/index.js index fa1a097b..1b5d2387 100644 --- a/custom-libp2p/index.js +++ b/custom-libp2p/index.js @@ -1,14 +1,13 @@ 'use strict' const Libp2p = require('libp2p') -const IPFS = require('ipfs') +const IPFS = require('../../') const TCP = require('libp2p-tcp') const MulticastDNS = require('libp2p-mdns') -const WebSocketStar = require('libp2p-websocket-star') const Bootstrap = require('libp2p-bootstrap') const SPDY = require('libp2p-spdy') const KadDHT = require('libp2p-kad-dht') -const MPLEX = require('pull-mplex') +const MPLEX = require('libp2p-mplex') const SECIO = require('libp2p-secio') /** @@ -32,11 +31,6 @@ const libp2pBundle = (opts) => { const peerBook = opts.peerBook const bootstrapList = opts.config.Bootstrap - // Create our WebSocketStar transport and give it our PeerId, straight from the ipfs node - const wsstar = new WebSocketStar({ - id: peerInfo.id - }) - // Build and return our libp2p node return new Libp2p({ peerInfo, @@ -49,8 +43,7 @@ const libp2pBundle = (opts) => { }, modules: { transport: [ - TCP, - wsstar + TCP ], streamMuxer: [ MPLEX, @@ -61,8 +54,7 @@ const libp2pBundle = (opts) => { ], peerDiscovery: [ MulticastDNS, - Bootstrap, - wsstar.discovery + Bootstrap ], dht: KadDHT }, diff --git a/custom-libp2p/package.json b/custom-libp2p/package.json index 197b8d5c..62c1a398 100644 --- a/custom-libp2p/package.json +++ b/custom-libp2p/package.json @@ -9,18 +9,16 @@ }, "license": "MIT", "dependencies": { - "ipfs": "file:../../", - "libp2p": "^0.26.2", - "libp2p-bootstrap": "~0.9.7", - "libp2p-kad-dht": "~0.16.0", - "libp2p-mdns": "~0.12.2", - "libp2p-secio": "~0.11.1", - "libp2p-spdy": "~0.13.3", - "libp2p-tcp": "~0.13.0", - "libp2p-websocket-star": "~0.10.2", - "pull-mplex": "~0.1.0" + "libp2p": "^0.27.0-rc.0", + "libp2p-bootstrap": "^0.10.3", + "libp2p-kad-dht": "^0.18.3", + "libp2p-mdns": "^0.13.1", + "libp2p-mplex": "^0.9.3", + "libp2p-secio": "^0.12.2", + "libp2p-spdy": "^0.13.3", + "libp2p-tcp": "^0.14.3" }, "devDependencies": { - "execa": "^3.2.0" + "execa": "^4.0.0" } } diff --git a/custom-libp2p/test.js b/custom-libp2p/test.js index b4666f67..3240104e 100644 --- a/custom-libp2p/test.js +++ b/custom-libp2p/test.js @@ -5,13 +5,11 @@ const execa = require('execa') const Libp2p = require('libp2p') const TCP = require('libp2p-tcp') const SPDY = require('libp2p-spdy') -const MPLEX = require('pull-mplex') +const MPLEX = require('libp2p-mplex') const SECIO = require('libp2p-secio') const PeerInfo = require('peer-info') const PeerId = require('peer-id') const multiaddr = require('multiaddr') -const promisify = require('promisify-es6') -const PeerBook = require('peer-book') async function test () { let output = '' @@ -31,12 +29,11 @@ async function test () { console.info('Dialling', address) - const peerInfo = new PeerInfo(await promisify(PeerId.create)()) + const peerInfo = new PeerInfo(await PeerId.create()) peerInfo.multiaddrs.add(multiaddr('/ip4/127.0.0.1/tcp/0')) const libp2p = new Libp2p({ peerInfo, - peerBook: new PeerBook(), modules: { transport: [ TCP diff --git a/exchange-files-in-browser/README.md b/exchange-files-in-browser/README.md index adb86df2..30a4f47e 100644 --- a/exchange-files-in-browser/README.md +++ b/exchange-files-in-browser/README.md @@ -2,7 +2,7 @@ This tutorial will help you exchange files between browser nodes and go-ipfs or js-ipfs nodes! -**Note:** As `js-ipfs@0.33.x` currently doesn't support DHT peer discovery, the peer from which you are fetching data should be within the reach (local or in public IP) of the browser node. +**Note:** As `js-ipfs@0.41.x` currently doesn't support DHT peer discovery, the peer from which you are fetching data should be within the reach (local or in public IP) of the browser node. That being said, we will explain how to circumvent these caveats and once they are fixed, we'll update the tutorial as well. @@ -35,9 +35,10 @@ Here's what we are going to be doing: 1. Install a `go-ipfs` or `js-ipfs` node in your machine 2. Make your daemons listen on WebSockets -3. Start the app -4. Dial to a node using WebSockets (your desktop ones) -5. Transfer files between all of your nodes! +3. Start a `libp2p-webrtc-star` signaling server +4. Start the app +5. Dial to a node using WebSockets (your desktop ones) +6. Transfer files between all of your nodes! Just follow the instructions below and it will be up and running in no time! @@ -121,7 +122,25 @@ Daemon is ready Check the `/ws` in line 5, that means it is listening. Cool. -### 3. Start the app +### 3. Start a `libp2p-webrtc-star` signaling server + +This server allows the two browser nodes to talk to each other by doing the initial handshake and network introductions. + +First install the `libp2p-webrtc-star` module globally: + +```sh +> npm install -g libp2p-webrtc-star +``` + +This will give you the `webrtc-star` command. Use this to start a signaling server: + +```sh +> webrtc-star +``` + +By default it will listen to all incoming connections on port 13579. Override this with the `--host` and/or `--port` options. + +### 4. Start the app Make sure you're in `js-ipfs/examples/exchange-files-in-browser`. @@ -147,7 +166,7 @@ Hit CTRL-C to stop the server Now go to http://127.0.0.1:12345 in a modern browser and you're on! -### 4. Dial to a node using WebSockets (your desktop ones) +### 5. Dial to a node using WebSockets (your desktop ones) Make sure you have a daemon running. If you don't, run: @@ -179,7 +198,7 @@ Check that you got connected: [js-libp2p-crypto#105]: https://github.com/libp2p/js-libp2p-crypto/issues/105 -### 5. Transfer files between all of your nodes! +### 6. Transfer files between all of your nodes! Now you can add files through the CLI with: diff --git a/exchange-files-in-browser/public/app.js b/exchange-files-in-browser/public/app.js index f23ca84f..29a3850a 100644 --- a/exchange-files-in-browser/public/app.js +++ b/exchange-files-in-browser/public/app.js @@ -1,7 +1,7 @@ /* global location */ 'use strict' -const IPFS = require('ipfs') +const IPFS = require('../../../dist') const { Buffer } = IPFS // Node @@ -31,7 +31,7 @@ const $workspaceInput = document.querySelector('#workspace-input') const $workspaceBtn = document.querySelector('#workspace-btn') let FILES = [] -let workspace = location.hash +let workspace = (location.hash || 'default-workspace').replace(/^#/, '') let fileSize = 0 @@ -44,20 +44,30 @@ let info async function start () { if (!node) { - const options = { + node = await IPFS.create({ repo: 'ipfs-' + Math.random(), config: { Addresses: { - Swarm: ['/dns4/ws-star.discovery.libp2p.io/tcp/443/wss/p2p-websocket-star'] + Swarm: [ + // This is a public webrtc-star server + // '/dns4/star-signal.cloud.ipfs.team/wss/p2p-webrtc-star' + '/ip4/127.0.0.1/tcp/13579/wss/p2p-webrtc-star' + ] } } - } - - node = await IPFS.create(options) + }) try { info = await node.id() - updateView('ready', node) + + const addressesHtml = info.addresses.map((address) => { + return `
  • ${address}
  • ` + }).join('') + $nodeId.innerText = info.id + $nodeAddresses.innerHTML = addressesHtml + $allDisabledButtons.forEach(b => { b.disabled = false }) + $allDisabledInputs.forEach(b => { b.disabled = false }) + $allDisabledElements.forEach(el => { el.classList.remove('disabled') }) } catch (err) { return onError(err) } @@ -114,7 +124,7 @@ async function start () { =========================================================================== */ const messageHandler = (message) => { - const myNode = info.id + const myNode = info.id.toString() const hash = message.data.toString() const messageSender = message.from @@ -127,7 +137,7 @@ const messageHandler = (message) => { const subscribeToWorkpsace = async () => { await node.pubsub.subscribe(workspace, messageHandler) - const msg = `Subscribed to workspace ${workspace}` + const msg = `Subscribed to workspace '${workspace}'` $logs.innerHTML = msg } @@ -138,7 +148,7 @@ const workspaceUpdated = async () => { FILES = [] $fileHistory.innerHTML = '' - workspace = location.hash + workspace = location.hash.replace(/^#/, '') await subscribeToWorkpsace() } @@ -207,15 +217,13 @@ async function getFile () { FILES.push(hash) - const files = await node.get(hash) - - return Promise.all(files.map(async (file) => { + for await (const file of node.get(hash)) { if (file.content) { await appendFile(file.name, hash, file.size, file.content) onSuccess(`The ${file.name} file was added.`) $emptyRow.style.display = 'none' } - })) + } } /* Drag & Drop @@ -272,10 +280,11 @@ async function refreshPeerList () { .map((peer) => { if (peer.addr) { const addr = peer.addr.toString() - if (addr.indexOf('ipfs') >= 0) { + + if (addr.indexOf('/p2p/') >= 0) { return addr } else { - return addr + peer.peer.id.toB58String() + return addr + peer.peer } } }) @@ -322,31 +331,6 @@ function onError (err) { window.onerror = onError -/* =========================================================================== - App states - =========================================================================== */ - -const states = { - ready: () => { - const addressesHtml = info.addresses.map((address) => { - return `
  • ${address}
  • ` - }).join('') - $nodeId.innerText = info.id - $nodeAddresses.innerHTML = addressesHtml - $allDisabledButtons.forEach(b => { b.disabled = false }) - $allDisabledInputs.forEach(b => { b.disabled = false }) - $allDisabledElements.forEach(el => { el.classList.remove('disabled') }) - } -} - -function updateView (state, ipfs) { - if (states[state] !== undefined) { - states[state]() - } else { - throw new Error('Could not find state "' + state + '"') - } -} - /* =========================================================================== Boot the app =========================================================================== */ diff --git a/exchange-files-in-browser/test.js b/exchange-files-in-browser/test.js index 2e9f1643..723a00ba 100644 --- a/exchange-files-in-browser/test.js +++ b/exchange-files-in-browser/test.js @@ -19,12 +19,12 @@ const df = createFactory({ js: { ipfsBin: path.resolve(`${__dirname}/../../src/cli/bin.js`) } -} -) +}) const { startServer } = require('../utils') const pkg = require('./package.json') +const webRTCStarSigServer = require('libp2p-webrtc-star/src/sig-server') async function testUI (env) { const proc = execa('nightwatch', [path.join(__dirname, 'test.js')], { @@ -44,7 +44,13 @@ async function testUI (env) { } async function runTest () { - const ipfsd = await df.spawn({ + const sigServer = await webRTCStarSigServer.start({ + host: '127.0.0.1', + port: 13579 + }) + + const relay = await df.spawn({ + type: 'js', ipfsOptions: { config: { Addresses: { @@ -56,15 +62,20 @@ async function runTest () { } }) - const [{ - hash: cid - }] = await ipfsd.api.add('A file with some content') + let cid + + for await (const imported of relay.api.add('A file with some content')) { + cid = imported.cid + } + const server1 = await startServer(__dirname) const server2 = await startServer(__dirname) try { - const id = await ipfsd.api.id() - const address = id.addresses.filter(addr => addr.includes('/ws/ipfs/Qm')).pop() + const id = await relay.api.id() + const address = id.addresses + .map(ma => ma.toString()) + .find(addr => addr.includes('/ws/p2p')) if (!address) { throw new Error(`Could not find web socket address in ${id.addresses}`) @@ -74,10 +85,12 @@ async function runTest () { const peerA = path.join(os.tmpdir(), `test-${Date.now()}-a.txt`) const peerB = path.join(os.tmpdir(), `test-${Date.now()}-b.txt`) + console.info('Relay address', address) + await Promise.all([ testUI({ IPFS_EXAMPLE_TEST_URL: server1.url, - IPFS_RELAY_ADDRESS: id.addresses[0], + IPFS_RELAY_ADDRESS: address, IPFS_CID: cid, IPFS_WORKSPACE_NAME: workspaceName, IPFS_ADD_FILE: true, @@ -86,7 +99,7 @@ async function runTest () { }), testUI({ IPFS_EXAMPLE_TEST_URL: server1.url, - IPFS_RELAY_ADDRESS: id.addresses[0], + IPFS_RELAY_ADDRESS: address, IPFS_CID: cid, IPFS_WORKSPACE_NAME: workspaceName, IPFS_LOCAL_PEER_ID_FILE: peerB, @@ -94,9 +107,10 @@ async function runTest () { }) ]) } finally { - await ipfsd.stop() - await server1.stop() await server2.stop() + await server1.stop() + await relay.stop() + await sigServer.stop() } } @@ -108,7 +122,7 @@ module.exports[pkg.name] = function (browser) { browser .url(process.env.IPFS_EXAMPLE_TEST_URL) - .waitForElementVisible('.node-addresses li pre') + .waitForElementVisible('#connected-peers tr td') .pause(1000) console.info('dialling relay', process.env.IPFS_RELAY_ADDRESS) diff --git a/ipfs-101/1.js b/ipfs-101/1.js index 3b832eb9..314f2dab 100644 --- a/ipfs-101/1.js +++ b/ipfs-101/1.js @@ -1,6 +1,7 @@ 'use strict' const IPFS = require('ipfs') +const all = require('it-all') async function main () { const node = await IPFS.create() @@ -8,16 +9,16 @@ async function main () { console.log('Version:', version.version) - const filesAdded = await node.add({ + for await (const file of await node.add({ path: 'hello.txt', content: Buffer.from('Hello World 101') - }) + })) { + console.log('Added file:', file.path, file.cid.toString()) - console.log('Added file:', filesAdded[0].path, filesAdded[0].hash) + const data = Buffer.concat(await all(node.cat(file.cid))) - const fileBuffer = await node.cat(filesAdded[0].hash) - - console.log('Added file contents:', fileBuffer.toString()) + console.log('Added file contents:', data.toString()) + } } main() diff --git a/ipfs-101/package.json b/ipfs-101/package.json index 7b775399..663bd15e 100644 --- a/ipfs-101/package.json +++ b/ipfs-101/package.json @@ -9,6 +9,7 @@ "author": "David Dias ", "license": "MIT", "dependencies": { - "ipfs": "file:../../" + "ipfs": "file:../../", + "it-all": "^1.0.1" } } diff --git a/package.json b/package.json index ed9608c3..42f4f055 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,6 @@ "license": "MIT", "dependencies": { "chromedriver": "^79.0.0", - "delay": "^4.1.0", "execa": "^3.2.0", "fs-extra": "^8.1.0", "http-server": "~0.11.1", diff --git a/running-multiple-nodes/README.md b/running-multiple-nodes/README.md index 9683075b..dcf836eb 100644 --- a/running-multiple-nodes/README.md +++ b/running-multiple-nodes/README.md @@ -42,7 +42,7 @@ Firstly, you'll want to pass the [`repo`](https://github.com/ipfs/js-ipfs#option ```js // The repo path by default is `os.homedir() + '/.jsipfs'`. -new IPFS({ repo: os.homedir() + '/.jsipfs2' }) +await IPFS.create({ repo: os.homedir() + '/.jsipfs2' }) ``` Secondly, you'll need them to bind to different ports because otherwise bad things happen. @@ -50,7 +50,7 @@ Secondly, you'll need them to bind to different ports because otherwise bad thin To do this, simply pass the different ports to the [`config`](https://github.com/ipfs/js-ipfs#optionsconfig) constructor option. All together: ```js -new IPFS({ +await IPFS.create({ repo: os.homedir() + '/.jsipfs2', config: { Addresses: { diff --git a/running-multiple-nodes/test.js b/running-multiple-nodes/test.js index 76eefe9c..c62577d6 100644 --- a/running-multiple-nodes/test.js +++ b/running-multiple-nodes/test.js @@ -7,7 +7,6 @@ const os = require('os') const path = require('path') const hat = require('hat') const { - ephemeralPort, waitForOutput } = require('../utils') @@ -29,9 +28,9 @@ async function startCliNode () { const ipfs = path.resolve(__dirname, '../../src/cli/bin.js') await execa(ipfs, ['init'], opts) - await execa(ipfs, ['config', 'Addresses.Swarm', '--json', JSON.stringify([`/ip4/0.0.0.0/tcp/${ephemeralPort()}`, `/ip4/127.0.0.1/tcp/${ephemeralPort()}/ws`])], opts) - await execa(ipfs, ['config', 'Addresses.API', `/ip4/127.0.0.1/tcp/${ephemeralPort()}`], opts) - await execa(ipfs, ['config', 'Addresses.Gateway', `/ip4/127.0.0.1/tcp/${ephemeralPort()}`], opts) + await execa(ipfs, ['config', 'Addresses.Swarm', '--json', JSON.stringify([`/ip4/0.0.0.0/tcp/0`, `/ip4/127.0.0.1/tcp/0/ws`])], opts) + await execa(ipfs, ['config', 'Addresses.API', `/ip4/127.0.0.1/tcp/0`], opts) + await execa(ipfs, ['config', 'Addresses.Gateway', `/ip4/127.0.0.1/tcp/0`], opts) return waitForOutput('Daemon is ready', ipfs, ['daemon'], opts) } @@ -45,25 +44,21 @@ async function testProgramatically () { async function startProgramaticNode () { const repoDir = path.join(os.tmpdir(), `repo-${hat()}`) - const node = new IPFS({ + const node = await IPFS.create({ repo: repoDir, config: { Addresses: { Swarm: [ - `/ip4/0.0.0.0/tcp/${ephemeralPort()}`, - `/ip4/127.0.0.1/tcp/${ephemeralPort()}/ws` + `/ip4/0.0.0.0/tcp/0`, + `/ip4/127.0.0.1/tcp/0/ws` ], - API: `/ip4/127.0.0.1/tcp/${ephemeralPort()}`, - Gateway: `/ip4/127.0.0.1/tcp/${ephemeralPort()}` + API: `/ip4/127.0.0.1/tcp/0`, + Gateway: `/ip4/127.0.0.1/tcp/0` }, Bootstrap: [] } }) - console.info('Initialising programmatic node') - await node.init() - console.info('Starting programmatic node') - await node.start() console.info('Stopping programmatic node') await node.stop() } diff --git a/test-all.js b/test-all.js index 50ae41a9..a4eb7fa8 100644 --- a/test-all.js +++ b/test-all.js @@ -24,6 +24,8 @@ async function testAll () { continue } + console.info('Testing example', dir) + await waitForOutput('npm info ok', 'npm', ['test', '--verbose', '--', dir], { cwd: __dirname }) diff --git a/traverse-ipld-graphs/test.js b/traverse-ipld-graphs/test.js index 45ae20ae..e40d2534 100644 --- a/traverse-ipld-graphs/test.js +++ b/traverse-ipld-graphs/test.js @@ -19,7 +19,7 @@ async function runTest () { await waitForOutput('capoeira', path.resolve(__dirname, 'get-path-accross-formats.js')) console.info('Testing tree.js') - await waitForOutput("'hobbies/0/Links'", path.resolve(__dirname, 'tree.js')) + await waitForOutput("hobbies/0/Links", path.resolve(__dirname, 'tree.js')) console.info('Testing eth.js') await waitForOutput('302516', path.resolve(__dirname, 'eth.js')) diff --git a/traverse-ipld-graphs/tree.js b/traverse-ipld-graphs/tree.js index 7f52206d..1acba5e5 100644 --- a/traverse-ipld-graphs/tree.js +++ b/traverse-ipld-graphs/tree.js @@ -29,9 +29,11 @@ async function main () { hashAlg: 'sha3-512' }) - const paths = await ipfs.dag.tree(cborNodeCid, { recursive: true }) + for await (const path of ipfs.dag.tree(cborNodeCid, { recursive: true })) { + console.log(path) + } - console.log(paths) + await ipfs.stop() } main() diff --git a/utils.js b/utils.js index 98cc5d2b..7c1b0ee4 100644 --- a/utils.js +++ b/utils.js @@ -125,28 +125,48 @@ async function waitForOutput (expectedOutput, command, args = [], opts = {}) { let output = '' const time = 120000 - const timeout = setTimeout(() => { - throw new Error(`Did not see "${expectedOutput}" in output from "${[command].concat(args).join(' ')}" after ${time / 1000}s`) - }, time) + let foundExpectedOutput = false + let cancelTimeout + const timeoutPromise = new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new Error(`Did not see "${expectedOutput}" in output from "${[command].concat(args).join(' ')}" after ${time / 1000}s`)) + + setTimeout(() => { + proc.kill() + }, 100) + }, time) + + cancelTimeout = () => { + clearTimeout(timeout) + resolve() + } + }) proc.all.on('data', (data) => { process.stdout.write(data) - output += data.toString('utf8') if (output.includes(expectedOutput)) { - clearTimeout(timeout) + foundExpectedOutput = true proc.kill() + cancelTimeout() } }) try { - await proc + await Promise.race([ + proc, + timeoutPromise + ]) } catch (err) { if (!err.killed) { throw err } } + + if (!foundExpectedOutput) { + throw new Error(`Did not see "${expectedOutput}" in output from "${[command].concat(args).join(' ')}"`) + } } module.exports = {