Skip to content
This repository has been archived by the owner on Jul 14, 2019. It is now read-only.

Commit

Permalink
feat(fs): Initial implementation of fs backed store.
Browse files Browse the repository at this point in the history
All tests are passing. Also fixed a reference in the inmemory implementation.
  • Loading branch information
mikeal committed Jul 17, 2017
1 parent 37ada32 commit 1c78706
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 12 deletions.
103 changes: 92 additions & 11 deletions fs.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,108 @@
const fs = require('fs')
const path = require('path')
const once = require('once')
const util = require('util')
const createHasher = require('hashes-stream')

// cas: content addressable storage
// cass: content addressable storage spec

const isDirectory = dir => fs.statSync(dir).isDirectory()

class FileSystemContentAddressableStorage {
constructor (dir) {
if (!fs.isDirectorySync(dir)) throw new Error('Not a directory.')
constructor (dir, algo = 'sha256', _createHasher = createHasher) {
console.log(dir)
if (!isDirectory(dir)) throw new Error('Not a directory.')
this.dir = dir
this._algo = algo
this._createHasher = _createHasher
}
set (value, cb) {
if (Buffer.isBuffer(value)) {
return this._setBuffer(value, cb)
}
// TODO:
// create random token
// write to random token on fs
// get the hash
// move token file to file named that hash
if (typeof value === 'object' && value.readable) {
return this._setStream(value, cb)
}
process.nextTick(() => cb(new Error('value is a not a valid type')))
}
hash (value, cb) {
let hasher = this._createHasher(this._algo, cb)
if (Buffer.isBuffer(value)) {
hasher.write(value)
hasher.end()
return
}
if (typeof value === 'object' && value.readable) {
return value.pipe(hasher)
}
process.nextTick(() => cb(new Error('value is a not a valid type')))
}
_setBuffer (value, cb) {
this.hash(value, (err, hash) => {
if (err) return cb(err)
fs.writeFile(path.join(this.dir, hash), value, err => {
if (err) return cb(err)
cb(null, hash)
})
})
}
_setStream (value, cb) {
cb = once(cb)
let hash
let closed
let tmpfile = path.join(this.dir, '.' + Date.now() + Math.random())
let finish = () => {
fs.rename(tmpfile, path.join(this.dir, hash), err => {
if (err) return cb(err)
cb(null, hash)
})
}
let hasher = this._createHasher(this._algo, (err, _hash) => {
if (err) return cb(err)
hash = _hash
if (closed) finish()
})
let file = fs.createWriteStream(tmpfile)
file.on('error', cb)
file.on('close', () => {
closed = true
if (hash) finish()
})
value.pipe(file)
value.pipe(hasher)
}

// _setStream (value, cb) {
// cb = once(cb)
// let hash
// let hasher = util.promisify(this._createHasher)(this._algo)
// hasher.then(_hash => {
// console.log('hash', hash)
// hash = _hash
// fs.rename(tmpfile, path.join(this.dir, hash), err => {
// if (err) return cb(err)
// cb(null, hash)
// })
// })
// let tmpfile = path.join(this.dir, '.' + Date.now() + Math.random())
// let filepromise = new Promise((resolve, reject) => {
// let file = fs.createWriteStream(tmpfile)
// file.on('error', err => reject(err))
// file.on('close', () => resolve())
// value.pipe(file)
// })
// let all = Promise.all(hasher, filepromise)
// all.then(() => {
// fs.rename(tmpfile, path.join(this.dir, hash), err => {
// if (err) return cb(err)
// cb(null, hash)
// })
// })
// }
getBuffer (hash, cb) {
fs.readFile(path.join(this.dir, hash), cb)
}
}
getStream (hash, cb) {
return fs.createReadStream(path.join(this.dir, hash))
}
}

module.exports = (dir, algo, ch) => new FileSystemContentAddressableStorage(dir, algo, ch)
2 changes: 1 addition & 1 deletion inmemory.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class InMemoryContentAddressableStorage {

set (value, cb) {
let _value = bl()
let hasher = this._createHasher('sha256', (err, hash) => {
let hasher = this._createHasher(this._algo, (err, hash) => {
if (err) return cb(err)
this._store.set(hash, _value)
cb(null, hash)
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"cracks": "^3.1.2",
"cz-conventional-changelog": "^2.0.0",
"husky": "^0.14.3",
"rimraf": "^2.6.1",
"semantic-release": "^6.3.6",
"validate-commit-msg": "^2.12.2"
},
Expand Down
20 changes: 20 additions & 0 deletions tests/test-fs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const path = require('path')
const fs = require('fs')
const fsStore = require('../fs')
const testdir = fs.mkdtempSync(path.join(__dirname, '.testtmp-'))

require('../lib/test-basics')('fs', fsStore(testdir))

let test = require('tap').test
let rimraf = require('rimraf')

process.on('beforeExit', () => {
rimraf.sync(testdir)
})

// test('teardown', t => {
// t.plan(1)
// rimraf(testdir, err => {
// t.error(err)
// })
// })

0 comments on commit 1c78706

Please sign in to comment.