From 09397903d667fb4ae6cf27f911c8b37a981857fe Mon Sep 17 00:00:00 2001 From: David Dias Date: Tue, 28 Jun 2016 10:17:23 +0100 Subject: [PATCH 1/4] init pinning API --- API/pinning-api/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 API/pinning-api/README.md diff --git a/API/pinning-api/README.md b/API/pinning-api/README.md new file mode 100644 index 00000000..8ac8c7d8 --- /dev/null +++ b/API/pinning-api/README.md @@ -0,0 +1,3 @@ +pinning API +=========== + From fa784b337333fea37f54813e771b4a6325e1d8d9 Mon Sep 17 00:00:00 2001 From: David Dias Date: Tue, 9 Aug 2016 08:44:59 +0100 Subject: [PATCH 2/4] feat(pinning): add pin.add spec --- API/pinning-api/README.md | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/API/pinning-api/README.md b/API/pinning-api/README.md index 8ac8c7d8..9c37b201 100644 --- a/API/pinning-api/README.md +++ b/API/pinning-api/README.md @@ -1,3 +1,58 @@ pinning API =========== +#### `add` + +> Pin an IPFS object to local storage + +##### `Go` **WIP** + +##### `JavaScript` - ipfs.pin.add(hash, [options, callback]) + +Where: + +- `hash` is an IPFS multihash. +- `options` is an object that can contain the following keys: + - `recursive` - Recursevely pin the object linked. + +`callback` must follow `function (err) {}` signature, where `err` is an error if the operation was not successful. + +If no `callback` is passed, a promise is returned. + +Example: + +```JavaScript +ipfs.pin.add(hash, function (err) {}) +``` + + +#### `ls` + +> + +##### `Go` **WIP** + +##### `JavaScript` - ipfs.SOMETHING(data, [callback]) + +`callback` must follow `function (err, res) {}` signature, where `err` is an error if the operation was not successful. `res` will be an array of: + +If no `callback` is passed, a promise is returned. + +Example: + + + +#### `rm` + +> + +##### `Go` **WIP** + +##### `JavaScript` - ipfs.SOMETHING(data, [callback]) + +`callback` must follow `function (err, res) {}` signature, where `err` is an error if the operation was not successful. `res` will be an array of: + +If no `callback` is passed, a promise is returned. + +Example: + From 59a45d0747079e8410613bfc7644075cf18741b8 Mon Sep 17 00:00:00 2001 From: David Dias Date: Tue, 9 Aug 2016 08:50:35 +0100 Subject: [PATCH 3/4] feat(pinning): add pin.ls + rm spec --- API/pinning-api/README.md | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/API/pinning-api/README.md b/API/pinning-api/README.md index 9c37b201..c08c3c27 100644 --- a/API/pinning-api/README.md +++ b/API/pinning-api/README.md @@ -25,34 +25,49 @@ Example: ipfs.pin.add(hash, function (err) {}) ``` - #### `ls` -> +> List all the objects pinned to local storage or under a specific hash. ##### `Go` **WIP** -##### `JavaScript` - ipfs.SOMETHING(data, [callback]) +##### `JavaScript` - ipfs.pin.ls([hash, options, callback]) -`callback` must follow `function (err, res) {}` signature, where `err` is an error if the operation was not successful. `res` will be an array of: +Where: + +- `hash` is an IPFS multihash. +- `options` is an object that can contain the following keys: + - `type` - Return also the type of pin (direct, indirect or recursive) + +`callback` must follow `function (err, pinset) {}` signature, where `err` is an error if the operation was not successful. `pinset` is an array of objects with keys `hash` and `type`. If no `callback` is passed, a promise is returned. Example: +```JavaScript +ipfs.pin.ls(function (err, pinset) {}) +``` #### `rm` -> +> Remove an hash from the pinset ##### `Go` **WIP** -##### `JavaScript` - ipfs.SOMETHING(data, [callback]) +##### `JavaScript` - ipfs.pin.rm(hash, [callback]) + +Where `hash` is a multihash. -`callback` must follow `function (err, res) {}` signature, where `err` is an error if the operation was not successful. `res` will be an array of: +`callback` must follow `function (err) {}` signature, where `err` is an error if the operation was not successful. If no `callback` is passed, a promise is returned. Example: +```JavaScript +ipfs.pin.rm(hash, function (err, pinset) {}) +``` + + From eaabe8fd3914833d425ca91a7d56cd612afaa790 Mon Sep 17 00:00:00 2001 From: David Dias Date: Mon, 15 Aug 2016 14:23:14 +0100 Subject: [PATCH 4/4] feat(pin): tests --- API/pin/README.md | 90 ++++++++++++++++++++++ API/pinning-api/README.md | 73 ------------------ package.json | 2 +- src/index.js | 1 + src/pin.js | 158 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 250 insertions(+), 74 deletions(-) create mode 100644 API/pin/README.md delete mode 100644 API/pinning-api/README.md create mode 100644 src/pin.js diff --git a/API/pin/README.md b/API/pin/README.md new file mode 100644 index 00000000..7d45f12d --- /dev/null +++ b/API/pin/README.md @@ -0,0 +1,90 @@ +Pin API +======= + +#### `add` + +> Adds an IPFS object to the pinset and also stores it to the IPFS repo. pinset is the set of hashes currently pinned (not gc'able). + +##### `Go` **WIP** + +##### `JavaScript` - ipfs.pin.add(hash, [options, callback]) + +Where: + +- `hash` is an IPFS multihash. +- `options` is an object that can contain the following keys + - 'recursive' - Recursively pin the object linked. Type: bool. Default: `false` + +`callback` must follow `function (err, res) {}` signature, where `err` is an error if the operation was not successful. `res` is an array of objects that represent the files that were pinned. Example: + +```JavaScript +{ + hash: 'QmHash' +} +``` + +If no `callback` is passed, a promise is returned. + +Example: + +```JavaScript +ipfs.pin.add(hash, function (err) {}) +``` + +#### `ls` + +> List all the objects pinned to local storage or under a specific hash. + +##### `Go` **WIP** + +##### `JavaScript` - ipfs.pin.ls([hash, options, callback]) + +Where: + +- `hash` is an IPFS multihash. +- `options` is an object that can contain the following keys: + - 'type' - Return also the type of pin (direct, indirect or recursive) + +`callback` must follow `function (err, pinset) {}` signature, where `err` is an error if the operation was not successful. `pinset` is an array of objects with keys `hash` and `type`. + +If no `callback` is passed, a promise is returned. + +Example: + +```JavaScript +ipfs.pin.ls(function (err, pinset) { + if (err) { + throw err + } + console.log(pinset) +}) +``` + + +#### `rm` + +> Remove a hash from the pinset + +##### `Go` **WIP** + +##### `JavaScript` - ipfs.pin.rm(hash, [options, callback]) + +Where: +- `hash` is a multihash. +- `options` is an object that can contain the following keys + - 'recursive' - Recursively unpin the object linked. Type: bool. Default: `false` + +`callback` must follow `function (err) {}` signature, where `err` is an error if the operation was not successful. + +If no `callback` is passed, a promise is returned. + +Example: + +```JavaScript +ipfs.pin.rm(hash, function (err, pinset) { + if (err) { + throw err + } + console.log(pinset) prints the hashes that were unpinned +}) +``` diff --git a/API/pinning-api/README.md b/API/pinning-api/README.md deleted file mode 100644 index c08c3c27..00000000 --- a/API/pinning-api/README.md +++ /dev/null @@ -1,73 +0,0 @@ -pinning API -=========== - -#### `add` - -> Pin an IPFS object to local storage - -##### `Go` **WIP** - -##### `JavaScript` - ipfs.pin.add(hash, [options, callback]) - -Where: - -- `hash` is an IPFS multihash. -- `options` is an object that can contain the following keys: - - `recursive` - Recursevely pin the object linked. - -`callback` must follow `function (err) {}` signature, where `err` is an error if the operation was not successful. - -If no `callback` is passed, a promise is returned. - -Example: - -```JavaScript -ipfs.pin.add(hash, function (err) {}) -``` - -#### `ls` - -> List all the objects pinned to local storage or under a specific hash. - -##### `Go` **WIP** - -##### `JavaScript` - ipfs.pin.ls([hash, options, callback]) - -Where: - -- `hash` is an IPFS multihash. -- `options` is an object that can contain the following keys: - - `type` - Return also the type of pin (direct, indirect or recursive) - -`callback` must follow `function (err, pinset) {}` signature, where `err` is an error if the operation was not successful. `pinset` is an array of objects with keys `hash` and `type`. - -If no `callback` is passed, a promise is returned. - -Example: - -```JavaScript -ipfs.pin.ls(function (err, pinset) {}) -``` - - -#### `rm` - -> Remove an hash from the pinset - -##### `Go` **WIP** - -##### `JavaScript` - ipfs.pin.rm(hash, [callback]) - -Where `hash` is a multihash. - -`callback` must follow `function (err) {}` signature, where `err` is an error if the operation was not successful. - -If no `callback` is passed, a promise is returned. - -Example: - -```JavaScript -ipfs.pin.rm(hash, function (err, pinset) {}) -``` - - diff --git a/package.json b/package.json index 5b437904..b3750513 100644 --- a/package.json +++ b/package.json @@ -47,4 +47,4 @@ "greenkeeperio-bot ", "nginnever " ] -} \ No newline at end of file +} diff --git a/src/index.js b/src/index.js index 33c4ad49..38d0b50b 100644 --- a/src/index.js +++ b/src/index.js @@ -3,3 +3,4 @@ exports.object = require('./object') exports.files = require('./files') exports.config = require('./config') +exports.pin = require('./pin') diff --git a/src/pin.js b/src/pin.js new file mode 100644 index 00000000..4f92a1ff --- /dev/null +++ b/src/pin.js @@ -0,0 +1,158 @@ +/* eslint-env mocha */ +/* eslint max-nested-callbacks: ["error", 8] */ + +'use strict' + +const expect = require('chai').expect +const fs = require('fs') +const path = require('path') + +const testfile = fs.readFileSync(path.join(__dirname, './data/testfile.txt')) + +module.exports = (common) => { + describe('.pin', () => { + let ipfs + + before(function (done) { + // CI takes longer to instantiate the daemon, + // so we need to increase the timeout for the + // before step + this.timeout(20 * 1000) + + common.setup((err, factory) => { + expect(err).to.not.exist + factory.spawnNode((err, node) => { + expect(err).to.not.exist + ipfs = node + populate() + }) + }) + + function populate () { + const expectedMultihash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' + + ipfs.files.add(testfile, (err, res) => { + expect(err).to.not.exist + + expect(res).to.have.length(1) + expect(res[0].hash).to.equal(expectedMultihash) + expect(res[0].path).to.equal(expectedMultihash) + done() + }) + } + }) + + after((done) => { + common.teardown(done) + }) + + describe('callback API', () => { + // 1st, because ipfs.files.add pins automatically + it('.rm', (done) => { + const hash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' + + ipfs.pin.rm(hash, { recursive: true }, (err, pinset) => { + expect(err).to.not.exist + expect(pinset).to.exist + ipfs.pin.ls({ type: 'direct' }, (err, pinset) => { + expect(err).to.not.exist + expect(pinset).to.be.empty + done() + }) + }) + }) + + it('.add', (done) => { + const hash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' + + ipfs.pin.add(hash, { recursive: false }, (err, pinset) => { + expect(err).to.not.exist + expect(pinset[0]).to.be.equal(hash) + done() + }) + }) + + it('.ls', (done) => { + ipfs.pin.ls((err, pinset) => { + expect(err).to.not.exist + expect(pinset).to.not.be.empty + done() + }) + }) + + it('.ls type direct', (done) => { + ipfs.pin.ls({ type: 'direct' }, (err, pinset) => { + expect(err).to.not.exist + expect(pinset).to.not.be.empty + done() + }) + }) + + it('.ls type indirect', (done) => { + ipfs.pin.ls({ type: 'indirect' }, (err, pinset) => { + expect(err).to.not.exist + expect(pinset).to.not.be.empty + done() + }) + }) + + it('.ls type recursive', (done) => { + ipfs.pin.ls({ type: 'recursive' }, (err, pinset) => { + expect(err).to.not.exist + expect(pinset).to.not.be.empty + done() + }) + }) + + it('.ls for a specific hash', (done) => { + const hash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' + + ipfs.pin.ls(hash, (err, pinset) => { + expect(err).to.not.exist + expect(pinset).to.exist + done() + }) + }) + }) + + describe('promise API', () => { + it('.add', () => { + const hash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' + + return ipfs.pin.add(hash, { recursive: false }) + .then((pinset) => { + expect(pinset[0]).to.be.equal(hash) + }) + }) + + it('.ls', () => { + return ipfs.pin.ls() + .then((pinset) => { + expect(pinset).to.exist + expect(pinset).to.not.be.empty + }) + }) + + it('.ls hash', () => { + const hash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' + + return ipfs.pin.ls(hash) + .then((pinset) => { + expect(pinset).to.exist + }) + }) + + it('.rm', () => { + const hash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP' + + return ipfs.pin.rm(hash, { recursive: false }) + .then((pinset) => { + return ipfs.pin.ls({ type: 'direct' }) + }) + .then((pinset) => { + expect(pinset).to.be.empty + }) + }) + }) + }) +}