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

.add/files.add http-api endpoint #323

Closed
wants to merge 10 commits into from
4 changes: 2 additions & 2 deletions src/core/ipfs/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ module.exports = function files (self) {
}),

get: promisify((hash, callback) => {
const exportFile = Exporter(hash, self._dagS)
callback(null, exportFile)
const exportStream = Exporter(hash, self._dagS)
callback(null, exportStream)
})
}
}
1 change: 0 additions & 1 deletion src/core/ipfs/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ module.exports = function object (self) {
if (err) {
return cb(err)
}

cb(null, node.data)
})
}),
Expand Down
124 changes: 123 additions & 1 deletion src/http-api/resources/files.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
'use strict'

const bs58 = require('bs58')
const ndjson = require('ndjson')
const multipart = require('ipfs-multipart')
const debug = require('debug')
const tar = require('tar-stream')
const log = debug('http-api:files')
log.error = debug('http-api:files:error')
const async = require('async')

exports = module.exports

Expand Down Expand Up @@ -42,8 +46,126 @@ exports.cat = {
Code: 0
}).code(500)
}
return reply(stream).header('X-Stream-Output', '1')
})
}
}

exports.get = {
// uses common parseKey method that returns a `key`
parseArgs: exports.parseKey,

// main route handler which is called after the above `parseArgs`, but only if the args were valid
handler: (request, reply) => {
const key = request.pre.args.key

request.server.app.ipfs.files.get(key, (err, stream) => {
if (err) {
log.error(err)
return reply({
Message: 'Failed to get file: ' + err,
Code: 0
}).code(500)
}
var pack = tar.pack()
const files = []
stream.on('data', (data) => {
return reply(data)
files.push(data)
})
const processFile = (file) => {
return (callback) => {
if (!file.content) { // is directory
pack.entry({name: file.path, type: 'directory'})
callback()
} else { // is file
const fileContents = []
file.content.on('data', (data) => {
fileContents.push(data)
})
file.content.on('end', () => {
pack.entry({name: file.path}, Buffer.concat(fileContents))
callback()
})
}
}
}
stream.on('end', () => {
const callbacks = files.map(processFile)
async.series(callbacks, () => {
pack.finalize()
reply(pack).header('X-Stream-Output', '1')
})
})
})
}
}

exports.add = {
handler: (request, reply) => {
if (!request.payload) {
return reply('Array, Buffer, or String is required.').code(400).takeover()
}

const parser = multipart.reqParser(request.payload)

var filesParsed = false
var filesAdded = 0

var serialize = ndjson.serialize()
// hapi doesn't permit object streams: http://hapijs.com/api#replyerr-result
serialize._readableState.objectMode = false

request.server.app.ipfs.files.createAddStream((err, fileAdder) => {
if (err) {
return reply({
Message: err,
Code: 0
}).code(500)
}

fileAdder.on('data', (file) => {
const filePath = file.path ? file.path : file.hash
serialize.write({
Name: filePath,
Hash: file.hash
})
filesAdded++
})

fileAdder.on('end', () => {
if (filesAdded === 0 && filesParsed) {
return reply({
Message: 'Failed to add files.',
Code: 0
}).code(500)
} else {
serialize.end()
return reply(serialize)
.header('x-chunked-output', '1')
.header('content-type', 'application/json')
}
})

parser.on('file', (fileName, fileStream) => {
var filePair = {
path: fileName,
content: fileStream
}
filesParsed = true
fileAdder.write(filePair)
})
parser.on('directory', (directory) => {
fileAdder.write({
path: directory,
content: ''
})
})

parser.on('end', () => {
if (!filesParsed) {
return reply("File argument 'data' is required.").code(400).takeover()
}
fileAdder.end()
})
})
}
Expand Down
26 changes: 26 additions & 0 deletions src/http-api/routes/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = (server) => {
const api = server.select('API')

api.route({
// TODO fix method
method: '*',
path: '/api/v0/cat',
config: {
Expand All @@ -15,4 +16,29 @@ module.exports = (server) => {
handler: resources.files.cat.handler
}
})

api.route({
// TODO fix method
method: '*',
path: '/api/v0/get',
config: {
pre: [
{ method: resources.files.get.parseArgs, assign: 'args' }
],
handler: resources.files.get.handler
}
})

api.route({
// TODO fix method
method: '*',
path: '/api/v0/add',
config: {
payload: {
parse: false,
output: 'stream'
},
handler: resources.files.add.handler
}
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

'use strict'

/*
const test = require('interface-ipfs-core')
const FactoryClient = require('./../../utils/factory-http')

Expand All @@ -17,8 +16,5 @@ const common = {
fc.dismantle(callback)
}
}
*/

// TODO
// needs: https://github.com/ipfs/js-ipfs/pull/323
// test.files(common)
test.files(common)