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

Commit

Permalink
chore: update pr after review
Browse files Browse the repository at this point in the history
  • Loading branch information
achingbrain committed Mar 15, 2019
1 parent 6111234 commit a499fc9
Show file tree
Hide file tree
Showing 4 changed files with 497 additions and 173 deletions.
163 changes: 102 additions & 61 deletions src/http/api/resources/dag.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
const promisify = require('promisify-es6')
const CID = require('cids')
const multipart = require('ipfs-multipart')
const mh = require('multihashes')
const Joi = require('joi')
const multibase = require('multibase')
const Boom = require('boom')
const debug = require('debug')
const {
cidToString
} = require('../../../utils/cid')
const log = debug('ipfs:http-api:dag')
log.error = debug('ipfs:http-api:dag:error')

// common pre request handler that parses the args and returns `key` which is assigned to `request.pre.args`
exports.parseKey = (request, h) => {
exports.parseKey = (request) => {
if (!request.query.arg) {
throw Boom.badRequest("Argument 'key' is required")
}
Expand All @@ -30,7 +34,7 @@ exports.parseKey = (request, h) => {
path = `${parts.join('/')}`
}

if (path.endsWith('/')) {
if (path && path.endsWith('/')) {
path = path.substring(0, path.length - 1)
}

Expand All @@ -45,10 +49,34 @@ exports.parseKey = (request, h) => {
}
}

const encodeBufferKeys = (obj, encoding) => {
if (!obj) {
return obj
}

if (Buffer.isBuffer(obj)) {
return obj.toString(encoding)
}

Object.keys(obj).forEach(key => {
if (Buffer.isBuffer(obj)) {
obj[key] = obj[key].toString(encoding)

return
}

if (typeof obj[key] === 'object') {
obj[key] = encodeBufferKeys(obj[key], encoding)
}
})

return obj
}

exports.get = {
validate: {
query: Joi.object().keys({
'data-encoding': Joi.string().valid(['text', 'base64']).default('base64'),
'data-encoding': Joi.string().valid(['text', 'base64', 'hex']).default('text'),
'cid-base': Joi.string().valid(multibase.names)
}).unknown()
},
Expand All @@ -64,22 +92,24 @@ exports.get = {
} = request.pre.args
const { ipfs } = request.server.app

let dataEncoding = request.query['data-encoding']

if (dataEncoding === 'text') {
dataEncoding = 'utf8'
}

let result

try {
result = await ipfs.dag.get(key, path)
} catch (err) {
throw Boom.boomify(err, { message: 'Failed to get dag node' })
throw Boom.badRequest(err)
}

if (key.codec === 'dag-pb' && result.value) {
if (typeof result.value.toJSON === 'function') {
result.value = result.value.toJSON()
}

if (Buffer.isBuffer(result.value.data)) {
result.value.data = result.value.data.toString(request.query.dataencoding)
}
try {
result.value = encodeBufferKeys(result.value, dataEncoding)
} catch (err) {
throw Boom.boomify(err)
}

return h.response(result.value)
Expand All @@ -89,11 +119,10 @@ exports.get = {
exports.put = {
validate: {
query: Joi.object().keys({
// TODO validate format, & hash
format: Joi.string(),
'input-enc': Joi.string().valid('dag-cbor', 'dag-pb', 'raw'),
format: Joi.string().default('cbor'),
'input-enc': Joi.string().default('json'),
pin: Joi.boolean(),
hash: Joi.string(),
hash: Joi.string().valid(mh.names).default('sha2-256'),
'cid-base': Joi.string().valid(multibase.names).default('base58btc')
}).unknown()
},
Expand All @@ -102,78 +131,89 @@ exports.put = {
// which is assigned to `request.pre.args`
async parseArgs (request, h) {
if (!request.payload) {
throw Boom.badRequest("File argument 'data' is required")
throw Boom.badRequest("File argument 'object data' is required")
}

const enc = request.query.inputenc
const enc = request.query['input-enc']

if (!request.headers['content-type']) {
throw Boom.badRequest("File argument 'object data' is required")
}

const fileStream = await new Promise((resolve, reject) => {
multipart.reqParser(request.payload)
.on('file', (name, stream) => resolve(stream))
.on('end', () => reject(Boom.badRequest("File argument 'data' is required")))
.on('end', () => reject(Boom.badRequest("File argument 'object data' is required")))
})

let data = await new Promise((resolve, reject) => {
fileStream
.on('data', data => resolve(data))
.on('end', () => reject(Boom.badRequest("File argument 'data' is required")))
.on('end', () => reject(Boom.badRequest("File argument 'object data' is required")))
})

if (enc === 'json') {
let format = request.query.format

if (format === 'cbor') {
format = 'dag-cbor'
}

let node

if (format === 'raw') {
node = data
} else if (enc === 'json') {
try {
data = JSON.parse(data.toString())
node = JSON.parse(data.toString())
} catch (err) {
throw Boom.badRequest('Failed to parse the JSON: ' + err)
}
}
} else {
const { ipfs } = request.server.app
const codec = ipfs._ipld.resolvers[format]

try {
return {
buffer: data
if (!codec) {
throw Boom.badRequest(`Missing IPLD format "${request.query.format}"`)
}
} catch (err) {
throw Boom.badRequest('Failed to create DAG node: ' + err)

const deserialize = promisify(codec.util.deserialize)

node = await deserialize(data)
}

return {
node,
format,
hashAlg: request.query.hash
}
},

// main route handler which is called after the above `parseArgs`, but only if the args were valid
async handler (request, h) {
const { ipfs } = request.server.app
const { buffer } = request.pre.args
const { node, format, hashAlg } = request.pre.args

let cid

return new Promise((resolve, reject) => {
const format = ipfs._ipld.resolvers[request.query.format]

if (!format) {
return reject(Boom.badRequest(`Missing IPLD format "${request.query.format}"`))
}

format.util.deserialize(buffer, async (err, node) => {
if (err) {
return reject(err)
}

try {
cid = await ipfs.dag.put(node, {
format: request.query.format,
hashAlg: request.query.hash
})
} catch (err) {
throw Boom.boomify(err, { message: 'Failed to put node' })
}
try {
cid = await ipfs.dag.put(node, {
format: format,
hashAlg: hashAlg
})
} catch (err) {
throw Boom.boomify(err, { message: 'Failed to put node' })
}

if (request.query.pin) {
await ipfs.pin.add(cid)
}
if (request.query.pin) {
await ipfs.pin.add(cid)
}

resolve(h.response({
Cid: {
'/': cid.toBaseEncodedString(request.query.cidbase)
}
}))
})
return h.response({
Cid: {
'/': cidToString(cid, {
base: request.query['cid-base']
})
}
})
}
}
Expand All @@ -191,7 +231,6 @@ exports.resolve = {
// main route handler which is called after the above `parseArgs`, but only if the args were valid
async handler (request, h) {
let { key, path } = request.pre.args
const cidBase = request.query['cid-base']
const { ipfs } = request.server.app

// to be consistent with go we need to return the CID to the last node we've traversed
Expand Down Expand Up @@ -226,9 +265,11 @@ exports.resolve = {

return h.response({
Cid: {
'/': lastCid.toBaseEncodedString(cidBase)
'/': cidToString(lastCid, {
base: request.query['cid-base']
})
},
RemPath: lastRemainderPath
RemPath: lastRemainderPath || ''
})
} catch (err) {
throw Boom.boomify(err)
Expand Down
111 changes: 0 additions & 111 deletions test/http-api/dag.js

This file was deleted.

1 change: 0 additions & 1 deletion test/http-api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
require('./block')
require('./bootstrap')
require('./config')
require('./dag')
require('./dns')
require('./id')
require('./routes')
Expand Down
Loading

0 comments on commit a499fc9

Please sign in to comment.