diff --git a/src/stdlib/process-task-shell.coffee b/src/stdlib/process-task-shell.coffee new file mode 100644 index 000000000..83f36327c --- /dev/null +++ b/src/stdlib/process-task-shell.coffee @@ -0,0 +1,37 @@ +global.window = {} +global.attachEvent = -> +console = + warn: -> callTaskMethod 'warn', arguments... + log: -> callTaskMethod 'log', arguments... + error: -> callTaskMethod 'error', arguments... +global.__defineGetter__ 'console', -> console + +window.document = + createElement: -> + setAttribute: -> + getElementsByTagName: -> [] + appendChild: -> + documentElement: + insertBefore: -> + removeChild: -> + getElementById: -> {} + createComment: -> {} + createDocumentFragment: -> {} +global.document = window.document + +# `callTaskMethod` can be used to invoke method's on the parent `Task` object +# back in the window thread. +global.callTaskMethod = (method, args...) -> + process.send(method: method, args: args) + +# The worker's initial handler replaces itglobal when `start` is invoked +global.handler = + start: ({globals, handlerPath}) -> + for key, value of globals + global[key] = value + window[key] = value + global.handler = require(handlerPath) + callTaskMethod 'started' + +process.on 'message', (data) -> + handler[data.method]?(data.args...) if data.method diff --git a/src/stdlib/process-task.coffee b/src/stdlib/process-task.coffee new file mode 100644 index 000000000..d4a7b0b69 --- /dev/null +++ b/src/stdlib/process-task.coffee @@ -0,0 +1,61 @@ +_ = require 'underscore' +child_process = require 'child_process' +EventEmitter = require 'event-emitter' +fs = require 'fs-utils' + +module.exports = +class ProcessTask + aborted: false + + constructor: (@path) -> + + start: -> + throw new Error("Task already started") if @worker? + + # Equivalent with node --eval "...". + blob = "require('coffee-script'); require('process-task-shell');" + @worker = child_process.fork '--eval', [ blob ], cwd: __dirname + + @worker.on 'message', (data) => + if @aborted + @done() + return + + if data.method and this[data.method] + this[data.method](data.args...) + else + @onMessage(data) + + @startWorker() + + log: -> console.log(arguments...) + warn: -> console.warn(arguments...) + error: -> console.error(arguments...) + + startWorker: -> + @callWorkerMethod 'start', + globals: + navigator: + userAgent: navigator.userAgent + handlerPath: @path + + started: -> + + onMessage: (message) -> + + callWorkerMethod: (method, args...) -> + @postMessage({method, args}) + + postMessage: (data) -> + @worker.send(data) + + abort: -> + @aborted = true + + done: -> + @abort() + @worker?.kill() + @worker = null + @trigger 'task-completed' + +_.extend ProcessTask.prototype, EventEmitter