websockets is just a hair faster and easier to implement. just sayin'.

This commit is contained in:
John Bintz 2012-03-21 18:41:29 -04:00
parent ed00ba476a
commit 9de5460533
7 changed files with 70 additions and 102 deletions

View File

@ -33,5 +33,6 @@ Gem::Specification.new do |gem|
gem.add_dependency 'sprockets' gem.add_dependency 'sprockets'
gem.add_dependency 'sprockets-vendor_gems' gem.add_dependency 'sprockets-vendor_gems'
gem.add_dependency 'thin' gem.add_dependency 'thin'
gem.add_dependency 'em-websocket'
end end

View File

@ -3,77 +3,18 @@
#= require flowerbox/exception #= require flowerbox/exception
# #
Flowerbox = Flowerbox =
baseUrl: '/'
debug: false debug: false
ping: -> ping: ->
Flowerbox.contact('ping') Flowerbox.contact('ping')
contactQueue: []
contact: (url, data...) -> contact: (url, data...) ->
Flowerbox.started = true
if !Flowerbox.debug if !Flowerbox.debug
Flowerbox.contactQueue.push([url, data]) Flowerbox.socket.send(JSON.stringify([ url, data ]))
Flowerbox.done = true if url == 'results'
queueIndex: 0
delay: 40
started: false started: false
done: false done: false
xhrObjects: {}
onQueueStateChange: ->
queueRunner: (failsafe = 5) ->
Flowerbox.onQueueStateChange("checking queue")
if Flowerbox.contactQueue.length > 0
Flowerbox.started = true
info = Flowerbox.contactQueue.shift()
[ url, data ] = info
xhr = new XMLHttpRequest()
xhr.open("POST", Flowerbox.baseUrl + url, true)
xhr.setRequestHeader("Accept", "application/json")
done = false
xhr.onreadystatechange = ->
if xhr.readyState == 4
done = true
Flowerbox.onQueueStateChange("done #{url}")
if url == "results"
Flowerbox.onQueueStateChange("finsihed all tests")
Flowerbox.done = true
else
setTimeout(
->
Flowerbox.queueRunner()
, 1
)
Flowerbox.onQueueStateChange("running #{url}")
setTimeout(
->
if xhr.readyState != 4
xhr.abort()
Flowerbox.onQueueStateChange("aborted #{url}, rerunning")
Flowerbox.contactQueue.unshift(info)
if failsafe > 0
failsafe -= 1
Flowerbox.queueRunner(failsafe)
, Flowerbox.delay * 5
)
xhr.send(JSON.stringify(data))
else
Flowerbox.startQueueRunner()
startQueueRunner: ->
setTimeout(
->
Flowerbox.queueRunner()
, Flowerbox.delay
)
fail: -> fail: ->

View File

@ -48,19 +48,15 @@ module Flowerbox
end end
command :ping do command :ping do
runner.ping
end end
command :pause_timer do command :pause_timer do
runner.pause_timer
end end
command :unpause_timer do command :unpause_timer do
runner.unpause_timer
end end
command :starting do command :starting do
runner.did_start!
end end
get %r{^/__F__/(.*)$} do |file| get %r{^/__F__/(.*)$} do |file|

View File

@ -140,7 +140,7 @@ module Flowerbox
server_options[:logging] = true if options[:verbose_server] server_options[:logging] = true if options[:verbose_server]
server_options[:port] = Flowerbox.port server_options[:port] = Flowerbox.port
Flowerbox.server = Flowerbox::Server.new(server_options) Flowerbox.server = Flowerbox::Server.new(self, server_options)
end end
def log(message) def log(message)

View File

