Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
language: node_js
node:
- lts/*
services: xvfb
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# random-access-chrome-file

[![Build Status](https://travis-ci.com/random-access-storage/random-access-chrome-file.svg?branch=master)](https://travis-ci.com/random-access-storage/random-access-chrome-file)
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)

A [random-access-storage](https://github.com/random-access-storage/random-access-storage) instance backed by the Chrome file system api

```
Expand Down
6 changes: 5 additions & 1 deletion bench.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ function benchRead () {
console.time('512mb read')
st.read(0, 65536, function onread (err, buf) {
if (err) throw err
if (offset >= 512 * 1024 * 1024) return console.timeEnd('512mb read')
if (offset >= 512 * 1024 * 1024) {
console.timeEnd('512mb read')
console.log('### EXIT')
return
}
st.read(offset += buf.length, 65536, onread)
})
}
Expand Down
57 changes: 57 additions & 0 deletions browser-runner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const puppeteer = require('puppeteer')
const budo = require('budo')
const tapFinished = require('tap-finished')
const { PassThrough, pipeline } = require('stream')

const args = process.argv.slice(2)

budo.cli(args, { live: false, watchGlob: '', stream: false }).on('connect', runTests)

async function runTests (ev) {
const results = new PassThrough()
let browser
let page

try {
browser = await puppeteer.launch()
page = await browser.newPage()
} catch (err) {
console.error(err)
shutdown(1)
}

page.on('error', async err => {
console.error(err)
shutdown(1)
})

page.on('pageerror', async err => {
console.error(err)
shutdown(1)
})

page.on('console', msg => {
msg = msg.text()
if (msg.includes('### EXIT')) {
shutdown()
} else {
results.push(`${msg}\n`)
}
})

pipeline(results, tapFinished(result => {
shutdown(result.ok ? 0 : 1)
}), () => {})

pipeline(results, process.stdout, () => {})

await page.goto(`http://localhost:${ev.port}`)

async function shutdown (code = 0) {
if (browser) {
await browser.close().catch(() => {})
}

process.exit(code)
}
}
97 changes: 75 additions & 22 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const ras = require('random-access-storage')
const mutexify = require('mutexify')

const TYPE = {type: 'octet/stream'}
const requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem
Expand Down Expand Up @@ -29,19 +30,20 @@ function createFile (name, opts) {

var fs = null
var entry = null
var file = null
var toDestroy = null
var readers = []
var writers = []

return ras({read, write, open, stat, close, destroy})

function read (req) {
const r = readers.pop() || new ReadRequest(readers, entry, mutex)
const r = readers.pop() || new ReadRequest(readers, entry, file, mutex)
r.run(req)
}

function write (req) {
const w = writers.pop() || new WriteRequest(writers, entry, mutex)
const w = writers.pop() || new WriteRequest(writers, entry, file, mutex)
w.run(req)
}

Expand All @@ -51,9 +53,10 @@ function createFile (name, opts) {
}

function stat (req) {
entry.file(file => {
file.get((err, file) => {
if (err) return req.callback(err)
req.callback(null, file)
}, err => req.callback(err))
})
}

function destroy (req) {
Expand All @@ -78,7 +81,11 @@ function createFile (name, opts) {
mkdirp(parentFolder(name), function () {
fs.root.getFile(name, {create: true}, function (e) {
entry = toDestroy = e
req.callback(null)
file = new EntryFile(entry)
file.get((err) => {
if (err) return onerror(err)
req.callback(null)
})
}, onerror)
})
}, onerror)
Expand Down Expand Up @@ -107,9 +114,10 @@ function parentFolder (path) {
return /^\w:$/.test(p) ? '' : p
}

function WriteRequest (pool, entry, mutex) {
function WriteRequest (pool, entry, file, mutex) {
this.pool = pool
this.entry = entry
this.file = file
this.mutex = mutex
this.writer = null
this.req = null
Expand All @@ -122,7 +130,8 @@ WriteRequest.prototype.makeWriter = function () {
this.entry.createWriter(function (writer) {
self.writer = writer

writer.onwriteend = function () {
writer.onwriteend = function (e) {
self.file.updateSize(e.currentTarget.length)
self.onwrite(null)
}

Expand Down Expand Up @@ -164,21 +173,21 @@ WriteRequest.prototype.lock = function () {
}

WriteRequest.prototype.run = function (req) {
this.entry.file(file => {
this.req = req
if (!this.writer || this.writer.length !== file.size) return this.makeWriter()
var file = this.file

const end = req.offset + req.size
if (end > file.size && !this.lock()) return
this.req = req
if (!this.writer || this.writer.length !== file.size) return this.makeWriter()

if (req.offset > this.writer.length) {
if (req.offset > file.size) return this.truncate()
return this.makeWriter()
}
const end = req.offset + req.size
if (end > file.size && !this.lock()) return

if (req.offset > this.writer.length) {
if (req.offset > file.size) return this.truncate()
return this.makeWriter()
}

this.writer.seek(req.offset)
this.writer.write(new Blob([req.data], TYPE))
}, err => req.callback(err))
this.writer.seek(req.offset)
this.writer.write(new Blob([req.data], TYPE))
}

function Mutex () {
Expand All @@ -202,9 +211,10 @@ Mutex.prototype.lock = function (req) {
return true
}

function ReadRequest (pool, entry, mutex) {
function ReadRequest (pool, entry, file, mutex) {
this.pool = pool
this.entry = entry
this.file = file
this.mutex = mutex
this.reader = new FileReader()
this.req = null
Expand Down Expand Up @@ -251,10 +261,53 @@ ReadRequest.prototype.onread = function (err, buf) {
}

ReadRequest.prototype.run = function (req) {
this.entry.file(file => {
this.file.get((err, file) => {
if (err) return req.callback(err)

const end = req.offset + req.size
this.req = req
if (end > file.size) return this.onread(new Error('Could not satisfy length'), null)
this.reader.readAsArrayBuffer(file.slice(req.offset, end))
}, err => req.callback(err))
})
}

class EntryFile {
constructor (entry) {
this._entry = entry
this._lock = mutexify()
this._file = null
this._size = 0
}

get locked () {
return this._lock.locked
}

get size () {
return this._size
}

updateSize (size) {
this._size = size
this._file = null
}

get (cb) {
if (this._file) {
cb(null, this._file)
return
}

this._lock(release => {
if (this._file) {
return release(cb, null, this._file)
}

this._entry.file(file => {
this._file = file
this._size = file.size
release(cb, null, file)
}, err => release(cb, err))
})
}
}
13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@
"description": "random-access-storage instance backed by the Chrome file system api.",
"main": "index.js",
"dependencies": {
"mutexify": "^1.3.0",
"random-access-storage": "^1.3.0"
},
"devDependencies": {
"standard": "^11.0.1"
"budo": "^11.6.3",
"puppeteer": "^3.0.2",
"random-access-test": "github:random-access-storage/random-access-test",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i didn't realise we had this! should we publish that to npm?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed the same. We should, I think is really helpful to test these modules.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

published

"standard": "^11.0.1",
"tap-finished": "0.0.1",
"tape": "^5.0.0"
},
"scripts": {
"test": "standard"
"test": "node browser-runner.js test.js",
"posttest": "npm run lint",
"lint": "standard",
"bench": "node browser-runner.js bench.js"
},
"repository": {
"type": "git",
Expand Down
10 changes: 10 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const test = require('random-access-test')
const racf = require('./')

const createStorage = (root) => (file, opts) => racf(`${root}/${file}`, opts)

const storage = createStorage('tests-' + Math.random())

test(function (name, options, callback) {
callback(storage(name, options))
}, {})