diff --git a/.gitignore b/.gitignore
index 5148e52..907c78a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,6 @@
# Logs
logs
*.log
-npm-debug.log*
# Runtime data
pids
@@ -14,9 +13,6 @@ lib-cov
# Coverage directory used by tools like istanbul
coverage
-# nyc test coverage
-.nyc_output
-
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
@@ -26,12 +22,8 @@ coverage
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
-# Dependency directories
+# Dependency directory
+# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
-jspm_packages
-
-# Optional npm cache directory
-.npm
-# Optional REPL history
-.node_repl_history
+dist
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..59a480e
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,29 @@
+# Logs
+logs
+*.log
+
+# Runtime data
+pids
+*.pid
+*.seed
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directory
+# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
+node_modules
+
+test
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..4fe6550
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,36 @@
+sudo: false
+language: node_js
+matrix:
+ include:
+ - node_js: 4
+ env: CXX=g++-4.8
+ - node_js: 6
+ env:
+ - SAUCE=true
+ - CXX=g++-4.8
+ - node_js: stable
+ env: CXX=g++-4.8
+
+# Make sure we have new NPM.
+before_install:
+ - npm install -g npm
+
+script:
+ - npm run lint
+ - npm test
+ - npm run coverage
+
+before_script:
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
+
+after_success:
+ - npm run coverage-publish
+
+addons:
+ firefox: 'latest'
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - g++-4.8
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index a664bae..4cc0133 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
-MIT License
+The MIT License (MIT)
-Copyright (c) 2017 IPLD
+Copyright (c) 2017 David Dias
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -19,3 +19,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+
diff --git a/README.md b/README.md
index 35aa600..deb224b 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,86 @@
# js-ipld-torrent
-JavaScript implementation of the Torrent IPLD format
+
+[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
+[![](https://img.shields.io/badge/project-IPLD-blue.svg?style=flat-square)](http://github.com/ipld/ipld)
+[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
+[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
+[![Coverage Status](https://coveralls.io/repos/github/ipld/js-ipld-torrent/badge.svg?branch=master)](https://coveralls.io/github/ipld/js-ipld-dag-cbor?branch=master)
+[![Travis CI](https://travis-ci.org/ipld/js-ipld-torrent.svg?branch=master)](https://travis-ci.org/ipld/js-ipld-dag-cbor)
+[![Circle CI](https://circleci.com/gh/ipld/js-ipld-torrent.svg?style=svg)](https://circleci.com/gh/ipld/js-ipld-dag-cbor)
+[![Dependency Status](https://david-dm.org/ipld/js-ipld-torrent.svg?style=flat-square)](https://david-dm.org/ipld/js-ipld-dag-cbor) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)
+![](https://img.shields.io/badge/npm-%3E%3D3.0.0-orange.svg?style=flat-square)
+![](https://img.shields.io/badge/Node.js-%3E%3D4.0.0-orange.svg?style=flat-square)
+
+[![Sauce Test Status](https://saucelabs.com/browser-matrix/ipld-js-torrent.svg)](https://saucelabs.com/u/ipld-js-dag-cbor)
+
+> JavaScript implementation of the [IPLD spec](https://github.com/ipfs/specs/tree/master/ipld).
+
+## Table of Contents
+
+- [Install](#install)
+ - [npm](#npm)
+ - [Use in Node.js](#use-in-nodejs)
+ - [Use in a browser with browserify, webpack or any other bundler](#use-in-a-browser-with-browserify-webpack-or-any-other-bundler)
+ - [Use in a browser Using a script tag](#use-in-a-browser-using-a-script-tag)
+- [Usage](#usage)
+- [Maintainers](#maintainers)
+- [Contribute](#contribute)
+- [License](#license)
+
+## Install
+
+### npm
+
+```sh
+> npm install ipld-torrent
+```
+
+### Use in Node.js
+
+```JavaScript
+const torrent = require('ipld-torrent')
+```
+
+### Use in a browser with browserify, webpack or any other bundler
+
+The code published to npm that gets loaded on require is in fact a ES5 transpiled version with the right shims added. This means that you can require it and use with your favourite bundler without having to adjust asset management process.
+
+```JavaScript
+const torrent = require('ipld-torrent')
+```
+
+### Use in a browser Using a script tag
+
+Loading this module through a script tag will make the `IpldTorrent` obj available in the global namespace.
+
+```html
+
+
+
+```
+
+## Usage
+
+```JavaScript
+const torrent = require('ipld-torrent')
+```
+
+## BitTorrent Documentation
+
+- [File Structure](https://wiki.theory.org/BitTorrentSpecification#Metainfo_File_Structure)
+
+## Maintainers
+
+[@diasdavid](https://github.com/diasdavid)
+
+## Contribute
+
+Feel free to join in. All welcome. Open an [issue](https://github.com/ipld/js-ipld-torrent/issues)!
+
+Check out our [contributing document](https://github.com/ipld/ipld/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to IPLD are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
+
+Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
+
+## License
+
+[MIT](LICENSE) © 2017 David Dias
diff --git a/circle.yml b/circle.yml
new file mode 100644
index 0000000..434211a
--- /dev/null
+++ b/circle.yml
@@ -0,0 +1,12 @@
+machine:
+ node:
+ version: stable
+
+dependencies:
+ pre:
+ - google-chrome --version
+ - wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
+ - sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
+ - sudo apt-get update
+ - sudo apt-get --only-upgrade install google-chrome-stable
+ - google-chrome --version
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..2fb9bd7
--- /dev/null
+++ b/package.json
@@ -0,0 +1,55 @@
+{
+ "name": "ipld-torrent",
+ "version": "0.0.0",
+ "description": "",
+ "main": "src/index.js",
+ "scripts": {
+ "test": "aegir-test",
+ "test:browser": "aegir-test --env browser",
+ "test:node": "aegir-test --env node",
+ "lint": "aegir-lint",
+ "release": "aegir-release",
+ "release-minor": "aegir-release --type minor",
+ "release-major": "aegir-release --type major",
+ "build": "aegir-build",
+ "coverage": "aegir-coverage",
+ "coverage-publish": "aegir-coverage publish"
+ },
+ "pre-commit": [
+ "lint",
+ "test"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/ipld/js-ipld-torrent.git"
+ },
+ "keywords": [
+ "IPFS"
+ ],
+ "author": "David Dias ",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/ipld/js-ipld-torrent/issues"
+ },
+ "engines": {
+ "node": ">=4.0.0",
+ "npm": ">=3.0.0"
+ },
+ "homepage": "https://github.com/ipld/js-ipld-torrent",
+ "dependencies": {
+ "async": "^2.1.5",
+ "bencode": "^0.11.0",
+ "cids": "^0.4.1",
+ "multihashing-async": "^0.4.3",
+ "parse-torrent-file": "^4.0.1",
+ "traverse": "^0.6.6"
+ },
+ "devDependencies": {
+ "aegir": "^10.0.0",
+ "chai": "^3.5.0",
+ "ipfs-block": "^0.5.5"
+ },
+ "contributors": [
+ "David Dias "
+ ]
+}
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 0000000..adc8a1b
--- /dev/null
+++ b/src/index.js
@@ -0,0 +1,4 @@
+'use strict'
+
+exports.util = require('./util.js')
+exports.resolver = require('./resolver.js')
diff --git a/src/resolver.js b/src/resolver.js
new file mode 100644
index 0000000..116b76c
--- /dev/null
+++ b/src/resolver.js
@@ -0,0 +1,51 @@
+'use strict'
+
+const util = require('./util')
+const setImmediate = require('async/setImmediate')
+const traverse = require('traverse')
+
+exports = module.exports
+
+exports.multicodec = 'torrent-file'
+
+exports.resolve = (block, path, callback) => {
+ if (typeof path === 'function') {
+ callback = path
+ path = undefined
+ }
+
+ util.deserialize(block.data, (err, node) => {
+ if (err) {
+ return callback(err)
+ }
+
+ // root
+ if (!path || path === '/') {
+ return callback(null, {
+ value: node,
+ remainderPath: ''
+ })
+ }
+
+ const parts = path.split('/')
+ const val = traverse(node).get(parts)
+
+ console.log(node)
+
+ if (val) {
+ // TODO if it is a link to a piece, return a CID of a raw block
+ return callback(null, {
+ value: val,
+ remainderPath: ''
+ })
+ }
+
+ // out of scope
+ // TODO
+ })
+}
+
+// TODO implement when needed
+exports.tree = (block, options, callback) => {
+ setImmediate(() => callback(new Error('not implemented')))
+}
diff --git a/src/util.js b/src/util.js
new file mode 100644
index 0000000..0fbb9c2
--- /dev/null
+++ b/src/util.js
@@ -0,0 +1,40 @@
+'use strict'
+
+const parseTorrentFile = require('parse-torrent-file')
+// const bencode = require('bencode')
+const resolver = require('./resolver')
+const waterfall = require('async/waterfall')
+const multihashing = require('multihashing-async')
+const CID = require('cids')
+
+exports = module.exports
+
+exports.serialize = (dagNode, callback) => {
+ let serialized
+ try {
+ serialized = parseTorrentFile.encode(dagNode)
+ } catch (err) {
+ return callback(err)
+ }
+ callback(null, serialized)
+}
+
+exports.deserialize = (data, callback) => {
+ let node
+ try {
+ node = parseTorrentFile(data)
+ } catch (err) {
+ return callback(err)
+ }
+ callback(null, node)
+}
+
+exports.cid = (dagNode, callback) => {
+ waterfall([
+ (cb) => exports.serialize(dagNode, cb),
+ (serialized, cb) => {
+ multihashing(serialized, 'sha2-256', cb)
+ },
+ (mh, cb) => cb(null, new CID(1, resolver.multicodec, mh))
+ ], callback)
+}
diff --git a/test/.DS_Store b/test/.DS_Store
new file mode 100644
index 0000000..1a71cb0
Binary files /dev/null and b/test/.DS_Store differ
diff --git a/test/fixtures/bitlove-intro.torrent b/test/fixtures/bitlove-intro.torrent
new file mode 100644
index 0000000..1c91bf1
Binary files /dev/null and b/test/fixtures/bitlove-intro.torrent differ
diff --git a/test/fixtures/leaves-duplicate-tracker.torrent b/test/fixtures/leaves-duplicate-tracker.torrent
new file mode 100644
index 0000000..b60d587
Binary files /dev/null and b/test/fixtures/leaves-duplicate-tracker.torrent differ
diff --git a/test/fixtures/leaves-empty-announce-list.torrent b/test/fixtures/leaves-empty-announce-list.torrent
new file mode 100644
index 0000000..8b500d4
Binary files /dev/null and b/test/fixtures/leaves-empty-announce-list.torrent differ
diff --git a/test/fixtures/leaves-empty-url-list.torrent b/test/fixtures/leaves-empty-url-list.torrent
new file mode 100644
index 0000000..30f6bdf
Binary files /dev/null and b/test/fixtures/leaves-empty-url-list.torrent differ
diff --git a/test/fixtures/leaves-url-list.torrent b/test/fixtures/leaves-url-list.torrent
new file mode 100644
index 0000000..6f06e9a
Binary files /dev/null and b/test/fixtures/leaves-url-list.torrent differ
diff --git a/test/resolver.spec.js b/test/resolver.spec.js
new file mode 100644
index 0000000..dad8529
--- /dev/null
+++ b/test/resolver.spec.js
@@ -0,0 +1,53 @@
+/* eslint max-nested-callbacks: ["error", 8] */
+/* eslint-env mocha */
+'use strict'
+
+const expect = require('chai').expect
+const torrent = require('../src')
+const resolver = torrent.resolver
+const Block = require('ipfs-block')
+const loadFixture = require('aegir/fixtures')
+
+const bitloveIntro = loadFixture(__dirname, '/fixtures/bitlove-intro.torrent')
+
+describe('IPLD format resolver (local)', () => {
+ let block
+ let node
+
+ before((done) => {
+ block = new Block(bitloveIntro)
+ torrent.util.deserialize(bitloveIntro, (err, _node) => {
+ expect(err).to.not.exist
+ node = _node
+ done()
+ })
+ })
+
+ it('multicodec is torrent-file', () => {
+ expect(resolver.multicodec).to.equal('torrent-file')
+ })
+
+ describe('.resolve', () => {
+ it('root', (done) => {
+ resolver.resolve(block, '/', (err, result) => {
+ expect(err).to.not.exist
+ expect(result.value).to.eql(node)
+ done()
+ })
+ })
+
+ it.skip('path within scope that is not a link', (done) => {
+ resolver.resolve(block, '/createdBy', (err, result) => {
+ expect(err).to.not.exist
+ expect(result.value).to.eql('')
+ done()
+ })
+ })
+
+ it.skip('path within scope that is a link', (done) => {})
+
+ it.skip('path out of scope', (done) => {})
+ })
+
+ describe('.tree', () => {})
+})
diff --git a/test/util.spec.js b/test/util.spec.js
new file mode 100644
index 0000000..f21a5c2
--- /dev/null
+++ b/test/util.spec.js
@@ -0,0 +1,43 @@
+/* eslint-env mocha */
+'use strict'
+
+const expect = require('chai').expect
+const loadFixture = require('aegir/fixtures')
+const torrent = require('../src')
+
+const bitloveIntro = loadFixture(__dirname, '/fixtures/bitlove-intro.torrent')
+
+describe('util', () => {
+ it('.deserialize', (done) => {
+ torrent.util.deserialize(bitloveIntro, (err, node) => {
+ expect(err).to.not.exist
+ // console.log(JSON.stringify(node, '', 2))
+ done()
+ })
+ })
+
+ it('.serialize', (done) => {
+ torrent.util.deserialize(bitloveIntro, (err, node) => {
+ expect(err).to.not.exist
+ torrent.util.serialize(node, (err, torrentFile) => {
+ expect(err).to.not.exist
+ // Not canonical until https://github.com/feross/parse-torrent-file/pull/15
+ // expect(bitloveIntro).to.eql(torrentFile)
+ done()
+ })
+ })
+ })
+
+ it('.cid', (done) => {
+ torrent.util.deserialize(bitloveIntro, (err, node) => {
+ expect(err).to.not.exist
+ torrent.util.cid(node, (err, cid) => {
+ expect(err).to.not.exist
+ const cidStr = cid.toBaseEncodedString()
+ expect(cidStr)
+ .to.equal('zevZRbu3w14eudURWPXsP78tQ1i6Mqq5zCQmZhv6sBDCsrhUF')
+ done()
+ })
+ })
+ })
+})