ChromeChunkStore
| function ChromeChunkStore (chunkLength, opts) { | |
| var self = this | |
| if (!(self instanceof ChromeChunkStore)) return new ChromeChunkStore(chunkLength, opts) | |
| if (!opts) opts = {} | |
| if (opts.torrent && opts.torrent.infoHash) { | |
| self.path = opts.torrent.infoHash | |
| } | |
| self.opts = opts | |
| self.chunkLength = Number(chunkLength) | |
| if (!self.chunkLength) throw new Error('First argument must be a chunk length') | |
| self.closed = false | |
| self.length = Number(opts.length) || Infinity | |
| if (self.length !== Infinity) { | |
| self.lastChunkLength = (self.length % self.chunkLength) || self.chunkLength | |
| self.lastChunkIndex = Math.ceil(self.length / self.chunkLength) - 1 | |
| } | |
| if (opts.size == null) { | |
| opts.size = 10 * 1024 * 1024 * 1024 // 10GB | |
| } | |
| if (opts.type == null) { | |
| opts.type = 0 // temporary | |
| } | |
| navigator.webkitTemporaryStorage.requestQuota(opts.size, () => { | |
| webkitRequestFileSystem(opts.type, opts.size, fs => { | |
| self.fs = fs | |
| _setUp() | |
| }) | |
| }) | |
| function _setUp () { | |
| self.fileReader = new FileReader | |
| self.fs.root.getFile(self.opts.torrent.infoHash, {create: false}, fileEntry => { | |
| self.fileEntry = fileEntry | |
| self.fileEntry.file(file => self.file = file, err => console.log(err)) | |
| self.fileEntry.createWriter(fileWriter => self.fileWriter = fileWriter) | |
| }, err => console.log(err)) | |
| self.writeQueues = [] // limitation of FileWriter, single operation at a time | |
| self.readQueues = [] // limitation of FileReader | |
| } | |
| } | |
| ChromeChunkStore.prototype.put = function (index, buf, cb) { | |
| //console.log('call put') | |
| if (this.closed) return nextTick(cb, new Error('Storage is closed')) | |
| if (!this.fileWriter || !this.writeQueues || !this.file) { | |
| setTimeout(() => { | |
| nextTick(this.put(index, buf, cb)) | |
| }, 0) | |
| return | |
| //return nextTick(this.put(index, buf, cb)) // this work too fast, have to settle with setTimeout 0 | |
| } | |
| var isLastChunk = (index === this.lastChunkIndex) | |
| if (isLastChunk && buf.length !== this.lastChunkLength) { | |
| return nextTick(cb, new Error('Last chunk length must be ' + this.lastChunkLength)) | |
| } | |
| if (!isLastChunk && buf.length !== this.chunkLength) { | |
| return nextTick(cb, new Error('Chunk length must be ' + this.chunkLength)) | |
| } | |
| this.writeQueues.push({index: index, buf: buf, cb: cb}) | |
| this._put() | |
| } | |
| ChromeChunkStore.prototype._put = function () { | |
| //console.log('call _put') | |
| if (this.writeQueues.length == 0 || this.fileWriter.readyState == 1) { | |
| return | |
| } | |
| var chunkInfo = this.writeQueues.shift() | |
| this.fileWriter.onwriteend = () => { | |
| chunkInfo.cb() | |
| this._put() | |
| } | |
| this.fileWriter.seek(chunkInfo.index * this.chunkLength) | |
| this.fileWriter.write(new Blob([chunkInfo.buf])) | |
| } | |
| ChromeChunkStore.prototype.get = function (index, opts, cb) { | |
| //console.log('call get') | |
| if (typeof opts === 'function') return this.get(index, null, opts) | |
| if (this.closed) return nextTick(cb, new Error('Storage is closed')) | |
| if (!this.fileReader || !this.readQueues || !this.file) { | |
| setTimeout(() => { | |
| this.get(index, opts, cb) | |
| }, 0) | |
| return | |
| //return nextTick(this.get(index, opts, cb)) | |
| } | |
| if (opts == null) { | |
| opts = {} | |
| } | |
| if (!opts.offset) { | |
| opts.offset = 0 | |
| } | |
| if (!opts.length) { | |
| opts.length = 0 | |
| } | |
| this.readQueues.push({index: index, opts: opts, cb: cb}) | |
| this._get() | |
| } | |
| ChromeChunkStore.prototype._get = function () { | |
| //console.log('call _get') | |
| if (this.readQueues.length == 0 || this.fileReader.readyState == 1) { | |
| return | |
| } | |
| var chunkInfo = this.readQueues.shift() | |
| this.fileReader.onload = progressEvent => { | |
| if (!this.fileReader.result.byteLength) return nextTick(chunkInfo.cb, new Error('Chunk not found')) | |
| nextTick(chunkInfo.cb, null, this.fileReader.result) | |
| this._get() | |
| } | |
| var length = chunkInfo.opts.length ? chunkInfo.opts.length + this.chunkLength * chunkInfo.index : this.chunkLength * (chunkInfo.index + 1) | |
| this.fileReader.readAsArrayBuffer(this.file.slice( | |
| chunkInfo.index * this.chunkLength + chunkInfo.opts.offset, | |
| length | |
| )) | |
| } | |
| ChromeChunkStore.prototype.close = ChromeChunkStore.prototype.destroy = function (cb) { | |
| if (this.closed) return nextTick(cb, new Err('Storage is closed')) | |
| this.fileWriter.onwriteend = () => { | |
| cb() | |
| } | |
| this.fileWriter.truncate(()=>{}) | |
| this.closed = true | |
| } | |
| function nextTick(cb, err, val) { | |
| process.nextTick(function () { | |
| if (cb) cb(err, val) | |
| }) | |
| } | |
| module.exports = ChromeChunkStore |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
kocoten1992 commentedApr 20, 2017
update
navigator.webkitTemporaryStorage.requestQuota, silly me -_