Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

Commit

Permalink
feat!: match go-ipfs@0.10 dag put options and semantics
Browse files Browse the repository at this point in the history
Fixes: #3914
Ref: https://github.com/ipfs/go-ipfs/blob/master/CHANGELOG.md#v0100-2021-09-30

--format and --input-enc have been replaced with --input-codec and
--store-codec and mean something a little different. You now supply
raw input and instruct the server which --input-codec that data is
in which it will decode, then re-encode with --store-codec before
storing it and providing you with the CID.

We accept plain JavaScript objects to encode with --store-codec via
the API here, defaulting to dag-cbor, and send that to the server as
encoded bytes using that codec, to be stored using that codec.

If you supply an --input-codec then we assume you're supplying raw,
encoded bytes using that codec and we pass that directly on to the
server to handle.
  • Loading branch information
rvagg committed Oct 11, 2021
1 parent 09c7bf7 commit f95fbfc
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 23 deletions.
2 changes: 1 addition & 1 deletion packages/ipfs-http-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
"devDependencies": {
"aegir": "^35.1.1",
"delay": "^5.0.0",
"go-ipfs": "0.9.1",
"go-ipfs": "0.10.0",
"ipfsd-ctl": "^10.0.4",
"it-all": "^1.0.4",
"it-first": "^1.0.4",
Expand Down
25 changes: 21 additions & 4 deletions packages/ipfs-http-client/src/dag/put.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,31 @@ export const createPut = (codecs, options) => {
*/
const put = async (dagNode, options = {}) => {
const settings = {
format: 'dag-cbor',
storeCodec: 'dag-cbor',
hashAlg: 'sha2-256',
inputEnc: 'raw',
...options
}

const codec = await codecs.getCodec(settings.format)
const serialized = codec.encode(dagNode)
let serialized

if (settings.inputCodec) {
// if you supply an inputCodec, we assume you're passing in a raw, encoded
// block using that codec, so we'll just pass that on to the server and let
// it deal with the decode/encode/store cycle
if (!(dagNode instanceof Uint8Array)) {
throw new Error('Can only inputCodec on raw bytes that can be decoded')
}
serialized = dagNode
} else {
// if you don't supply an inputCodec, we assume you've passed in a JavaScript
// object you want to have encoded using storeCodec, so we'll prepare it for
// you if we have the codec
const storeCodec = await codecs.getCodec(settings.storeCodec)
serialized = storeCodec.encode(dagNode)
// now we have a serialized form, the server should be told to receive it
// in that format
settings.inputCodec = settings.storeCodec
}

// allow aborting requests on body errors
const controller = new AbortController()
Expand Down
46 changes: 28 additions & 18 deletions packages/ipfs-http-client/test/dag.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import { expect } from 'aegir/utils/chai.js'
import { CID } from 'multiformats/cid'
import * as dagPB from '@ipld/dag-pb'
import * as dagCBOR from '@ipld/dag-cbor'
import * as raw from 'multiformats/codecs/raw'
Expand All @@ -14,33 +15,33 @@ const f = factory()

let ipfs

describe('.dag', function () {
describe.only('.dag', function () {
this.timeout(20 * 1000)
before(async function () {
ipfs = (await f.spawn()).api
})

after(() => f.clean())

it('should be able to put and get a DAG node with format dag-pb', async () => {
it('should be able to put and get a DAG node with dag-pb codec', async () => {
const data = uint8ArrayFromString('some data')
const node = {
Data: data,
Links: []
}

const cid = await ipfs.dag.put(node, { format: 'dag-pb', hashAlg: 'sha2-256', cidVersion: 0 })
const cid = await ipfs.dag.put(node, { storeCodec: 'dag-pb', hashAlg: 'sha2-256' })
expect(cid.code).to.equal(dagPB.code)
expect(cid.toString(base58btc)).to.equal('Qmd7xRhW5f29QuBFtqu3oSD27iVy35NRB91XFjmKFhtgMr')
expect(cid.toV0().toString()).to.equal('Qmd7xRhW5f29QuBFtqu3oSD27iVy35NRB91XFjmKFhtgMr')

const result = await ipfs.dag.get(cid)

expect(result.value.Data).to.deep.equal(data)
})

it('should be able to put and get a DAG node with format dag-cbor', async () => {
it('should be able to put and get a DAG node with dag-cbor codec', async () => {
const cbor = { foo: 'dag-cbor-bar' }
const cid = await ipfs.dag.put(cbor, { format: 'dag-cbor', hashAlg: 'sha2-256' })
const cid = await ipfs.dag.put(cbor, { storeCodec: 'dag-cbor', hashAlg: 'sha2-256' })

expect(cid.code).to.equal(dagCBOR.code)
expect(cid.toString(base32)).to.equal('bafyreic6f672hnponukaacmk2mmt7vs324zkagvu4hcww6yba6kby25zce')
Expand All @@ -50,9 +51,9 @@ describe('.dag', function () {
expect(result.value).to.deep.equal(cbor)
})

it('should be able to put and get a DAG node with format raw', async () => {
it('should be able to put and get a DAG node with raw codec', async () => {
const node = uint8ArrayFromString('some data')
const cid = await ipfs.dag.put(node, { format: 'raw', hashAlg: 'sha2-256' })
const cid = await ipfs.dag.put(node, { storeCodec: 'raw', hashAlg: 'sha2-256' })

expect(cid.code).to.equal(raw.code)
expect(cid.toString(base32)).to.equal('bafkreiata6mq425fzikf5m26temcvg7mizjrxrkn35swuybmpah2ajan5y')
Expand All @@ -70,19 +71,28 @@ describe('.dag', function () {
await expect(ipfs.dag.get(cid)).to.eventually.be.rejectedWith(/No codec found/)
})

it('should error when putting node with esoteric format', () => {
it('should error when putting node with esoteric codec', () => {
const node = uint8ArrayFromString('some data')

return expect(ipfs.dag.put(node, { format: 'git-raw', hashAlg: 'sha2-256' })).to.eventually.be.rejectedWith(/No codec found/)
return expect(ipfs.dag.put(node, { storeCodec: 'git-raw', hashAlg: 'sha2-256' })).to.eventually.be.rejectedWith(/No codec found/)
})

it('should attempt to load an unsupported format', async () => {
let askedToLoadFormat
it('should pass through raw bytes with inputCodec', async () => {
const node = uint8ArrayFromString('blob 9\0some data')
// we don't support git-raw in the HTTP client, but inputCodec and a Uint8Array should make
// the raw data pass through to go-ipfs, which does talk git-raw
const cid = await ipfs.dag.put(node, { inputCodec: 'git-raw', storeCodec: 'git-raw', hashAlg: 'sha1' })
expect(cid.code).to.equal(0x78)
expect(cid.toString(base32)).to.equal('baf4bcfd4azdl7vj4d4hnix75qfld6mabo4l4uwa')
})

it('should attempt to load an unsupported codec', async () => {
let askedToLoadCodec
const ipfs2 = httpClient({
url: `http://${ipfs.apiHost}:${ipfs.apiPort}`,
ipld: {
loadCodec: (format) => {
askedToLoadFormat = format === 'git-raw'
loadCodec: (codec) => {
askedToLoadCodec = codec === 'boop'
return {
encode: (buf) => buf
}
Expand All @@ -93,9 +103,9 @@ describe('.dag', function () {
const node = uint8ArrayFromString('some data')

// error is from go-ipfs, this means the client serialized it ok
await expect(ipfs2.dag.put(node, { format: 'git-raw', hashAlg: 'sha2-256' })).to.eventually.be.rejectedWith(/no parser for format "git-raw"/)
await expect(ipfs2.dag.put(node, { storeCodec: 'boop', hashAlg: 'sha2-256' })).to.eventually.be.rejectedWith(/unknown multicodec: "boop"/)

expect(askedToLoadFormat).to.be.true()
expect(askedToLoadCodec).to.be.true()
})

it('should allow formats to be specified without overwriting others', async () => {
Expand All @@ -115,7 +125,7 @@ describe('.dag', function () {
hello: 'world'
}
const cid1 = await ipfs2.dag.put(dagCborNode, {
format: 'dag-cbor',
storeCodec: 'dag-cbor',
hashAlg: 'sha2-256'
})

Expand All @@ -124,7 +134,7 @@ describe('.dag', function () {
Links: []
}
const cid2 = await ipfs2.dag.put(dagPbNode, {
format: 'dag-pb',
storeCodec: 'dag-pb',
hashAlg: 'sha2-256'
})

Expand Down

0 comments on commit f95fbfc

Please sign in to comment.