Skip to content

Commit e3dcf55

Browse files
committed
Merge pull request #2 from ipfs/masylum/initial-implementation
Bring @masylum PR and @diasdavid PR to be a PR from a ipfs/js-ipfs-repo branch to master
2 parents 8cb9452 + 8b68155 commit e3dcf55

File tree

46 files changed

+954
-4
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+954
-4
lines changed

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ coverage
1919
# node-waf configuration
2020
.lock-wscript
2121

22-
# Compiled binary addons (http://nodejs.org/api/addons.html)
23-
build/Release
22+
build
2423

2524
# Dependency directory
2625
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git

README.md

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,113 @@
1-
# js-ipfs-repo
2-
Implementation of the IPFS repo spec (https://github.com/ipfs/specs/tree/master/repo) in JavaScript
1+
js-ipfs-repo
2+
============
3+
4+
5+
[![](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)
6+
7+
> Implementation of the IPFS repo spec (https://github.com/ipfs/specs/tree/master/repo) in JavaScript
8+
9+
## API
10+
11+
### `Repo`
12+
13+
Constructor, accepts a path and options:
14+
15+
```js
16+
var Repo = require('js-ipfs-repo')
17+
var repo = new Repo('/Users/someone/.ipfs', {adaptor: 'fs'})
18+
```
19+
20+
Options:
21+
22+
- `adaptor`: String with the adaptor. Defaults to `fs`
23+
24+
### `#version`
25+
26+
Read/Write the version number of that repository.
27+
28+
```js
29+
repo.version().read(function (err, num) {
30+
console.log(err, num) // => 2
31+
})
32+
33+
repo.version().write(3, function (err) {
34+
console.log(err)
35+
})
36+
```
37+
38+
### `#api`
39+
40+
Read/Write the JSON configuration for that repository.
41+
42+
```js
43+
repo.api().read(function (err, multiaddr) {
44+
console.log(err, multiaddr)
45+
})
46+
47+
repo.api().write('/ip4/127.0.0.1/tcp/5001', function (err) {
48+
console.log(err)
49+
})
50+
```
51+
52+
### `#config`
53+
54+
Read/Write the JSON configuration for that repository.
55+
56+
```js
57+
repo.config().read(function (err, json) {
58+
console.log(err, json)
59+
})
60+
61+
repo.config().write({foo: 'bar'}, function (err) {
62+
console.log(err)
63+
})
64+
```
65+
66+
### `#blocks`
67+
68+
Store data on the block store.
69+
70+
```js
71+
repo.blocks().read('12200007d4e3a319cd8c7c9979280e150fc5dbaae1ce54e790f84ae5fd3c3c1a0475', function (buff, err) {
72+
console.log(err)
73+
})
74+
```
75+
76+
```js
77+
repo.blocks().write(buff, function (buff, err) {
78+
console.log(buff.toString('utf-8'), err)
79+
})
80+
```
81+
82+
### `#repo`
83+
84+
Read/Write the `repo.lock` file.
85+
86+
```js
87+
repo.repo().read(function (err, content) {
88+
console.log(err, content)
89+
})
90+
91+
repo.repo().write('foo', function (err) {
92+
console.log(err)
93+
})
94+
```
95+
96+
## Adaptors
97+
98+
By default it will use the `fs-repo` adaptor. Eventually we can write other adaptors
99+
and make those available on configuration.
100+
101+
### `fs-repo`
102+
103+
The default adaptor. Uses the `repo.lock` file to ensure there are no simultaneous reads
104+
nor writes. Uses the `fs-blob-store`.
105+
106+
### `memory-repo`
107+
108+
Ideal for testing purposes. Uses the `abstract-blob-store`.
109+
110+
## Tests
111+
112+
Not there yet! Should ran both in node and in Phantom with compatible
113+
adaptors.

package.json

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"name": "ipfs-repo",
3+
"version": "0.0.1",
4+
"description": "IPFS Repo implementation",
5+
"main": "src/index.js",
6+
"scripts": {
7+
"test": "mocha tests/*-test.js",
8+
"coverage": "istanbul cover --print both -- _mocha tests/*-test.js",
9+
"lint": "standard"
10+
},
11+
"repository": {
12+
"type": "git",
13+
"url": "https://github.com/diasdavid/js-ipfs-repo.git"
14+
},
15+
"keywords": [
16+
"IPFS"
17+
],
18+
"pre-commit": [
19+
"lint",
20+
"test"
21+
],
22+
"homepage": "https://github.com/ipfs/js-ipfs-record",
23+
"devDependencies": {
24+
"chai": "^3.4.1",
25+
"istanbul": "^0.4.1",
26+
"mocha": "^2.3.4",
27+
"ncp": "^2.0.0",
28+
"pre-commit": "^1.1.1",
29+
"rimraf": "^2.4.4",
30+
"standard": "^5.1.1"
31+
},
32+
"dependencies": {
33+
"abstract-blob-store": "^3.2.0",
34+
"concat-stream": "^1.5.1",
35+
"fs-blob-store": "^5.2.0",
36+
"level-js": "^2.2.2",
37+
"lockfile": "^1.0.1",
38+
"multihashes": "^0.2.0"
39+
}
40+
}

src/adaptors/fs-repo/index.js

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
var concat = require('concat-stream')
2+
var fs = require('fs-blob-store')
3+
var path = require('path')
4+
var lockFile = require('lockfile')
5+
6+
function BlobStore (base_path) {
7+
this.store = fs(base_path)
8+
this.LOCK_PATH = path.join(base_path, 'repo.lock')
9+
}
10+
11+
BlobStore.prototype = {
12+
13+
/**
14+
* Read a blob on a given path
15+
* It holds the repo.lock while reading
16+
*
17+
* @param {String} key
18+
* @param {Function} cb
19+
* @return {ReadableStream}
20+
*/
21+
read: function (key, cb) {
22+
var store = this.store
23+
var LOCK_PATH = this.LOCK_PATH
24+
var rs = store.createReadStream(key)
25+
26+
function onFinish (buff) {
27+
lockFile.unlock(LOCK_PATH, function (err) {
28+
if (err) return cb(err)
29+
30+
cb(null, buff.toString('utf8'))
31+
})
32+
}
33+
34+
function onLock (err) {
35+
if (err) return cb(err)
36+
37+
rs.on('error', cb)
38+
rs.pipe(concat(onFinish))
39+
}
40+
41+
lockFile.lock(LOCK_PATH, {}, onLock)
42+
43+
return rs
44+
},
45+
46+
/**
47+
* Read a blob on a given path
48+
* It does not lock
49+
*
50+
* @param {String} key
51+
* @param {Function} cb
52+
* @return {ReadableStream}
53+
*/
54+
readWithoutLock: function (key, cb) {
55+
var rs = this.store.createReadStream(key)
56+
57+
rs.on('error', cb)
58+
rs.pipe(concat(function (buff) {
59+
cb(null, buff.toString('utf8'))
60+
}))
61+
62+
return rs
63+
},
64+
65+
/**
66+
* Write the contents to the blob in the given path
67+
* It holds the repo.lock while reading
68+
*
69+
* @param {String} key
70+
* @param {Function} cb
71+
* @return {WritableStream}
72+
*/
73+
write: function (key, content, cb) {
74+
var store = this.store
75+
var LOCK_PATH = this.LOCK_PATH
76+
var ws = store.createWriteStream(key)
77+
78+
function onFinish (err) {
79+
if (err) return cb(err)
80+
81+
lockFile.unlock(LOCK_PATH, cb)
82+
}
83+
84+
function onLock (err) {
85+
if (err) return cb(err)
86+
87+
ws.on('error', cb)
88+
ws.on('finish', onFinish)
89+
90+
ws.write(content)
91+
ws.end()
92+
}
93+
94+
lockFile.lock(LOCK_PATH, {}, onLock)
95+
96+
return ws
97+
},
98+
99+
/**
100+
* Writes content to a blob on a given path
101+
* It does not lock
102+
*
103+
* @param {String} key
104+
* @param {String} content
105+
* @param {Function} cb
106+
* @return {WritableStream}
107+
*/
108+
writeWithoutLock: function (key, content, cb) {
109+
var ws = this.store.createWriteStream(key)
110+
111+
ws.on('error', cb)
112+
ws.on('finish', cb)
113+
114+
ws.write(content)
115+
ws.end()
116+
117+
return ws
118+
}
119+
}
120+
121+
module.exports = BlobStore

src/adaptors/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
'fs-repo': require('./fs-repo'),
3+
'memory-repo': require('./memory-repo')
4+
}

src/adaptors/memory-repo/index.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
var concat = require('concat-stream')
2+
var ms = require('abstract-blob-store')
3+
4+
function BlobStore () {
5+
this.store = ms()
6+
}
7+
8+
BlobStore.prototype = {
9+
10+
/**
11+
* Read a blob on a given path
12+
*
13+
* @param {String} key
14+
* @param {Function} cb
15+
* @return {ReadableStream}
16+
*/
17+
read: function (key, cb) {
18+
var store = this.store
19+
var rs = store.createReadStream(key)
20+
21+
function onFinish (buff) {
22+
cb(null, buff.toString('utf8'))
23+
}
24+
25+
rs.on('error', cb)
26+
rs.pipe(concat(onFinish))
27+
28+
return rs
29+
},
30+
31+
/**
32+
* Read a blob on a given path
33+
*
34+
* @param {String} key
35+
* @param {Function} cb
36+
* @return {ReadableStream}
37+
*/
38+
readWithoutLock: function (key, cb) {
39+
return this.read(key, cb)
40+
},
41+
42+
/**
43+
* Write the contents to the blob in the given path
44+
*
45+
* @param {String} key
46+
* @param {Function} cb
47+
* @return {WritableStream}
48+
*/
49+
write: function (key, content, cb) {
50+
var store = this.store
51+
var ws = store.createWriteStream(key)
52+
53+
ws.on('error', cb)
54+
ws.on('finish', cb)
55+
56+
ws.write(content)
57+
ws.end()
58+
59+
return ws
60+
},
61+
62+
/**
63+
* Write the contents to the blob in the given path
64+
*
65+
* @param {String} key
66+
* @param {Function} cb
67+
* @return {WritableStream}
68+
*/
69+
writeWithoutLock: function (key, cb) {
70+
return this.write(key, cb)
71+
}
72+
}
73+
74+
module.exports = BlobStore

0 commit comments

Comments
 (0)