@ -22,13 +22,13 @@ module Flowerbox
def configured? def configured?
File.directory?(File.join(Dir.pwd, 'node_modules/jsdom')) && File.directory?(File.join(Dir.pwd, 'node_modules/jsdom')) &&
File.directory?(File.join(Dir.pwd, 'node_modules/xmlhttprequest')) File.directory?(File.join(Dir.pwd, 'node_modules/ws'))
end end
def cleanup ; end def cleanup ; end
def configure def configure
system %{bash -c "mkdir -p node_modules && npm link jsdom && npm link xmlhttprequest"} system %{bash -c "mkdir -p node_modules && npm link jsdom && npm link ws"}
end end
def run(sprockets, spec_files, options) def run(sprockets, spec_files, options)
@ -53,7 +53,7 @@ var fs = require('fs'),
vm = require('vm'), vm = require('vm'),
http = require('http'), http = require('http'),
jsdom = require('jsdom'), jsdom = require('jsdom'),
xhr = require('xmlhttprequest') ws = require('ws')
// expand the sandbox a bit // expand the sandbox a bit
var context = function() {}; var context = function() {};
@ -62,7 +62,7 @@ for (method in global) { context[method] = global[method]; }
jsdom.env( jsdom.env(
"<html><head><title></title></head><body></body></html>", [], function(errors, window) { "<html><head><title></title></head><body></body></html>", [], function(errors, window) {
context.window = window; context.window = window;
context.XMLHttpRequest = xhr.XMLHttpRequest; context.WebSocket = ws;
var gotFlowerbox = false; var gotFlowerbox = false;
@ -106,23 +106,20 @@ jsdom.env(
request.end(); request.end();
} else { } else {
#{env} context.Flowerbox.socket = new ws('ws://localhost:#{server.port + 1}/');
context.Flowerbox.socket.onopen = function() {
#{env}
context.Flowerbox.onQueueStateChange = function(msg) { var waitForFinish;
//console.log(msg); waitForFinish = function() {
if (!context.Flowerbox.started || !context.Flowerbox.done) {
process.nextTick(waitForFinish);
} else {
process.exit(0);
}
};
waitForFinish();
}; };
context.Flowerbox.startQueueRunner()
var waitForFinish;
waitForFinish = function() {
if (!context.Flowerbox.started || !context.Flowerbox.done) {
process.nextTick(waitForFinish);
} else {
process.exit(0);
}
};
waitForFinish();
} }
}; };
fileRunner(); fileRunner();

View File

@ -70,8 +70,10 @@ console.log = function(msg) {
var context = this; var context = this;
window.addEventListener('DOMContentLoaded', function() { window.addEventListener('DOMContentLoaded', function() {
#{env} Flowerbox.socket = new WebSocket('ws://localhost:#{server.port + 1}/');
Flowerbox.startQueueRunner() Flowerbox.socket.onopen = function() {
#{env}
};
}, false); }, false);
</script> </script>
</body> </body>

View File

@ -3,16 +3,19 @@ require 'net/http'
require 'socket' require 'socket'
require 'rack/builder' require 'rack/builder'
require 'thin' require 'thin'
require 'eventmachine' require 'em-websocket'
module Flowerbox module Flowerbox
class Server class Server
attr_reader :options attr_reader :options
attr_reader :runner
class MissingRackApp < StandardError ; end class MissingRackApp < StandardError ; end
class ServerDiedError < StandardError ; end class ServerDiedError < StandardError ; end
def initialize(options = {}) def initialize(runner, options = {})
@runner = runner
@options = { :logging => false }.merge(options || {}) @options = { :logging => false }.merge(options || {})
end end
@ -22,23 +25,51 @@ module Flowerbox
def start def start
@server_thread = Thread.new do @server_thread = Thread.new do
server_options = { :Port => port, :Host => interface } EventMachine.run do
server_options = { :Port => port, :Host => interface }
Thin::Logging.silent = !options[:logging] Thin::Logging.silent = !options[:logging]
rack_app = app rack_app = app
if options[:logging] if options[:logging]
rack_app = ::Rack::Builder.new do rack_app = ::Rack::Builder.new do
use ::Rack::CommonLogger, STDOUT use ::Rack::CommonLogger, STDOUT
run app run app
end
end end
end
::Rack::Handler::Thin.run(rack_app, server_options) do |server| EventMachine::WebSocket.start(:host => interface, :port => port + 1) do |ws|
Thread.current[:server] = server ws.onmessage { |message|
command, data = JSON.parse(message)
trap('QUIT') { server.stop } case command
when 'starting'
runner.did_start!
when 'unpause_timer'
runner.unpause_timer
when 'pause_timer'
runner.pause_timer
when 'ping'
runner.ping
when 'log'
runner.log(data.first)
when 'finish_test'
runner.add_results(data.flatten)
when 'start_test'
runner.add_tests(data.flatten)
when 'results'
runner.finish!(data.flatten.first)
end
}
end
::Rack::Handler::Thin.run(rack_app, server_options) do |server|
Thread.current[:server] = server
trap('QUIT') { server.stop }
end
end end
end end
@ -69,7 +100,7 @@ module Flowerbox
begin begin
attempts -= 1 attempts -= 1
current_port = random_port current_port = (random_port / 2).floor * 2
begin begin
socket = TCPSocket.new(interface, current_port) socket = TCPSocket.new(interface, current_port)