Skip to content

Commit 8a3bc81

Browse files
committed
impl + partial tests, next: more tests
1 parent 056beac commit 8a3bc81

File tree

5 files changed

+167
-1
lines changed

5 files changed

+167
-1
lines changed

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "JavaScript implementation of IPFS' unixfs (a Unix FileSystem representation on top of a MerkleDAG)",
55
"main": "src/index.js",
66
"scripts": {
7-
"test": "mocha tests/*-test.js"
7+
"test": "mocha tests/test-*.js"
88
},
99
"repository": {
1010
"type": "git",
@@ -24,5 +24,8 @@
2424
"mocha": "^2.4.5",
2525
"pre-commit": "^1.1.2",
2626
"standard": "^6.0.4"
27+
},
28+
"dependencies": {
29+
"protocol-buffers": "^3.1.5"
2730
}
2831
}

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exports.format = require('./unixfs-format.js')

src/unixfs-format.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
const fs = require('fs')
2+
const path = require('path')
3+
const protobuf = require('protocol-buffers')
4+
const schema = fs.readFileSync(path.resolve(__dirname, 'unixfs.proto'))
5+
const pb = protobuf(schema)
6+
const unixfsData = pb.Data // encode/decode
7+
// const unixfsMetadata = pb.MetaData // encode/decode
8+
9+
const types = [
10+
'raw',
11+
'directory',
12+
'file',
13+
'metadata',
14+
'symlink'
15+
]
16+
17+
exports = module.exports = Data
18+
19+
function Data (type, data) {
20+
if (!(this instanceof Data)) {
21+
return new Data(type, data)
22+
}
23+
if (types.indexOf(type) === -1) {
24+
throw new Error('Type: ' + type + ' is not valid')
25+
}
26+
27+
this.type = type
28+
this.data = data
29+
this.blockSizes = []
30+
31+
this.addBlockSize = (size) => {
32+
this.blockSizes.push(size)
33+
}
34+
35+
this.removeBlockSize = (index) => {
36+
this.blockSizes.splice(index, 1)
37+
}
38+
39+
// data.length + blockSizes
40+
this.fileSize = () => {
41+
var sum = 0
42+
this.blockSizes.forEach((size) => {
43+
sum += size
44+
})
45+
if (data) {
46+
sum += data.length
47+
}
48+
return sum
49+
}
50+
51+
// encode to protobuf
52+
this.marshal = () => {
53+
var type
54+
55+
switch (this.type) {
56+
case 'raw': type = unixfsData.DataType.Raw; break
57+
case 'directory': type = unixfsData.DataType.Directory; break
58+
case 'file': type = unixfsData.DataType.File; break
59+
case 'metadata': type = unixfsData.DataType.Metadata; break
60+
case 'symlink': type = unixfsData.DataType.Symlink; break
61+
}
62+
63+
return unixfsData.encode({
64+
Type: type,
65+
Data: this.data,
66+
filesize: this.fileSize(),
67+
blocksizes: this.blockSizes
68+
})
69+
}
70+
}
71+
72+
// decode from protobuf https://github.com/ipfs/go-ipfs/blob/master/unixfs/format.go#L24
73+
exports.unmarshal = (marsheled) => {
74+
const decoded = unixfsData.decode(marsheled)
75+
if (!decoded.Data) {
76+
decoded.Data = undefined
77+
}
78+
const obj = new Data(types[decoded.Type], decoded.Data)
79+
obj.blockSizes = decoded.blocksizes
80+
return obj
81+
}

src/unixfs.proto

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
message Data {
2+
enum DataType {
3+
Raw = 0;
4+
Directory = 1;
5+
File = 2;
6+
Metadata = 3;
7+
Symlink = 4;
8+
}
9+
10+
required DataType Type = 1;
11+
optional bytes Data = 2;
12+
optional uint64 filesize = 3;
13+
repeated uint64 blocksizes = 4;
14+
}
15+
16+
message Metadata {
17+
required string MimeType = 1;
18+
}

tests/test-unixfs-format.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/* globals describe, it */
2+
3+
const expect = require('chai').expect
4+
5+
const UnixfsFormat = require('../src').format
6+
7+
describe('unixfs-format', () => {
8+
it('raw', (done) => {
9+
const data = new UnixfsFormat('raw', new Buffer('bananas'))
10+
const marsheled = data.marshal()
11+
const unmarsheled = UnixfsFormat.unmarshal(marsheled)
12+
expect(data.type).to.equal(unmarsheled.type)
13+
expect(data.data).to.deep.equal(unmarsheled.data)
14+
expect(data.blockSizes).to.deep.equal(unmarsheled.blockSizes)
15+
expect(data.fileSize()).to.deep.equal(unmarsheled.fileSize())
16+
done()
17+
})
18+
19+
it('directory', (done) => {
20+
const data = new UnixfsFormat('directory')
21+
const marsheled = data.marshal()
22+
const unmarsheled = UnixfsFormat.unmarshal(marsheled)
23+
expect(data.type).to.equal(unmarsheled.type)
24+
expect(data.data).to.deep.equal(unmarsheled.data)
25+
expect(data.blockSizes).to.deep.equal(unmarsheled.blockSizes)
26+
expect(data.fileSize()).to.deep.equal(unmarsheled.fileSize())
27+
done()
28+
})
29+
30+
it('file', (done) => {
31+
const data = new UnixfsFormat('file', new Buffer('batata'))
32+
const marsheled = data.marshal()
33+
const unmarsheled = UnixfsFormat.unmarshal(marsheled)
34+
expect(data.type).to.equal(unmarsheled.type)
35+
expect(data.data).to.deep.equal(unmarsheled.data)
36+
expect(data.blockSizes).to.deep.equal(unmarsheled.blockSizes)
37+
expect(data.fileSize()).to.deep.equal(unmarsheled.fileSize())
38+
done()
39+
})
40+
41+
it.skip('file add blocksize', (done) => {})
42+
it.skip('file add and remove blocksize', (done) => {})
43+
it.skip('metadata', (done) => {})
44+
it.skip('symlink', (done) => {})
45+
it('wrong type', (done) => {
46+
var data
47+
try {
48+
data = new UnixfsFormat('bananas')
49+
} catch (err) {
50+
expect(err).to.exist
51+
expect(data).to.not.exist
52+
done()
53+
}
54+
})
55+
56+
describe('interop', () => {
57+
it.skip('raw', (done) => {})
58+
it.skip('directory', (done) => {})
59+
it.skip('file', (done) => {})
60+
it.skip('metadata', (done) => {})
61+
it.skip('symlink', (done) => {})
62+
})
63+
})

0 commit comments

Comments
 (0)