diff --git a/API/files/README.md b/API/files/README.md index b1cdba67..724a110b 100644 --- a/API/files/README.md +++ b/API/files/README.md @@ -111,19 +111,24 @@ A great source of [examples][] can be found in the tests for this API. ##### `Go` **WIP** -##### `JavaScript` - ipfs.files.cat(multihash, [callback]) +##### `JavaScript` - ipfs.files.cat(ipfsPath, [callback]) -`multihash` is a [multihash][] which can be passed as +ipfsPath can be of type: -- Buffer, the raw Buffer of the multihash -- String, the base58 encoded version of the multihash +- `multihash` is a [multihash][] which can be passed as + - Buffer, the raw Buffer of the multihash + - String, the base58 encoded version of the multihash +- String, including the ipfs handler, a multihash and a path to traverse to, ie: + - '/ipfs/QmXEmhrMpbVvTh61FNAxP9nU7ygVtyvZA8HZDUaqQCAb66' + - '/ipfs/QmXEmhrMpbVvTh61FNAxP9nU7ygVtyvZA8HZDUaqQCAb66/a.txt' + - 'QmXEmhrMpbVvTh61FNAxP9nU7ygVtyvZA8HZDUaqQCAb66/a.txt' `callback` must follow `function (err, stream) {}` signature, where `err` is an error if the operation was not successful and `stream` is a readable stream of the file. If no `callback` is passed, a promise is returned. ```JavaScript -ipfs.files.cat(multihash, function (err, file) { +ipfs.files.cat(ipfsPath, function (err, file) { // file will be a stream containing the data of the file requested }) ``` @@ -136,9 +141,17 @@ A great source of [examples][] can be found in the tests for this API. ##### `Go` **WIP** -##### `JavaScript` - ipfs.files.get(multihash, [callback]) +##### `JavaScript` - ipfs.files.get(ipfsPath, [callback]) -Where `multihash` is an IPFS multihash or string multihash. +ipfsPath can be of type: + +- `multihash` is a [multihash][] which can be passed as + - Buffer, the raw Buffer of the multihash + - String, the base58 encoded version of the multihash +- String, including the ipfs handler, a multihash and a path to traverse to, ie: + - '/ipfs/QmXEmhrMpbVvTh61FNAxP9nU7ygVtyvZA8HZDUaqQCAb66' + - '/ipfs/QmXEmhrMpbVvTh61FNAxP9nU7ygVtyvZA8HZDUaqQCAb66/a.txt' + - 'QmXEmhrMpbVvTh61FNAxP9nU7ygVtyvZA8HZDUaqQCAb66/a.txt' `callback` must follow `function (err, stream) {}` signature, where `err` is an error if the operation was not successful. `stream` will be a Readable stream in diff --git a/package-lock.json b/package-lock.json index 9a6deb79..4205b2f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "interface-ipfs-core", - "version": "0.27.2", + "version": "0.28.0", "lockfileVersion": 1, "dependencies": { "abbrev": { @@ -7477,11 +7477,6 @@ "integrity": "sha1-mIkBnRAkzOVc3AaUmDN+9hhqEaE=", "dev": true }, - "source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=" - }, "source-map-support": { "version": "0.4.15", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz", @@ -8151,48 +8146,12 @@ "integrity": "sha1-BMgamb3V3FImPqKdJMa/jUgYpLs=", "dev": true }, - "uglify-js": { - "version": "github:mishoo/UglifyJS2#7906033e82d66f2735f8626e98f0f7352d9b3d25", - "dev": true, - "dependencies": { - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dev": true - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dev": true - } - } - }, "uglify-save-license": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/uglify-save-license/-/uglify-save-license-0.4.1.tgz", "integrity": "sha1-lXJsF8xv0XHDYX479NjYKqjEzOE=", "dev": true }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "dev": true - }, "ultron": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", diff --git a/package.json b/package.json index 31188c92..9b80a212 100644 --- a/package.json +++ b/package.json @@ -63,4 +63,4 @@ "haad ", "nginnever " ] -} \ No newline at end of file +} diff --git a/src/files.js b/src/files.js index af08bcf3..335c7681 100644 --- a/src/files.js +++ b/src/files.js @@ -14,6 +14,7 @@ const bl = require('bl') const isNode = require('detect-node') const concat = require('concat-stream') const through = require('through2') +const Buffer = require('safe-buffer').Buffer module.exports = (common) => { describe('.files', () => { @@ -48,14 +49,12 @@ module.exports = (common) => { }) }) - after((done) => { - common.teardown(done) - }) + after((done) => common.teardown(done)) describe('callback API', (done) => { describe('.add', () => { it('stream', (done) => { - const buffered = new Buffer('some data') + const buffered = Buffer.from('some data') const expectedMultihash = 'QmVv4Wz46JaZJeH5PMV4LGbRiiMKEmszPYY3g6fjGnVXBS' const rs = new Readable() @@ -196,9 +195,7 @@ module.exports = (common) => { } }) - files.forEach((file) => { - stream.write(file) - }) + files.forEach((file) => stream.write(file)) stream.end() }) @@ -218,6 +215,7 @@ module.exports = (common) => { describe('.cat', () => { it('with a base58 string encoded multihash', (done) => { const hash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' + ipfs.files.cat(hash, (err, stream) => { expect(err).to.not.exist() stream.pipe(bl((err, data) => { @@ -229,7 +227,7 @@ module.exports = (common) => { }) it('with a multihash', (done) => { - const mhBuf = new Buffer(bs58.decode('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP')) + const mhBuf = Buffer.from(bs58.decode('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP')) ipfs.files.cat(mhBuf, (err, stream) => { expect(err).to.not.exist() stream.pipe(bl((err, data) => { @@ -242,6 +240,7 @@ module.exports = (common) => { it('streams a large file', (done) => { const hash = 'Qme79tX2bViL26vNjPsF3DP1R9rMKMvnPYJiKTTKPrXJjq' + ipfs.files.cat(hash, (err, stream) => { expect(err).to.not.exist() stream.pipe(bl((err, data) => { @@ -251,6 +250,219 @@ module.exports = (common) => { })) }) }) + + it('with ipfs path', (done) => { + const ipfsPath = '/ipfs/Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' + + ipfs.files.cat(ipfsPath, (err, stream) => { + expect(err).to.not.exist() + stream.pipe(bl((err, data) => { + expect(err).to.not.exist() + expect(data.toString()).to.contain('Plz add me!') + done() + })) + }) + }) + + it('with ipfs path, nested value', (done) => { + const file = { + path: 'a/testfile.txt', + content: smallFile + } + + ipfs.files.createAddStream((err, stream) => { + expect(err).to.not.exist() + + stream.on('data', (file) => { + if (file.path === 'a') { + ipfs.files.cat(`/ipfs/${file.hash}/testfile.txt`, (err, stream) => { + expect(err).to.not.exist() + stream.pipe(bl((err, data) => { + expect(err).to.not.exist() + expect(data.toString()).to.contain('Plz add me!') + done() + })) + }) + } + }) + + stream.write(file) + stream.end() + }) + }) + }) + + describe('.get', () => { + it('with a base58 encoded multihash', (done) => { + const hash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' + ipfs.files.get(hash, (err, stream) => { + expect(err).to.not.exist() + + let files = [] + stream.pipe(through.obj((file, enc, next) => { + file.content.pipe(concat((content) => { + files.push({ + path: file.path, + content: content + }) + next() + })) + }, () => { + expect(files).to.be.length(1) + expect(files[0].path).to.be.eql(hash) + expect(files[0].content.toString()).to.contain('Plz add me!') + done() + })) + }) + }) + + it('with a multihash', (done) => { + const hash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' + const mhBuf = Buffer.from(bs58.decode(hash)) + ipfs.files.get(mhBuf, (err, stream) => { + expect(err).to.not.exist() + + let files = [] + stream.pipe(through.obj((file, enc, next) => { + file.content.pipe(concat((content) => { + files.push({ + path: file.path, + content: content + }) + next() + })) + }, () => { + expect(files).to.be.length(1) + expect(files[0].path).to.be.eql(hash) + expect(files[0].content.toString()).to.contain('Plz add me!') + done() + })) + }) + }) + + it('large file', (done) => { + const hash = 'Qme79tX2bViL26vNjPsF3DP1R9rMKMvnPYJiKTTKPrXJjq' + ipfs.files.get(hash, (err, stream) => { + expect(err).to.not.exist() + + // accumulate the files and their content + var files = [] + stream.pipe(through.obj((file, enc, next) => { + file.content.pipe(concat((content) => { + files.push({ + path: file.path, + content: content + }) + next() + })) + }, () => { + expect(files.length).to.equal(1) + expect(files[0].path).to.equal(hash) + expect(files[0].content).to.deep.equal(bigFile) + done() + })) + }) + }) + + it('directory', (done) => { + // Needs https://github.com/ipfs/js-ipfs-api/issues/339 to be fixed + // for js-ipfs-api + go-ipfs + if (!isNode) { return done() } + + const hash = 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP' + ipfs.files.get(hash, (err, stream) => { + expect(err).to.not.exist() + + // accumulate the files and their content + var files = [] + stream.pipe(through.obj((file, enc, next) => { + if (file.content) { + file.content.pipe(concat((content) => { + files.push({ + path: file.path, + content: content + }) + next() + })) + } else { + files.push(file) + next() + } + }, () => { + files = files.sort((a, b) => { + if (a.path > b.path) return 1 + if (a.path < b.path) return -1 + return 0 + }) + // Check paths + var paths = files.map((file) => { + return file.path + }) + expect(paths).to.include.members([ + 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP', + 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/alice.txt', + 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/empty-folder', + 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/files', + 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/files/empty', + 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/files/hello.txt', + 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/files/ipfs.txt', + 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/holmes.txt', + 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/jungle.txt', + 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/pp.txt' + ]) + + // Check contents + var contents = files.map(function (file) { + return file.content ? file.content.toString() : null + }) + expect(contents).to.include.members([ + directoryContent['alice.txt'].toString(), + directoryContent['files/hello.txt'].toString(), + directoryContent['files/ipfs.txt'].toString(), + directoryContent['holmes.txt'].toString(), + directoryContent['jungle.txt'].toString(), + directoryContent['pp.txt'].toString() + ]) + done() + })) + }) + }) + + it('with ipfs path, nested value', (done) => { + const file = { + path: 'a/testfile.txt', + content: smallFile + } + + ipfs.files.createAddStream((err, stream) => { + expect(err).to.not.exist() + + stream.on('data', (file) => { + if (file.path === 'a') { + ipfs.files.get(`/ipfs/${file.hash}/testfile.txt`, (err, stream) => { + expect(err).to.not.exist() + let files = [] + stream.pipe(through.obj((file, enc, next) => { + file.content.pipe(concat((content) => { + files.push({ + path: file.path, + content: content + }) + next() + })) + }, () => { + expect(files).to.be.length(1) + expect(files[0].content.toString()).to.contain('Plz add me!') + done() + })) + }) + } + }) + + stream.write(file) + stream.end() + }) + }) }) }) @@ -298,7 +510,7 @@ module.exports = (common) => { }) it('with a multihash', () => { - const hash = new Buffer(bs58.decode('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP')) + const hash = Buffer.from(bs58.decode('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP')) return ipfs.files.cat(hash) .then((stream) => { stream.pipe(bl((err, data) => { @@ -308,145 +520,8 @@ module.exports = (common) => { }) }) }) - }) - - describe('.get', () => { - it('with a base58 encoded multihash', (done) => { - const hash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' - ipfs.files.get(hash, (err, stream) => { - expect(err).to.not.exist() - - let files = [] - stream.pipe(through.obj((file, enc, next) => { - file.content.pipe(concat((content) => { - files.push({ - path: file.path, - content: content - }) - next() - })) - }, () => { - expect(files).to.be.length(1) - expect(files[0].path).to.be.eql(hash) - expect(files[0].content.toString()).to.contain('Plz add me!') - done() - })) - }) - }) - - it('with a multihash', (done) => { - const hash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' - const mhBuf = new Buffer(bs58.decode(hash)) - ipfs.files.get(mhBuf, (err, stream) => { - expect(err).to.not.exist() - - let files = [] - stream.pipe(through.obj((file, enc, next) => { - file.content.pipe(concat((content) => { - files.push({ - path: file.path, - content: content - }) - next() - })) - }, () => { - expect(files).to.be.length(1) - expect(files[0].path).to.be.eql(hash) - expect(files[0].content.toString()).to.contain('Plz add me!') - done() - })) - }) - }) - - it('large file', (done) => { - const hash = 'Qme79tX2bViL26vNjPsF3DP1R9rMKMvnPYJiKTTKPrXJjq' - ipfs.files.get(hash, (err, stream) => { - expect(err).to.not.exist() - - // accumulate the files and their content - var files = [] - stream.pipe(through.obj((file, enc, next) => { - file.content.pipe(concat((content) => { - files.push({ - path: file.path, - content: content - }) - next() - })) - }, () => { - expect(files.length).to.equal(1) - expect(files[0].path).to.equal(hash) - expect(files[0].content).to.deep.equal(bigFile) - done() - })) - }) - }) - - it('directory', (done) => { - // Needs https://github.com/ipfs/js-ipfs-api/issues/339 to be fixed - // for js-ipfs-api + go-ipfs - if (!isNode) { return done() } - - const hash = 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP' - ipfs.files.get(hash, (err, stream) => { - expect(err).to.not.exist() - - // accumulate the files and their content - var files = [] - stream.pipe(through.obj((file, enc, next) => { - if (file.content) { - file.content.pipe(concat((content) => { - files.push({ - path: file.path, - content: content - }) - next() - })) - } else { - files.push(file) - next() - } - }, () => { - files = files.sort((a, b) => { - if (a.path > b.path) return 1 - if (a.path < b.path) return -1 - return 0 - }) - // Check paths - var paths = files.map((file) => { - return file.path - }) - expect(paths).to.include.members([ - 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP', - 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/alice.txt', - 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/empty-folder', - 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/files', - 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/files/empty', - 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/files/hello.txt', - 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/files/ipfs.txt', - 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/holmes.txt', - 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/jungle.txt', - 'QmVvjDy7yF7hdnqE8Hrf4MHo5ABDtb5AbX6hWbD3Y42bXP/pp.txt' - ]) - - // Check contents - var contents = files.map(function (file) { - return file.content ? file.content.toString() : null - }) - expect(contents).to.include.members([ - directoryContent['alice.txt'].toString(), - directoryContent['files/hello.txt'].toString(), - directoryContent['files/ipfs.txt'].toString(), - directoryContent['holmes.txt'].toString(), - directoryContent['jungle.txt'].toString(), - directoryContent['pp.txt'].toString() - ]) - done() - })) - }) - }) - describe('promise', () => { + describe('.get', () => { it('with a base58 encoded string', () => { const hash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' return ipfs.files.get(hash).then((stream) => {