From 01e56ec00a225da7d25328446cbdb978dec52d13 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 29 Oct 2016 21:18:33 +0100 Subject: [PATCH] feat: migrate http-api to use new async DAGNode interface --- src/http-api/resources/object.js | 183 ++++++++++++++++++++------ test/http-api/ipfs-api/test-object.js | 70 ++++++---- 2 files changed, 191 insertions(+), 62 deletions(-) diff --git a/src/http-api/resources/object.js b/src/http-api/resources/object.js index c8399ba910..0b0904e666 100644 --- a/src/http-api/resources/object.js +++ b/src/http-api/resources/object.js @@ -40,7 +40,15 @@ exports.new = (request, reply) => { }).code(500) } - return reply(node.toJSON()) + node.toJSON((err, nodeJSON) => { + if (err) { + return reply({ + Message: 'Failed to get object: ' + err, + Code: 0 + }).code(500) + } + return reply(nodeJSON) + }) }) } @@ -62,37 +70,73 @@ exports.get = { }).code(500) } - const res = node.toJSON() - res.Data = res.Data ? res.Data.toString() : '' - return reply(res) + node.toJSON((err, nodeJSON) => { + if (err) { + return reply({ + Message: 'Failed to get object: ' + err, + Code: 0 + }).code(500) + } + + nodeJSON.Data = nodeJSON.Data ? nodeJSON.Data.toString() : '' + return reply(nodeJSON) + }) }) } } exports.put = { - // pre request handler that parses the args and returns `node` which is assigned to `request.pre.args` + // pre request handler that parses the args and returns `node` + // which is assigned to `request.pre.args` parseArgs: (request, reply) => { if (!request.payload) { return reply("File argument 'data' is required").code(400).takeover() } const enc = request.query.inputenc - const parser = multipart.reqParser(request.payload) - var file - parser.on('file', (fileName, fileStream) => { - fileStream.on('data', (data) => { + let file + let finished = true + + parser.on('file', (name, stream) => { + finished = false + // TODO fix: stream is not emitting the 'end' event + stream.on('data', (data) => { if (enc === 'protobuf') { - const n = new DAGNode().unMarshal(data) - file = new Buffer(JSON.stringify(n.toJSON())) + dagPB.util.deserialize(data, (err, node) => { + if (err) { + return reply({ + Message: 'Failed to receive protobuf encoded: ' + err, + Code: 0 + }).code(500).takeover() + } + + node.toJSON((err, nodeJSON) => { + if (err) { + return reply({ + Message: 'Failed to receive protobuf encoded: ' + err, + Code: 0 + }).code(500).takeover() + } + file = new Buffer(JSON.stringify(nodeJSON)) + finished = true + }) + }) } else { file = data + + finished = true } }) }) - parser.on('end', () => { + parser.on('end', finish) + + function finish () { + if (!finished) { + return setTimeout(finish, 10) + } if (!file) { return reply("File argument 'data' is required").code(400).takeover() } @@ -107,15 +151,15 @@ exports.put = { Code: 0 }).code(500).takeover() } - }) + } }, // main route handler which is called after the above `parseArgs`, but only if the args were valid handler: (request, reply) => { - const node = request.pre.args.node - const dagNode = new DAGNode(new Buffer(node.Data), node.Links) + const nodeJSON = request.pre.args.node + const node = new DAGNode(new Buffer(nodeJSON.Data), nodeJSON.Links) - request.server.app.ipfs.object.put(dagNode, (err, obj) => { + request.server.app.ipfs.object.put(node, (err, obj) => { if (err) { log.error(err) return reply({ @@ -123,7 +167,17 @@ exports.put = { Code: 0 }).code(500) } - return reply(dagNode.toJSON()) + + node.toJSON((err, nodeJSON) => { + if (err) { + return reply({ + Message: 'Failed to put object: ' + err, + Code: 0 + }).code(500) + } + + return reply(nodeJSON) + }) }) } } @@ -189,10 +243,17 @@ exports.links = { }).code(500) } - const res = node.toJSON() - return reply({ - Hash: res.Hash, - Links: res.Links + node.toJSON((err, nodeJSON) => { + if (err) { + return reply({ + Message: 'Failed to get object: ' + err, + Code: 0 + }).code(500) + } + return reply({ + Hash: nodeJSON.Hash, + Links: nodeJSON.Links + }) }) }) } @@ -225,7 +286,8 @@ exports.parseKeyAndData = (request, reply) => { try { return reply({ data: file, - key: new Buffer(bs58.decode(request.query.arg)) // TODO: support ipfs paths: https://github.com/ipfs/http-api-spec/pull/68/files#diff-2625016b50d68d922257f74801cac29cR3880 + key: new Buffer(bs58.decode(request.query.arg)) + // TODO: support ipfs paths: https://github.com/ipfs/http-api-spec/pull/68/files#diff-2625016b50d68d922257f74801cac29cR3880 }) } catch (err) { return reply({ @@ -255,7 +317,15 @@ exports.patchAppendData = { }).code(500) } - return reply(node.toJSON()) + node.toJSON((err, nodeJSON) => { + if (err) { + return reply({ + Message: 'Failed to get object: ' + err, + Code: 0 + }).code(500) + } + return reply(nodeJSON) + }) }) } } @@ -279,10 +349,17 @@ exports.patchSetData = { }).code(500) } - const res = node.toJSON() - return reply({ - Hash: res.Hash, - Links: res.Links + node.toJSON((err, nodeJSON) => { + if (err) { + return reply({ + Message: 'Failed to get object: ' + err, + Code: 0 + }).code(500) + } + return reply({ + Hash: nodeJSON.Hash, + Links: nodeJSON.Links + }) }) }) } @@ -339,19 +416,44 @@ exports.patchAddLink = { }).code(500) } - const link = new DAGLink(name, linkedObj.size(), linkedObj.multihash()) - - request.server.app.ipfs.object.patch.addLink(root, link, (err, node) => { + linkedObj.size((err, size) => { if (err) { - log.error(err) - return reply({ - Message: 'Failed to add link to object: ' + err, + Message: 'Failed to get linked object: ' + err, Code: 0 }).code(500) } - - return reply(node.toJSON()) + linkedObj.multihash((err, multihash) => { + if (err) { + return reply({ + Message: 'Failed to get linked object: ' + err, + Code: 0 + }).code(500) + } + + const link = new DAGLink(name, size, multihash) + + request.server.app.ipfs.object.patch.addLink(root, link, (err, node) => { + if (err) { + log.error(err) + + return reply({ + Message: 'Failed to add link to object: ' + err, + Code: 0 + }).code(500) + } + + node.toJSON((err, nodeJSON) => { + if (err) { + return reply({ + Message: 'Failed to get object: ' + err, + Code: 0 + }).code(500) + } + return reply(nodeJSON) + }) + }) + }) }) }) } @@ -393,14 +495,21 @@ exports.patchRmLink = { request.server.app.ipfs.object.patch.rmLink(root, link, (err, node) => { if (err) { log.error(err) - return reply({ Message: 'Failed to add link to object: ' + err, Code: 0 }).code(500) } - return reply(node.toJSON()) + node.toJSON((err, nodeJSON) => { + if (err) { + return reply({ + Message: 'Failed to get object: ' + err, + Code: 0 + }).code(500) + } + return reply(nodeJSON) + }) }) } } diff --git a/test/http-api/ipfs-api/test-object.js b/test/http-api/ipfs-api/test-object.js index 3a4dea8ab7..ae84052f32 100644 --- a/test/http-api/ipfs-api/test-object.js +++ b/test/http-api/ipfs-api/test-object.js @@ -3,18 +3,22 @@ const expect = require('chai').expect const fs = require('fs') -const DAGLink = require('ipfs-merkle-dag').DAGLink +const dagPB = require('ipld-dag-pb') +const DAGLink = dagPB.DAGLink module.exports = (ctl) => { describe('.object', () => { it('.new', (done) => { ctl.object.new((err, result) => { expect(err).to.not.exist - const res = result.toJSON() - expect(res.Hash) - .to.equal('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n') - expect(res.Links).to.be.eql([]) - done() + + result.toJSON((err, nodeJSON) => { + expect(err).to.not.exist + expect(nodeJSON.Hash) + .to.equal('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n') + expect(nodeJSON.Links).to.be.eql([]) + done() + }) }) }) @@ -36,10 +40,12 @@ module.exports = (ctl) => { it('returns value', (done) => { ctl.object.get('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n', {enc: 'base58'}, (err, result) => { expect(err).to.not.exist - const res = result.toJSON() - expect(res.Links).to.be.eql([]) - expect(res.Data).to.equal('') - done() + result.toJSON((err, nodeJSON) => { + expect(err).to.not.exist + expect(nodeJSON.Links).to.be.eql([]) + expect(nodeJSON.Data).to.equal('') + done() + }) }) }) }) @@ -69,8 +75,11 @@ module.exports = (ctl) => { ctl.object.put(filePath, {enc: 'json'}, (err, res) => { expect(err).not.to.exist - expect(res.toJSON()).to.deep.equal(expectedResult) - done() + res.toJSON((err, nodeJSON) => { + expect(err).to.not.exist + expect(nodeJSON).to.deep.equal(expectedResult) + done() + }) }) }) }) @@ -187,8 +196,11 @@ module.exports = (ctl) => { ctl.object.patch.appendData(key, filePath, {enc: 'base58'}, (err, res) => { expect(err).not.to.exist - expect(res.toJSON()).to.deep.equal(expectedResult) - done() + res.toJSON((err, nodeJSON) => { + expect(err).to.not.exist + expect(nodeJSON).to.deep.equal(expectedResult) + done() + }) }) }) }) @@ -222,8 +234,11 @@ module.exports = (ctl) => { ctl.object.patch.setData(key, filePath, {enc: 'base58'}, (err, res) => { expect(err).not.to.exist - expect(res.toJSON()).to.deep.equal(expectedResult) - done() + res.toJSON((err, nodeJSON) => { + expect(err).to.not.exist + expect(nodeJSON).to.deep.equal(expectedResult) + done() + }) }) }) }) @@ -261,14 +276,16 @@ module.exports = (ctl) => { const link = new DAGLink(name, 10, ref) ctl.object.patch.addLink(root, link, {enc: 'base58'}, (err, result) => { expect(err).not.to.exist - const res = result.toJSON() - expect(res.Hash).to.equal('QmdVHE8fUD6FLNLugtNxqDFyhaCgdob372hs6BYEe75VAK') - expect(res.Links[0]).to.deep.equal({ - Name: 'foo', - Hash: 'QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn', - Size: 4 + result.toJSON((err, nodeJSON) => { + expect(err).to.not.exist + expect(nodeJSON.Hash).to.equal('QmdVHE8fUD6FLNLugtNxqDFyhaCgdob372hs6BYEe75VAK') + expect(nodeJSON.Links[0]).to.eql({ + Name: 'foo', + Hash: 'QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn', + Size: 4 + }) + done() }) - done() }) }) }) @@ -304,8 +321,11 @@ module.exports = (ctl) => { ctl.object.patch.rmLink(root, link, {enc: 'base58'}, (err, res) => { expect(err).not.to.exist - expect(res.toJSON().Hash).to.equal('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n') - done() + res.toJSON((err, nodeJSON) => { + expect(err).to.not.exist + expect(nodeJSON.Hash).to.equal('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n') + done() + }) }) }) })