Skip to content

Commit

Permalink
Merge pull request #2 from ipfs/masylum/initial-implementation
Browse files Browse the repository at this point in the history
Bring @masylum PR and @diasdavid PR to be a PR from a ipfs/js-ipfs-repo branch to master
  • Loading branch information
daviddias committed Dec 10, 2015
2 parents 8cb9452 + 8b68155 commit e3dcf55
Show file tree
Hide file tree
Showing 46 changed files with 954 additions and 4 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ coverage
# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
build

# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
Expand Down
115 changes: 113 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,113 @@
# js-ipfs-repo
Implementation of the IPFS repo spec (https://github.com/ipfs/specs/tree/master/repo) in JavaScript
js-ipfs-repo
============


[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) [![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) [![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)

> Implementation of the IPFS repo spec (https://github.com/ipfs/specs/tree/master/repo) in JavaScript
## API

### `Repo`

Constructor, accepts a path and options:

```js
var Repo = require('js-ipfs-repo')
var repo = new Repo('/Users/someone/.ipfs', {adaptor: 'fs'})
```

Options:

- `adaptor`: String with the adaptor. Defaults to `fs`

### `#version`

Read/Write the version number of that repository.

```js
repo.version().read(function (err, num) {
console.log(err, num) // => 2
})

repo.version().write(3, function (err) {
console.log(err)
})
```

### `#api`

Read/Write the JSON configuration for that repository.

```js
repo.api().read(function (err, multiaddr) {
console.log(err, multiaddr)
})

repo.api().write('/ip4/127.0.0.1/tcp/5001', function (err) {
console.log(err)
})
```

### `#config`

Read/Write the JSON configuration for that repository.

```js
repo.config().read(function (err, json) {
console.log(err, json)
})

repo.config().write({foo: 'bar'}, function (err) {
console.log(err)
})
```

### `#blocks`

Store data on the block store.

```js
repo.blocks().read('12200007d4e3a319cd8c7c9979280e150fc5dbaae1ce54e790f84ae5fd3c3c1a0475', function (buff, err) {
console.log(err)
})
```

```js
repo.blocks().write(buff, function (buff, err) {
console.log(buff.toString('utf-8'), err)
})
```

### `#repo`

Read/Write the `repo.lock` file.

```js
repo.repo().read(function (err, content) {
console.log(err, content)
})

repo.repo().write('foo', function (err) {
console.log(err)
})
```

## Adaptors

By default it will use the `fs-repo` adaptor. Eventually we can write other adaptors
and make those available on configuration.

### `fs-repo`

The default adaptor. Uses the `repo.lock` file to ensure there are no simultaneous reads
nor writes. Uses the `fs-blob-store`.

### `memory-repo`

Ideal for testing purposes. Uses the `abstract-blob-store`.

## Tests

Not there yet! Should ran both in node and in Phantom with compatible
adaptors.
40 changes: 40 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "ipfs-repo",
"version": "0.0.1",
"description": "IPFS Repo implementation",
"main": "src/index.js",
"scripts": {
"test": "mocha tests/*-test.js",
"coverage": "istanbul cover --print both -- _mocha tests/*-test.js",
"lint": "standard"
},
"repository": {
"type": "git",
"url": "https://github.com/diasdavid/js-ipfs-repo.git"
},
"keywords": [
"IPFS"
],
"pre-commit": [
"lint",
"test"
],
"homepage": "https://github.com/ipfs/js-ipfs-record",
"devDependencies": {
"chai": "^3.4.1",
"istanbul": "^0.4.1",
"mocha": "^2.3.4",
"ncp": "^2.0.0",
"pre-commit": "^1.1.1",
"rimraf": "^2.4.4",
"standard": "^5.1.1"
},
"dependencies": {
"abstract-blob-store": "^3.2.0",
"concat-stream": "^1.5.1",
"fs-blob-store": "^5.2.0",
"level-js": "^2.2.2",
"lockfile": "^1.0.1",
"multihashes": "^0.2.0"
}
}
121 changes: 121 additions & 0 deletions src/adaptors/fs-repo/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
var concat = require('concat-stream')
var fs = require('fs-blob-store')
var path = require('path')
var lockFile = require('lockfile')

function BlobStore (base_path) {
this.store = fs(base_path)
this.LOCK_PATH = path.join(base_path, 'repo.lock')
}

BlobStore.prototype = {

/**
* Read a blob on a given path
* It holds the repo.lock while reading
*
* @param {String} key
* @param {Function} cb
* @return {ReadableStream}
*/
read: function (key, cb) {
var store = this.store
var LOCK_PATH = this.LOCK_PATH
var rs = store.createReadStream(key)

function onFinish (buff) {
lockFile.unlock(LOCK_PATH, function (err) {
if (err) return cb(err)

cb(null, buff.toString('utf8'))
})
}

function onLock (err) {
if (err) return cb(err)

rs.on('error', cb)
rs.pipe(concat(onFinish))
}

lockFile.lock(LOCK_PATH, {}, onLock)

return rs
},

/**
* Read a blob on a given path
* It does not lock
*
* @param {String} key
* @param {Function} cb
* @return {ReadableStream}
*/
readWithoutLock: function (key, cb) {
var rs = this.store.createReadStream(key)

rs.on('error', cb)
rs.pipe(concat(function (buff) {
cb(null, buff.toString('utf8'))
}))

return rs
},

/**
* Write the contents to the blob in the given path
* It holds the repo.lock while reading
*
* @param {String} key
* @param {Function} cb
* @return {WritableStream}
*/
write: function (key, content, cb) {
var store = this.store
var LOCK_PATH = this.LOCK_PATH
var ws = store.createWriteStream(key)

function onFinish (err) {
if (err) return cb(err)

lockFile.unlock(LOCK_PATH, cb)
}

function onLock (err) {
if (err) return cb(err)

ws.on('error', cb)
ws.on('finish', onFinish)

ws.write(content)
ws.end()
}

lockFile.lock(LOCK_PATH, {}, onLock)

return ws
},

/**
* Writes content to a blob on a given path
* It does not lock
*
* @param {String} key
* @param {String} content
* @param {Function} cb
* @return {WritableStream}
*/
writeWithoutLock: function (key, content, cb) {
var ws = this.store.createWriteStream(key)

ws.on('error', cb)
ws.on('finish', cb)

ws.write(content)
ws.end()

return ws
}
}

module.exports = BlobStore
4 changes: 4 additions & 0 deletions src/adaptors/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
'fs-repo': require('./fs-repo'),
'memory-repo': require('./memory-repo')
}
74 changes: 74 additions & 0 deletions src/adaptors/memory-repo/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
var concat = require('concat-stream')
var ms = require('abstract-blob-store')

function BlobStore () {
this.store = ms()
}

BlobStore.prototype = {

/**
* Read a blob on a given path
*
* @param {String} key
* @param {Function} cb
* @return {ReadableStream}
*/
read: function (key, cb) {
var store = this.store
var rs = store.createReadStream(key)

function onFinish (buff) {
cb(null, buff.toString('utf8'))
}

rs.on('error', cb)
rs.pipe(concat(onFinish))

return rs
},

/**
* Read a blob on a given path
*
* @param {String} key
* @param {Function} cb
* @return {ReadableStream}
*/
readWithoutLock: function (key, cb) {
return this.read(key, cb)
},

/**
* Write the contents to the blob in the given path
*
* @param {String} key
* @param {Function} cb
* @return {WritableStream}
*/
write: function (key, content, cb) {
var store = this.store
var ws = store.createWriteStream(key)

ws.on('error', cb)
ws.on('finish', cb)

ws.write(content)
ws.end()

return ws
},

/**
* Write the contents to the blob in the given path
*
* @param {String} key
* @param {Function} cb
* @return {WritableStream}
*/
writeWithoutLock: function (key, cb) {
return this.write(key, cb)
}
}

module.exports = BlobStore
Loading

0 comments on commit e3dcf55

Please sign in to comment.