Initial commit

This commit is contained in:
Damjan Bursac 2019-05-10 22:39:02 +02:00
parent 5e90b7669f
commit f4bc8eda96
7 changed files with 4739 additions and 0 deletions

4
.zuul.yml Normal file
View File

@ -0,0 +1,4 @@
ui: tape
browsers:
- name: chrome
version: -1..latest

21
package.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "chunk-store",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"zuul-test": "zuul --local -- test/test.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"abstract-chunk-store": "^1.4.0",
"tape": "^4.9.1",
"zuul": "^3.12.0"
},
"devDependencies": {
"@types/node": "^12.0.0"
}
}

13
src/EventEmitter.ts Normal file
View File

@ -0,0 +1,13 @@
export default class EventEmitter {
private subscribers: Array<Function> = []
subscribe (subscriber) {
this.subscribers.push(subscriber)
}
notify () {
this.subscribers.forEach((subscriber) => {
subscriber()
})
}
}

169
src/Store.ts Normal file
View File

@ -0,0 +1,169 @@
import EventEmitter from './EventEmitter'
export default class Store {
public chunkLength: number;
private idb: any;
private db: IDBDatabase;
// Closed flag
private closed:boolean = false;
private eventEmitter: EventEmitter;
// Use to count number of store objects created. Determine database nome
private static storeCount: number = 0
private readonly currentStoreCount: number = 0
constructor (chunkLength: number) {
this.currentStoreCount = Store.storeCount
this.chunkLength = chunkLength;
this.eventEmitter = new EventEmitter();
// Open indexedDB (torrent_chunks) and
// create objectStore (torrent_chunk_store)
this.idb = window.indexedDB || {}; // || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
let request = this.idb.open(this.getDatabaseName(), 1);
Store.storeCount++
request.onerror = (event) => {
// Don't forget to handle errors!
}
request.onsuccess = (event: any) => {
this.db = event.target.result;
// EventEmmitter.emit('dbOpened')
this.eventEmitter.notify()
}
request.onupgradeneeded = (event: any) => {
// Save the IDBDatabase interface
this.db = event.target.result;
// Create an objectStore for this database
this.db.createObjectStore('torrent_chunk_store');
};
}
get (index: number, options, cb) {
let self = this
if (typeof options === 'function') {
return this.get(index, null, options)
}
if (!cb) {
cb = () => {}
}
if (!this.db) {
// Execute listener
this.eventEmitter.subscribe(_get.bind(this, index))
} else {
return _get(index)
}
function _get (index) {
// return new Promise(function (resolve, reject) {
let transaction = self.db.transaction('torrent_chunk_store', 'readonly');
let request = transaction.objectStore('torrent_chunk_store').get(index);
transaction.onerror = (event) => {
// Don't forget to handle errors!
}
request.onsuccess = (event) => {
// resolve(event.target)
let target = <IDBRequest> event.target
if (target.result === undefined) {
// cb(null, new Buffer(0))
this.nextTick(cb, new Error('Try to access non existen index'))
} else {
const buffer = new Buffer(target.result);
if (!options) {
return self.nextTick(cb, null, buffer)
}
const offset = options.offset || 0
const length = options.length || (target.result.length - offset)
cb(null, buffer.slice(offset, offset + length))
}
}
// })
}
}
put (index: number, chunkBuffer: Buffer, cb: Function) {
let self = this
if (!cb) {
cb = () => {}
}
if (chunkBuffer.length !== this.chunkLength) {
return this.nextTick(cb, new Error('Chunk length must be: ' + this.chunkLength))
}
if (!this.db) {
// Execute listener
this.eventEmitter.subscribe(_put.bind(this, index, chunkBuffer))
} else {
_put()
}
function _put () {
let transaction = self.db.transaction('torrent_chunk_store', 'readwrite')
transaction.onerror = (event) => {
// Don't forget to handle errors!
}
let request = transaction.objectStore('torrent_chunk_store').put(chunkBuffer, index)
request.onsuccess = (event) => {
cb(null, event)
}
request.onerror = (err) => {
cb(err)
}
}
}
close (cb) {
if (this.closed) return this.nextTick(cb, new Error('Storage is closed'));
if (!this.db) return this.nextTick(cb, undefined)
this.closed = true;
this.nextTick(cb, null, null);
}
destroy (cb) {
// Currently same implementation as close
// For indexeddb would be different:
// -- Close would empty database
// -- Destroy should delete database
this.close(cb)
this.idb.deleteDatabase(this.getDatabaseName())
}
nextTick (cb, err, val?) {
setTimeout(function () {
if (cb) cb(err, val)
}, 0)
}
/**
* Get database name based on storeCount
*/
private getDatabaseName () {
const databaseName = 'torrent_chunks'
if (this.currentStoreCount === 0) {
return databaseName
}
return databaseName + '_' + this.currentStoreCount
}
}

8
test/test.js Normal file
View File

@ -0,0 +1,8 @@
var tests = require('abstract-chunk-store/tests')
var tape = require('tape')
var StoreLib = require('../dist/Store.js')
var Store = StoreLib.default
tests(tape, Store)

20
tsconfig.json Normal file
View File

@ -0,0 +1,20 @@
{
"compilerOptions": {
// this aligns with Vue's browser support
"target": "es5",
"lib": ["es2015", "dom"],
// this enables stricter inference for data properties on `this`
"strict": false,
// if using webpack 2+ or rollup, to leverage tree shaking:
"module": "commonjs",
"moduleResolution": "node",
"outDir": "dist"
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}

4504
yarn.lock Normal file

File diff suppressed because it is too large Load Diff