├── .gitignore ├── demo-worker.js ├── demo.html ├── demo.js ├── index.js ├── one-filler.js ├── package.json ├── parent.js ├── readme.md └── test ├── ps-loopback-worker.js └── ps.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /demo-worker.js: -------------------------------------------------------------------------------- 1 | var oneFiller = require('./one-filler') 2 | 3 | self.onmessage = function(event) { 4 | var ab = event.data 5 | ab = oneFiller(ab) 6 | self.postMessage(ab, [ab]) 7 | } 8 | 9 | -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DOMNode WebWorker 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /demo.js: -------------------------------------------------------------------------------- 1 | var workerstream = require('./index') 2 | 3 | var worker = workerstream('demo-worker.js') 4 | 5 | worker.on('data', function(data) { 6 | console.log(new Uint8Array(data)) 7 | }) 8 | 9 | var ab = new ArrayBuffer( 10 ) 10 | worker.write( ab ) 11 | worker.end() -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var stream = require('stream') 2 | var inherits = require('inherits'); 3 | 4 | function WorkerStream(path) { 5 | stream.Stream.call(this) 6 | this.readable = true 7 | this.writable = true 8 | this.worker = typeof path === 'string' 9 | ? new Worker(path) 10 | : path 11 | this.worker.onmessage = this.workerMessage.bind(this) 12 | this.worker.onerror = this.workerError.bind(this) 13 | } 14 | 15 | inherits(WorkerStream, stream.Stream) 16 | 17 | module.exports = function(path) { 18 | return new WorkerStream(path) 19 | } 20 | 21 | module.exports.WorkerStream = WorkerStream 22 | 23 | WorkerStream.prototype.workerMessage = function(e) { 24 | this.emit('data', e.data, e) 25 | } 26 | 27 | WorkerStream.prototype.workerError = function(err) { 28 | this.emit('error', err) 29 | } 30 | 31 | // opts is for transferable objects 32 | WorkerStream.prototype.write = function(data, opts) { 33 | this.worker.postMessage(data, opts) 34 | return true 35 | } 36 | 37 | WorkerStream.prototype.end = function() { 38 | this.emit('end') 39 | } 40 | -------------------------------------------------------------------------------- /one-filler.js: -------------------------------------------------------------------------------- 1 | // fills an arraybuffer with 1's 2 | module.exports = function(ab) { 3 | var buf = new Uint8Array(ab.byteLength) 4 | for (var n = 0; n < buf.length; n++) buf[n] = 1 5 | return buf.buffer 6 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workerstream", 3 | "version": "1.2.1", 4 | "description": "use HTML5 web workers with the node stream API", 5 | "scripts": { 6 | "start": "beefy demo.js:demo-bundle.js demo-worker.js", 7 | "test": "beefy test/ps.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git://github.com/maxogden/workerstream.git" 12 | }, 13 | "author": "max ogden", 14 | "license": "BSD", 15 | "readmeFilename": "readme.md", 16 | "gitHead": "4a95a44ec08edaa96cc458630193afbe6408944d", 17 | "devDependencies": { 18 | "tape": "~2.3.2", 19 | "webworkify": "~0.1.0" 20 | }, 21 | "dependencies": { 22 | "inherits": "^2.0.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /parent.js: -------------------------------------------------------------------------------- 1 | var stream = require('stream') 2 | var inherits = require('inherits'); 3 | 4 | function ParentStream(workerGlobal){ 5 | stream.Stream.call(this) 6 | this.readable = true 7 | this.writable = true 8 | this.parent = workerGlobal || self 9 | this.parent.onmessage = this.parentMessage.bind(this) 10 | this.parent.onerror = this.parentError.bind(this) 11 | } 12 | 13 | inherits(ParentStream, stream.Stream) 14 | 15 | module.exports = function(workerGlobal) { 16 | return new ParentStream(workerGlobal) 17 | } 18 | 19 | module.exports.ParentStream = ParentStream 20 | 21 | ParentStream.prototype.parentMessage = function(e) { 22 | this.emit('data', e.data, e) 23 | } 24 | 25 | ParentStream.prototype.parentError = function(err) { 26 | this.emit('error', err) 27 | } 28 | 29 | // opts is for transferable objects 30 | ParentStream.prototype.write = function(data, opts) { 31 | this.parent.postMessage(data, opts) 32 | return true 33 | } 34 | 35 | ParentStream.prototype.end = function() { 36 | this.emit('end') 37 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # workerstream 2 | 3 | npm install workerstream 4 | 5 | use HTML5 [web workers](https://developer.mozilla.org/En/Using_web_workers) with the node streams API 6 | 7 | var workerstream = require('workerstream') 8 | var worker = workerstream('my-worker.js') 9 | 10 | `worker` is a stream and speaks stream events: `data`, `error` and `end`. that means you can pipe worker output to anything that accepts streams, such as an XHR. you can also pipe data into workers (such as a webcam feed or audio data) 11 | 12 | ## example 13 | 14 | in your app: 15 | 16 | ```js 17 | var worker = workerstream('worker.js') 18 | worker.on('data', function(data) { 19 | console.log(data) 20 | }) 21 | worker.on('error', function(e) { console.log('err', e)}) 22 | worker.write({ hello: 'world' }) 23 | ``` 24 | 25 | the worker code (`worker.js` above): 26 | 27 | ``` 28 | self.onmessage = function(event) { 29 | self.postMessage({whats: 'up'}) 30 | } 31 | ``` 32 | 33 | you can also pass in existing webworker instances 34 | 35 | 36 | ## using with webworkify 37 | 38 | [webworkify](https://npmjs.org/package/webworkify) allows you to simply create browserified webworkers. 39 | 40 | ```js 41 | var WebWorkify = require('webworkify') 42 | var WorkerStream = require('workerstream') 43 | 44 | var worker = WebWorkify(require('./worker.js')) 45 | var workerStream = WorkerStream(worker) 46 | ``` 47 | 48 | Your `worker.js` can use this module's `ParentStream` to create a stream connecting back to the parent 49 | 50 | ```js 51 | var ParentStream = require('workerstream/parent') 52 | 53 | module.exports = function(){ 54 | var parentStream = ParentStream() 55 | parentStream.pipe(somewhereAwesome).pipe(parentStream) 56 | } 57 | ``` 58 | 59 | ## transferable objects 60 | 61 | ```js 62 | worker.write(arraybuffer, [arraybuffer]) 63 | ``` 64 | 65 | MIT LICENSE 66 | -------------------------------------------------------------------------------- /test/ps-loopback-worker.js: -------------------------------------------------------------------------------- 1 | var ParentStream = require('../parent.js') 2 | 3 | module.exports = function(){ 4 | var parentStream = ParentStream() 5 | // just loopback data 6 | parentStream.pipe(parentStream) 7 | } -------------------------------------------------------------------------------- /test/ps.js: -------------------------------------------------------------------------------- 1 | var WebWorkify = require('webworkify') 2 | var WorkerStream = require('../index.js') 3 | var test = require('tape') 4 | 5 | test('Data can be transfered bidirectionally with ParentStream',function(t){ 6 | t.plan(1) 7 | 8 | var worker = WebWorkify(require('./ps-loopback-worker.js')) 9 | var workerStream = WorkerStream(worker) 10 | 11 | var testSlug = 'this is a test slug' 12 | 13 | workerStream.on('data', function(data) { 14 | t.equal(testSlug,data) 15 | t.end() 16 | }) 17 | 18 | workerStream.write( testSlug ) 19 | workerStream.end() 20 | 21 | }) --------------------------------------------------------------------------------