caslet
Version:
A simple content addressable system
122 lines (119 loc) • 3.42 kB
text/coffeescript
loglet = require 'loglet'
fs = require 'fs'
path = require 'path'
crypto = require 'crypto'
uuid = require 'node-uuid'
funclet = require 'funclet'
filelet = require 'filelet'
_ = require 'underscore'
class FSCas
: (options, cb) ->
defaultOpts =
baseDir: path.join process.env.HOME, '.caslet'
options = _.extend {}, defaultOpts, options
cas = new @ options
cas.initialize cb
constructor: () ->
= path.join .baseDir, 'paths'
= path.join .baseDir, 'contents'
= path.join .baseDir, 'temp' # for moving the files...
= {}
initialize: (cb) ->
funclet
.each [ , , ], (dirPath, next) ->
filelet.mkdirp dirPath, next
.catch(cb)
.done () => cb null, @
get: (option, cb) ->
if option.path
option.path, cb
else if option.hash
option.hash, cb
else
cb {error: 'invalid_argument', args: [ option ]}
_getViaPath: (pathsPath, cb) ->
if .hasOwnProperty(pathsPath)
[pathsPath].hash, cb
else
funclet
.start (next) =>
normalized = pathsPath
fs.readFile normalized, 'utf8', next
.catch(cb)
.done (data) =>
parsed = JSON.parse data
[pathsPath] = parsed
parsed.hash, cb
_getViaHash: (hash, cb) ->
try
hashPath = hash
stream = fs.createReadStream hashPath
cb null, stream
catch e
cb e
store: (instream, cb) ->
try
tempFilePath =
digest = crypto.createHash 'sha1'
digest.setEncoding 'hex'
outstream = fs.createWriteStream tempFilePath
instream.once 'close', () =>
try
digest.end()
outstream.end()
hash = digest.read()
instream.close()
outstream.close()
tempFilePath, hash, cb
catch e
cb e
instream.once 'error', cb
outstream.once 'error', cb
digest.once 'error', cb
instream.pipe digest
instream.pipe outstream
catch e
instream.close()
outstream.close()
cb e
storeWithPath: (instream, destPath, cb) ->
hash = null
funclet
.start (next) =>
instream, next
.then (val, next) =>
hash = val
hash, destPath, next
.catch(cb)
.done () ->
cb null, hash
_storePathMapping: (hash, destPath, cb) ->
normalizedPath =
result =
type: 'fs'
hash: hash
filelet.writeFile normalizedPath, JSON.stringify(result, null, 2), 'utf8', (err) =>
if err
cb err
else
[destPath] = result
cb null
_moveTempFile: (tempFilePath, hash, cb) ->
try
hashPath = hash
filelet.move tempFilePath, hashPath, (err) ->
if err
cb err
else
cb null, hash
catch e
cb e
_tempFilePath: () ->
path.join , uuid.v4()
_pathsFilePath: (filePath) ->
path.join , filePath
_hashFilePath: (hash) ->
parentDir = hash.substring(0, 3)
fileName = hash.substring(3)
path.join , parentDir, fileName
module.exports = FSCas