Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reorangized and implementation of a basic dag store #2

Merged
merged 7 commits into from
Nov 13, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
11 changes: 11 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
sudo: false
language: node_js
node_js:
- "4.0"

# Make sure we have new NPM.
before_install:
- npm install -g npm

script:
- npm test
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# ipfs-blob-store
ipfs-blob-store
===============

Implements the [abstract-blob-store] API, built ontop of IPFS.
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) [[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) ![Build Status](https://travis-ci.org/diasdavid/ipfs-blob-store.svg?style=flat-square)](https://travis-ci.org/diasdavid/ipfs-blob-store) ![](https://img.shields.io/badge/coverage-%3F-yellow.svg?style=flat-square) [![Dependency Status](https://david-dm.org/diasdavid/ipfs-blob-store.svg?style=flat-square)](https://david-dm.org/diasdavid/ipfs-blob-store) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)

![](https://github.com/maxogden/abstract-blob-store/raw/master/badge.png)

> Implements the [abstract-blob-store] API, built on top of IPFS.
60 changes: 5 additions & 55 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,67 +1,17 @@
var ipfs = require('ipfs-api')
var stream = require('stream')
var multihash = require('multihashes')
var base58 = require('base58-native')
var block = require('./lib/block')
var dag = require('./lib/dag')

module.exports = function (opts) {
if (!opts) opts = {}

opts.host = opts.host || '127.0.0.1'
opts.port = opts.port || 5001

var store = {}

var node = ipfs(opts.host, opts.port)

store.createWriteStream = function (opts, cb) {
if (typeof opts === 'string') opts = {key: opts}
if (typeof opts === 'function') return store.createWriteStream(null, opts)

var bufferStream = new stream.PassThrough()

node.block.put(bufferStream, function (err, data) {
if (err) return cb(err)

cb(null, {
key: data.Key,
size: data.Size
})
})

return bufferStream
}

store.createReadStream = function (opts) {
if (typeof opts === 'string') opts = {key: opts}
var bufferStream = new stream.PassThrough()
node.block.get(opts.key, function (err, stream) {
if (err && !stream) return bufferStream.emit('error', 'No stream')
stream.pipe(bufferStream)
})

return bufferStream
return {
block: block(node),
dag: dag(node)
}

store.exists = function (opts, cb) {
if (typeof opts === 'string') opts = {key: opts}
var buf

try {
buf = base58.decode(opts.key)
void multihash.decode(buf)
} catch (e) {
return cb(null, false)
}

node.block.get(opts.key, function (err, stream) {
if (err) return cb(err)
cb(null, true)
})
}

store.remove = function (opts, cb) {
cb(null, false)
}

return store
}
61 changes: 61 additions & 0 deletions lib/block.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
var stream = require('stream')
var multihash = require('multihashes')
var base58 = require('base58-native')

module.exports = function (node) {
var store = {}

store.createWriteStream = function (opts, cb) {
if (typeof opts === 'string') opts = {key: opts}
if (typeof opts === 'function') return store.createWriteStream(null, opts)

var bufferStream = new stream.PassThrough()

node.block.put(bufferStream, function (err, data) {
if (err) return cb(err)

cb(null, {
key: data.Key,
size: data.Size
})
})

return bufferStream
}

store.createReadStream = function (opts) {
if (typeof opts === 'string') opts = {key: opts}

var bufferStream = new stream.PassThrough()

node.block.get(opts.key, function (err, stream) {
if (err && !stream) return bufferStream.emit('error', err)
stream.pipe(bufferStream)
})

return bufferStream
}

store.exists = function (opts, cb) {
if (typeof opts === 'string') opts = {key: opts}
var buf

try {
buf = base58.decode(opts.key)
void multihash.decode(buf)
} catch (e) {
return cb(null, false)
}

node.block.get(opts.key, function (err, stream) {
if (err) return cb(err)
cb(null, true)
})
}

store.remove = function (opts, cb) {
cb(null, false)
}

return store
}
148 changes: 148 additions & 0 deletions lib/dag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
var stream = require('stream')
var async = require('async')

var Node = function () {
this.Links = []
this.Data = new Buffer('')
}

var Link = function () {
this.Hash = ''
this.Size = 0
this.Name = ''
}

module.exports = function (node) {
var store = {}
var root = new Node()
var root_hash = ''
var map = {}

store.createWriteStream = function (opts, cb) {
if (typeof opts === 'string') opts = {key: opts}
if (typeof opts === 'function') return store.createWriteStream(null, opts)
if (typeof opts === 'undefined' || opts === null) opts = {}

var bufferStream = new stream.PassThrough()
var buffer

bufferStream.on('data', function (chunk) {
if (!buffer) buffer = chunk
else {
buffer = Buffer.concat([buffer, chunk], buffer.length + chunk.length)
}
})

bufferStream.on('end', function () {
var blob = new Node()
blob.Data = buffer.toString()
async.waterfall([
function (callback) {
var raw = new Buffer(JSON.stringify(blob))
node.object.put(raw, 'json', callback)
},
function (res, callback) {
node.object.stat(res.Hash, function (err, stat) {
callback(err, res, stat)
})
},
function (res, stat, callback) {
var link = new Link()

link.Hash = res.Hash
link.Size = stat.CumulativeSize
link.Name = opts.key || res.Hash

root.Links = root.Links.filter(function (item) {
return item.Name !== opts.key
})

root.Links.push(link)

root.Data = root_hash
var raw = new Buffer(JSON.stringify(root))
node.object.put(raw, 'json', function (err, new_root) {
callback(err, link, new_root)
})
}, function (link, new_root, callback) {
map[opts.key] = true

callback(null, {
key: link.Name,
root: new_root.Hash,
hash: link.Hash,
size: link.Size
})

root_hash = new_root.Hash
}
], function (err, meta) {
if (err) return cb(err)
cb(null, meta)
})
})

return bufferStream
}

store.createReadStream = function (opts) {
if (typeof opts === 'string') {
opts = {key: opts}
}

var bufferStream = new stream.PassThrough()
node.object.data((opts.root || root_hash) + '/' + opts.key, function (err, stream) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You want node.object.get here, right? If the write stream stores a JSON object, the read stream should probably output one as well.

if (err && !stream) return bufferStream.emit('error', err)
stream.pipe(bufferStream)
})

return bufferStream
}

store.exists = function (opts, cb) {
if (typeof opts === 'string') {
opts = {key: opts}
}
if (!root_hash) {
return cb(null, false)
}

node.object.stat((opts.root || root_hash) + '/' + opts.key, function (err, stat) {
if (err) {
cb(null, false)
} else {
cb(null, true)
}
})
}

store.remove = function (opts, cb) {
async.waterfall([
function (callback) {
root.Links = root.Links.filter(function (item) {
return item.Name !== opts.key
})

root.Data = root_hash
var raw = new Buffer(JSON.stringify(root))
node.object.put(raw, 'json', function (err, new_root) {
callback(err, new_root)
})
},
function (new_root, callback) {
map[opts.key] = false

callback(null, true)

root_hash = new_root.Hash
}
], function (err, meta) {
if (err) {
return cb(err, false)
}
cb(null, meta)
})
}

return store
}
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "ipfs-blob-store",
"version": "1.0.0",
"version": "0.0.0",
"description": "",
"main": "index.js",
"main": "src/index.js",
"scripts": {
"test": "tape test.js",
"lint": "git diff --name-only --cached --relative | egrep .js$ | xargs --no-run-if-empty standard"
"test": "node tests/dag.js",
"lint": "./node_modules/.bin/standard"
},
"repository": {
"type": "git",
Expand All @@ -30,13 +30,13 @@
"pre-commit": "^1.0.6"
},
"pre-commit": [
"test",
"lint"
],
"dependencies": {
"async": "^1.2.0",
"base58-native": "^0.1.4",
"end-of-stream": "^1.1.0",
"ipfs-api": "^1.1.7",
"multihashes": "^0.1.2",
"vinyl": "^0.4.6"
"ipfs-api": "^2.3.2",
"multihashes": "^0.1.2"
}
}
15 changes: 15 additions & 0 deletions tests/block.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
var test = require('tape')
var abstractBlobTests = require('abstract-blob-store/tests')
var ipfsBlobStore = require('../index.js')

var common = {
setup: function (t, cb) {
var store = ipfsBlobStore().block
cb(null, store)
},
teardown: function (t, store, blob, cb) {
cb()
}
}

abstractBlobTests(test, common)
4 changes: 2 additions & 2 deletions test.js → tests/dag.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
var test = require('tape')
var abstractBlobTests = require('abstract-blob-store/tests')
var blobs = require('./')
var ipfsBlobStore = require('../index.js')

var common = {
setup: function (t, cb) {
var store = blobs()
var store = ipfsBlobStore().dag
cb(null, store)
},
teardown: function (t, store, blob, cb) {
Expand Down