Skip to content
This repository was archived by the owner on Aug 11, 2021. It is now read-only.

Commit 0c5f17c

Browse files
authored
feat: support passing AbortSignals to the configured repo (#89)
This is so the user can signal that they are no longer interested in the results of the operation and system components can stop trying to fulfil it.
1 parent 3eec2cc commit 0c5f17c

File tree

3 files changed

+112
-14
lines changed

3 files changed

+112
-14
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@
3030
},
3131
"homepage": "https://github.com/ipfs/js-ipfs-block-service#readme",
3232
"devDependencies": {
33+
"abort-controller": "^3.0.0",
3334
"aegir": "^21.8.1",
3435
"chai": "^4.2.0",
36+
"chai-as-promised": "^7.1.1",
3537
"cids": "^0.8.0",
3638
"dirty-chai": "^2.0.1",
3739
"fs-extra": "^9.0.0",

src/index.js

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,59 +54,67 @@ class BlockService {
5454
* Put a block to the underlying datastore.
5555
*
5656
* @param {Block} block
57+
* @param {Object} [options] - Options is an object with the following properties
58+
* @param {AbortSignal} [options.signal] - A signal that can be used to abort any long-lived operations that are started as a result of this operation
5759
* @returns {Promise}
5860
*/
59-
put (block) {
61+
put (block, options) {
6062
if (this.hasExchange()) {
61-
return this._bitswap.put(block)
63+
return this._bitswap.put(block, options)
6264
} else {
63-
return this._repo.blocks.put(block)
65+
return this._repo.blocks.put(block, options)
6466
}
6567
}
6668

6769
/**
6870
* Put a multiple blocks to the underlying datastore.
6971
*
7072
* @param {Array<Block>} blocks
73+
* @param {Object} [options] - Options is an object with the following properties
74+
* @param {AbortSignal} [options.signal] - A signal that can be used to abort any long-lived operations that are started as a result of this operation
7175
* @returns {Promise}
7276
*/
73-
putMany (blocks) {
77+
putMany (blocks, options) {
7478
if (this.hasExchange()) {
75-
return this._bitswap.putMany(blocks)
79+
return this._bitswap.putMany(blocks, options)
7680
} else {
77-
return this._repo.blocks.putMany(blocks)
81+
return this._repo.blocks.putMany(blocks, options)
7882
}
7983
}
8084

8185
/**
8286
* Get a block by cid.
8387
*
8488
* @param {CID} cid
89+
* @param {Object} [options] - Options is an object with the following properties
90+
* @param {AbortSignal} [options.signal] - A signal that can be used to abort any long-lived operations that are started as a result of this operation
8591
* @returns {Promise<Block>}
8692
*/
87-
get (cid) {
93+
get (cid, options) {
8894
if (this.hasExchange()) {
89-
return this._bitswap.get(cid)
95+
return this._bitswap.get(cid, options)
9096
} else {
91-
return this._repo.blocks.get(cid)
97+
return this._repo.blocks.get(cid, options)
9298
}
9399
}
94100

95101
/**
96102
* Get multiple blocks back from an array of cids.
97103
*
98104
* @param {Array<CID>} cids
105+
* @param {Object} [options] - Options is an object with the following properties
106+
* @param {AbortSignal} [options.signal] - A signal that can be used to abort any long-lived operations that are started as a result of this operation
99107
* @returns {Iterator<Block>}
100108
*/
101-
getMany (cids) {
109+
getMany (cids, options) {
102110
if (!Array.isArray(cids)) {
103111
throw new Error('first arg must be an array of cids')
104112
}
105113

106114
if (this.hasExchange()) {
107-
return this._bitswap.getMany(cids)
115+
return this._bitswap.getMany(cids, options)
108116
} else {
109-
const getRepoBlocks = map((cid) => this._repo.blocks.get(cid))
117+
const getRepoBlocks = map((cid) => this._repo.blocks.get(cid, options))
110118
return getRepoBlocks(cids)
111119
}
112120
}
@@ -115,10 +123,12 @@ class BlockService {
115123
* Delete a block from the blockstore.
116124
*
117125
* @param {CID} cid
126+
* @param {Object} [options] - Options is an object with the following properties
127+
* @param {AbortSignal} [options.signal] - A signal that can be used to abort any long-lived operations that are started as a result of this operation
118128
* @returns {Promise}
119129
*/
120-
delete (cid) {
121-
return this._repo.blocks.delete(cid)
130+
delete (cid, options) {
131+
return this._repo.blocks.delete(cid, options)
122132
}
123133
}
124134

test/aborting-requests.spec.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/* eslint-env mocha */
2+
'use strict'
3+
4+
const chai = require('chai')
5+
chai.use(require('dirty-chai'))
6+
chai.use(require('chai-as-promised'))
7+
const expect = chai.expect
8+
9+
const { collect } = require('streaming-iterables')
10+
const AbortController = require('abort-controller')
11+
12+
const BlockService = require('../src')
13+
14+
describe('aborting requests', () => {
15+
let abortedErr
16+
let r
17+
18+
beforeEach(() => {
19+
abortedErr = new Error('Aborted!')
20+
const abortOnSignal = (...args) => {
21+
const { signal } = args[args.length - 1]
22+
23+
return new Promise((resolve, reject) => {
24+
signal.addEventListener('abort', () => {
25+
reject(abortedErr)
26+
})
27+
})
28+
}
29+
30+
const repo = {
31+
blocks: {
32+
put: abortOnSignal,
33+
putMany: abortOnSignal,
34+
get: abortOnSignal,
35+
delete: abortOnSignal,
36+
deleteMany: abortOnSignal
37+
}
38+
}
39+
r = new BlockService(repo)
40+
})
41+
42+
it('put - supports abort signals', async () => {
43+
const controller = new AbortController()
44+
setTimeout(() => controller.abort(), 1)
45+
46+
await expect(r.put('block', {
47+
signal: controller.signal
48+
})).to.eventually.rejectedWith(abortedErr)
49+
})
50+
51+
it('putMany - supports abort signals', async () => {
52+
const controller = new AbortController()
53+
setTimeout(() => controller.abort(), 1)
54+
55+
await expect(r.putMany(['block'], {
56+
signal: controller.signal
57+
})).to.eventually.rejectedWith(abortedErr)
58+
})
59+
60+
it('get - supports abort signals', async () => {
61+
const controller = new AbortController()
62+
setTimeout(() => controller.abort(), 1)
63+
64+
await expect(r.get('cid', {
65+
signal: controller.signal
66+
})).to.eventually.rejectedWith(abortedErr)
67+
})
68+
69+
it('getMany - supports abort signals', async () => {
70+
const controller = new AbortController()
71+
setTimeout(() => controller.abort(), 1)
72+
73+
await expect(collect(r.getMany(['cid'], {
74+
signal: controller.signal
75+
}))).to.eventually.rejectedWith(abortedErr)
76+
})
77+
78+
it('remove - supports abort signals', async () => {
79+
const controller = new AbortController()
80+
setTimeout(() => controller.abort(), 1)
81+
82+
await expect(r.delete('cid', {
83+
signal: controller.signal
84+
})).to.eventually.rejectedWith(abortedErr)
85+
})
86+
})

0 commit comments

Comments
 (0)