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

feat: enable custom formats for server/client DAG (put|get) operations #3309

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions packages/ipfs-cli/src/daemon.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ class Daemon {
}
}

async start () {
/**
* Starts the IPFS HTTP server
* @param {object} [opts] - specify advanced configuration
* @param {object} [opts.ipld.formats] - IPLD custom formats
* @return {Promise<HttpApi>}
*/
async start (opts = {}) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are the opts passed into daemon start? If I run jsipfs daemon it's not going to pass anything into the start function, so there's no way to set these.

It would be helpful to have a test showing how passing the formats is intended to work, it's not clear to me right now, other than directly using the http server and client.

The updates themselves look good but the usage isn't clear.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't do this through the CLI as it stands, instead you'd create a wrapper that starts a daemon with the required IPLD options.

I've added an example of how to do this in #3347

log('starting')

const repo = typeof this._options.repo === 'string' || this._options.repo == null
Expand All @@ -40,7 +46,7 @@ class Daemon {

// start HTTP servers (if API or Gateway is enabled in options)
const httpApi = new HttpApi(ipfs, ipfsOpts)
this._httpApi = await httpApi.start()
this._httpApi = await httpApi.start(opts)

const httpGateway = new HttpGateway(ipfs, ipfsOpts)
this._httpGateway = await httpGateway.start()
Expand Down
27 changes: 18 additions & 9 deletions packages/ipfs-http-client/src/dag/get.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,32 @@ const dagPB = require('ipld-dag-pb')
const dagCBOR = require('ipld-dag-cbor')
const raw = require('ipld-raw')
const configure = require('../lib/configure')

const resolvers = {
'dag-cbor': dagCBOR.resolver,
'dag-pb': dagPB.resolver,
raw: raw.resolver
}
const multicodec = require('multicodec')

module.exports = configure((api, options) => {
const getBlock = require('../block/get')(options)
const dagResolve = require('./resolve')(options)

const formats = {
[multicodec.DAG_PB]: dagPB,
[multicodec.DAG_CBOR]: dagCBOR,
[multicodec.RAW]: raw
}

const ipldOptions = (options && options.ipld) || {}
const configuredFormats = (ipldOptions && ipldOptions.formats) || []
configuredFormats.forEach(format => {
formats[format.codec] = format
})

return async (cid, options = {}) => {
const resolved = await dagResolve(cid, options)
const block = await getBlock(resolved.cid, options)
const dagResolver = resolvers[resolved.cid.codec]

if (!dagResolver) {
const codec = multicodec[resolved.cid.codec.toUpperCase().replace(/-/g, '_')]
const format = formats[codec]

if (!format) {
throw Object.assign(
new Error(`Missing IPLD format "${resolved.cid.codec}"`),
{ missingMulticodec: resolved.cid.codec }
Expand All @@ -31,6 +40,6 @@ module.exports = configure((api, options) => {
resolved.remainderPath = '/'
}

return dagResolver.resolve(block.data, resolved.remainderPath)
return format.resolver.resolve(block.data, resolved.remainderPath)
}
})
14 changes: 11 additions & 3 deletions packages/ipfs-http-server/src/api/resources/dag.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,19 @@ exports.put = {
} else {
const codec = multicodec[format.toUpperCase().replace(/-/g, '_')]

if (!IpldFormats[codec]) {
throw new Error(`Missing IPLD format "${codec}"`)
let ipldFormat = IpldFormats[codec]
if (!ipldFormat) {
// look at the passed config
const ipldOpts = (request.server.app.opts && request.server.app.opts.ipld) || {}
if (ipldOpts.formats) {
ipldFormat = ipldOpts.formats.find((f) => f.codec === codec)
}
}

node = await IpldFormats[codec].util.deserialize(data)
if (!ipldFormat) {
throw new Error(`Missing IPLD format "${codec}"`)
}
node = await ipldFormat.util.deserialize(data)
}

return {
Expand Down
17 changes: 12 additions & 5 deletions packages/ipfs-http-server/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ function hapiInfoToMultiaddr (info) {
return toMultiaddr(uri)
}

async function serverCreator (serverAddrs, createServer, ipfs, cors) {
async function serverCreator (serverAddrs, createServer, ipfs, cors, opts) {
serverAddrs = serverAddrs || []
// just in case the address is just string
serverAddrs = Array.isArray(serverAddrs) ? serverAddrs : [serverAddrs]

const servers = []
for (const address of serverAddrs) {
const addrParts = address.split('/')
const server = await createServer(addrParts[2], addrParts[4], ipfs, cors)
const server = await createServer(addrParts[2], addrParts[4], ipfs, cors, opts)
await server.start()
server.info.ma = hapiInfoToMultiaddr(server.info)
servers.push(server)
Expand All @@ -49,7 +49,13 @@ class HttpApi {
this._log.error = debug(LOG_ERROR)
}

async start () {
/**
* Starts the IPFS HTTP server
* @param {object} [opts] - specify advanced configuration
* @param {object} [opts.ipld.formats] - IPLD custom formats
* @return {Promise<HttpApi>}
*/
async start (opts = {}) {
this._log('starting')

const ipfs = this._ipfs
Expand All @@ -63,13 +69,13 @@ class HttpApi {
this._apiServers = await serverCreator(apiAddrs, this._createApiServer, ipfs, {
origin: config.API.HTTPHeaders['Access-Control-Allow-Origin'] || [],
credentials: Boolean(config.API.HTTPHeaders['Access-Control-Allow-Credentials'])
})
}, opts)

this._log('started')
return this
}

async _createApiServer (host, port, ipfs, cors) {
async _createApiServer (host, port, ipfs, cors, opts) {
cors = {
...cors,
additionalHeaders: ['X-Stream-Output', 'X-Chunked-Output', 'X-Content-Length'],
Expand All @@ -95,6 +101,7 @@ class HttpApi {
compression: false
})
server.app.ipfs = ipfs
server.app.opts = opts

await server.register({
plugin: Pino,
Expand Down