Skip to content

Commit

Permalink
feat(*): basic API
Browse files Browse the repository at this point in the history
  • Loading branch information
olalonde committed Sep 19, 2016
1 parent 8f7682d commit d348509
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ node_modules

# Temporary / data folders
.tmp
.data
data/

# Build directory
Expand Down
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ src/

# Test directory
test/
.data

.eslintrc
.babelrc
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Build Status](https://travis-ci.org/blockai/fs-tus-store.svg?branch=master)](https://travis-ci.org/blockai/fs-tus-store)

WIP
WIP.

## Install

Expand All @@ -14,4 +14,21 @@ Requires Node v6+

## Usage

See [./test](./test) directory for usage examples.
See [./test](./test) directory for usage examples.

All methods return promises.

### Creating client

```javascript
import initFsStore from 'tus-fs-store'
const store = initFsStore({ directory: './path/to/base/directory' })
```

### info(key)

Resolves to an `{ uploadOffset[, uploadLength, uploadMetadata] }` object.

### create(key[, { uploadLength, uploadMetadata }])

### write(key, readStream)
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@
"blue-tape": "^1.0.0",
"cz-conventional-changelog": "^1.2.0",
"eslint-config-blockai": "^1.0.1",
"mkdirp": "^0.5.1",
"nodemon": "^1.10.2",
"rimraf": "^2.5.4",
"semantic-release": "^4.3.5"
"semantic-release": "^4.3.5",
"string-to-stream": "^1.1.0"
},
"release": {
"debug": false,
Expand All @@ -51,5 +53,8 @@
"commitizen": {
"path": "cz-conventional-changelog"
}
},
"dependencies": {
"pump": "^1.0.1"
}
}
}
76 changes: 75 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,77 @@
export default () => {
import path from 'path'
import fs from 'fs'
import pump from 'pump'

// promisify
const readFile = (file) => new Promise((resolve, reject) => {
fs.readFile(file, (err, data) => {
if (err) return reject(err)
resolve(data)
})
})
const writeFile = (file, data) => new Promise((resolve, reject) => {
fs.writeFile(file, data, (err) => {
if (err) return reject(err)
resolve(data)
})
})
const stat = (file) => new Promise((resolve, reject) => {
fs.stat(file, (err, statObj) => {
if (err) return reject(err)
resolve(statObj)
})
})

export default ({
directory = '.fs-tus-store',
} = {}) => {
const absoluteDir = path.resolve(directory)
// Returns { uploadOffset[, uploadLength] }

// TODO: convert key to base64 or validate it?
const keyPath = (key) => path.join(absoluteDir, key)
const keyInfoPath = (key) => `${keyPath(key)}.info`

const getKeyInfo = (key) => readFile(keyInfoPath(key))
.then(data => JSON.parse(data))

const setKeyInfo = (key, infoObj) => Promise.resolve()
.then(() => JSON.stringify(infoObj))
.then(data => writeFile(keyInfoPath(key), data))

const getKeyOffset = (key) => stat(keyPath(key))
.then(({ size }) => size)

const touchKey = (key) => writeFile(keyPath(key), '')

// TODO: fail if key already exists?
const create = (key, { uploadLength, uploadMetadata } = {}) => (
setKeyInfo(key, { uploadLength, uploadMetadata })
.then(() => touchKey(key))
)

const info = key => getKeyInfo(key)
.then(infoObj => (
getKeyOffset(key)
.then((uploadOffset) => ({
...infoObj,
uploadOffset,
}))
))

const write = (key, rs) => new Promise((resolve, reject) => {
const ws = fs.createWriteStream(keyPath(key), {
flags: 'a', // append to file
})
pump(rs, ws, (err) => {
if (err) return reject(err)
resolve()
})
})

return {
info,
create,
write,
}
}
73 changes: 69 additions & 4 deletions test/index.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,72 @@
import test from 'blue-tape'
import init from '../src'
import rimraf from 'rimraf'
import mkdirp from 'mkdirp'
import str from 'string-to-stream'

test('todo', (t) => {
t.ok(!!init)
t.end()
import initFsStore from '../src'

const resetStore = () => {
const directory = `${__dirname}/.data`
rimraf.sync(directory)
mkdirp.sync(directory)
return initFsStore({ directory })
}

const store = resetStore()

test('info - unknown key', (t) => {
store
.info('unknown-key')
.catch((err) => {
t.ok(err instanceof Error)
t.end()
})
})

test('info - foo- unknown key', (t) => {
store
.info('foo')
.catch((err) => {
t.ok(err instanceof Error)
t.end()
})
})

test('create foo', () => (
store
.create('foo', { uploadLength: 'bar'.length })
))

test('info foo', (t) => (
store
.info('foo')
.then(({ uploadOffset, uploadLength }) => {
t.equal(uploadOffset, 0)
t.equal(uploadLength, 3)
})
))

test('write ba to foo', () => (
store
.write('foo', str('ba'))
))

test('info foo', (t) => (
store
.info('foo')
.then(({ uploadOffset, uploadLength }) => {
t.equal(uploadOffset, 2)
t.equal(uploadLength, 3)
})
))

test('write r to foo', () => store.write('foo', str('r')))

test('info foo', (t) => (
store
.info('foo')
.then(({ uploadOffset, uploadLength }) => {
t.equal(uploadOffset, 3)
t.equal(uploadLength, 3)
})
))

0 comments on commit d348509

Please sign in to comment.