bullring 0.7.4 → 0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
1
  module Bullring
2
- VERSION = "0.7.4"
2
+ VERSION = "0.8"
3
3
  end
@@ -1,36 +1,56 @@
1
1
  require 'bullring/util/exceptions'
2
2
 
3
- # TODO this class may have the common uglifier code, maybe some common
4
- # caching code
5
-
6
3
  module Bullring
7
4
  class Worker
8
5
 
9
- def add_library(name, script)
10
- raise AbstractMethodCalled
11
- end
6
+ attr_reader :libraries
12
7
 
13
- def add_library_file(name, filename)
14
- raise AbstractMethodCalled
8
+ def initialize
9
+ @libraries = {}
10
+ end
11
+
12
+ def add_library(name, script)
13
+ Bullring.logger.debug { "Bullring: Adding library named '#{name}'" }
14
+ @libraries[name] = script
15
+ _add_library(name, script)
15
16
  end
16
17
 
17
18
  def check(script, options)
18
- raise AbstractMethodCalled
19
+ Bullring.logger.debug { "Bullring: Checking script with hash '#{script.hash}'" }
20
+ _check(script, options)
19
21
  end
20
22
 
21
23
  def run(script, options)
22
- raise AbstractMethodCalled
24
+ Bullring.logger.debug { "Bullring: Running script with hash '#{script.hash}'" }
25
+ _run(script, options)
23
26
  end
24
27
 
25
28
  def alive?
26
- raise AbstractMethodCalled
29
+ _alive?
27
30
  end
28
31
 
29
32
  def discard
30
- raise AbstractMethodCalled
33
+ Bullring.logger.debug { "Bullring: Attempting to discard." }
34
+ _discard
31
35
  end
32
36
 
37
+ def refresh
38
+ Bullring.logger.debug { "Bullring: Attempting to refresh." }
39
+ _refresh
40
+ end
41
+
42
+ protected
43
+
44
+ # Quasi-template method pattern
45
+ def _add_library(name, script); end
46
+ def _check(script, options); raise AbstractMethodCalled; end
47
+ def _run(script, options); raise AbstractMethodCalled; end
48
+ def _alive?; raise AbstractMethodCalled; end
49
+ def _discard; raise AbstractMethodCalled; end
50
+
33
51
  end
34
52
  end
35
53
 
36
- require 'bullring/workers/rhino_server_worker'
54
+ require 'bullring/workers/rhino_server_worker'
55
+ require 'bullring/workers/racer_worker'
56
+
@@ -0,0 +1,66 @@
1
+
2
+
3
+ module Bullring
4
+
5
+ class JSError < StandardError
6
+ def initialize(msg = nil)
7
+ @hash = {}
8
+ super(msg)
9
+ end
10
+
11
+ def []=(key, value)
12
+ @hash[key] = value
13
+ end
14
+
15
+ def [](key)
16
+ @hash[key]
17
+ end
18
+
19
+ attr_reader :hash
20
+ end
21
+
22
+ class Helper
23
+ def self.jslint_call(script)
24
+ jslintCall = <<-RACER_CALL
25
+ JSLINT("#{prepare_source(script)}", {devel: false,
26
+ bitwise: true,
27
+ undef: true,
28
+ continue: true,
29
+ unparam: true,
30
+ debug: true,
31
+ sloppy: true,
32
+ eqeq: true,
33
+ sub: true,
34
+ es5: true,
35
+ vars: true,
36
+ evil: true,
37
+ white: true,
38
+ forin: true,
39
+ passfail: false,
40
+ newcap: true,
41
+ nomen: true,
42
+ plusplus: true,
43
+ regexp: true,
44
+ maxerr: 50,
45
+ indent: 4}); JSLINT.errors
46
+ RACER_CALL
47
+ end
48
+
49
+ ESCAPE_MAP = {
50
+ '\\' => '\\\\',
51
+ "\r\n" => '\n',
52
+ "\n" => '\n',
53
+ "\r" => '\n',
54
+ '"' => '\"',
55
+ "'" => '\''
56
+ }
57
+
58
+ def self.prepare_source(source)
59
+ # escape javascript characters (similar to Rails escape_javascript)
60
+ source.gsub!(/(\\|\r\n|[\n\r"'])/u) {|match| ESCAPE_MAP[match] }
61
+ source
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,77 @@
1
+ module Bullring
2
+
3
+ class RacerWorker < Bullring::Worker
4
+
5
+ def initialize
6
+ super
7
+ end
8
+
9
+ def check(script, options)
10
+ context = V8::Context.new
11
+
12
+ context_wrapper {context.load(File.expand_path("../../js/jslint.min.js", __FILE__))}
13
+
14
+ call = Bullring::Helper::jslint_call(script)
15
+ duration, result = context_wrapper {context.eval(call)}
16
+
17
+ result = result.collect{|obj| obj.respond_to?(:to_h) ? obj.to_h : obj}
18
+ end
19
+
20
+ def run(script, options)
21
+ context = V8::Context.new
22
+
23
+ (options['library_names'] || []).each do |library_name|
24
+ library = libraries[library_name]
25
+ context_wrapper {context.eval(library)}
26
+ end
27
+
28
+ # context.timeout = Bullring.configuration.execution_timeout_secs * 1000
29
+
30
+ duration, result = context_wrapper {context.eval(script)}
31
+ result = result.respond_to?(:to_h) ? result.to_h : result
32
+ end
33
+
34
+ def alive?
35
+ true
36
+ end
37
+
38
+ def _discard; end
39
+
40
+ protected
41
+
42
+ def context_wrapper
43
+ begin
44
+
45
+
46
+ start_time = Time.now
47
+ result = yield
48
+ duration = Time.now - start_time
49
+
50
+ Bullring.logger.debug {"#{logname}: Ran script (#{duration} secs); result: " + result.inspect}
51
+
52
+ return duration, result
53
+
54
+ rescue V8::JSError => e
55
+ Bullring.logger.debug {"#{logname}: JSError! Cause: " + e.cause + "; Message: " + e.message}
56
+ raise Bullring::JSError, e.message.to_s, caller
57
+ # rescue Rhino::RunawayScriptError, Rhino::ScriptTimeoutError => e
58
+ # logger.debug {"#{logname}: Runaway Script: " + e.inspect}
59
+ # raise Bullring::JSError, "Script took too long to run", caller
60
+ # rescue Timeout::Error => e
61
+ # Bullring.logger.error {"#{logname}: Runaway script: #{e.inspect}"}
62
+ rescue NameError => e
63
+ Bullring.logger.debug {"#{logname}: Name error: " + e.inspect}
64
+ rescue StandardError => e
65
+ Bullring.logger.debug {"#{logname}: StandardError: " + e.inspect}
66
+ raise
67
+ end
68
+ end
69
+
70
+ def logname; "Bullring (Racer)"; end
71
+
72
+ end
73
+
74
+
75
+
76
+ end
77
+
@@ -2,46 +2,54 @@ require 'rhino'
2
2
  require 'drb'
3
3
  require 'logger'
4
4
 
5
- module Bullring
6
-
7
- class DummyLogger
8
- def method_missing(m, *args, &block)
9
- # ignore
5
+ unless Kernel.respond_to?(:require_relative)
6
+ module Kernel
7
+ def require_relative(path)
8
+ require File.join(File.dirname(caller[0]), path.to_str)
10
9
  end
11
10
  end
11
+ end
12
12
 
13
- class RhinoServer
14
-
15
- @@dummy_logger = Bullring::DummyLogger.new
16
-
17
- def initialize
18
- @library_scripts = {}
19
- @setup_providers = []
20
- configure
21
- logger.info {"#{logname}: Started a RhinoServer instance at #{Time.now}"}
22
- end
23
-
24
- def configure(options={})
25
- @options ||= { :run_is_sealed => false,
26
- :run_is_restrictable => true,
27
- :run_timeout_secs => 0.5 }
13
+ require_relative 'common'
14
+ require_relative '../util/dummy_logger'
15
+ require_relative '../util/server_registry'
28
16
 
29
- # Don't do a merge b/c jruby and ruby don't play nicely for some reason
30
- options.each{|k,v| @options[k] = v}
31
- end
32
-
33
- def load_setup(setup_provider)
34
- # Get the libraries from the setup provider and add them to our local list.
35
- # Hopefully, by calling 'to_s' we are getting copies that live only on our
36
- # side of DRb. Store the provider so we can go back to it later if we
37
- # find that we don't have a required library. Use a list of providers b/c
38
- # some providers may have died off.
17
+ module Bullring
18
+
19
+ class RhinoServer
20
+
21
+ def initialize(host, registry_port)
22
+ @library_cache = {}
39
23
 
40
- setup_provider.libraries.each do |name, script|
41
- add_library(name.to_s, library.to_s)
24
+ @default_options = { :run_is_sealed => false,
25
+ :run_is_restrictable => true,
26
+ :run_timeout_secs => 0.5 }
27
+
28
+ # Connect to the server registry
29
+ @server_registry = ServerRegistry.new(host,registry_port, nil)
30
+
31
+ # Start up as a DRb server (get the port from the registry)
32
+ port = @server_registry.next_server_port
33
+ uri = "druby://#{host}:#{port}"
34
+ DRb.start_service uri, self
35
+
36
+ # Put ourselves on the registry
37
+ @server_registry.register_server(uri)
38
+
39
+ # Keep an eye on the registry, if it dies, we should die
40
+ Thread.new do
41
+ while (true) do
42
+ sleep(5)
43
+ begin
44
+ @server_registry.test!
45
+ rescue
46
+ DRb.stop_service
47
+ Thread.main.exit
48
+ end
49
+ end
42
50
  end
43
51
 
44
- @setup_providers.push(setup_provider)
52
+ DRb.thread.join
45
53
  end
46
54
 
47
55
  def logger=(logger)
@@ -49,62 +57,37 @@ module Bullring
49
57
  end
50
58
 
51
59
  def logger
52
- @logger || @@dummy_logger
60
+ @logger ||= Bullring::DummyLogger.new
53
61
  end
54
-
55
- def add_library(name, script)
56
- @library_scripts[name] = script
57
- end
58
-
59
- def add_library_file(name, filename)
60
- raise NotYetImplemented
61
- script = read file into string
62
- @library_scripts[name] = script
62
+
63
+ def get_library(name)
64
+ @library_cache[name] ||= fetch_library(name)
63
65
  end
64
66
 
65
67
  def check(script, options)
66
68
  Rhino::Context.open do |context|
67
69
  context_wrapper {context.load(File.expand_path("../../js/jslint.min.js", __FILE__))}
68
70
 
69
- jslintCall = <<-RHINO_CALL
70
- JSLINT("#{prepare_source(script)}", {devel: false,
71
- bitwise: true,
72
- undef: true,
73
- continue: true,
74
- unparam: true,
75
- debug: true,
76
- sloppy: true,
77
- eqeq: true,
78
- sub: true,
79
- es5: true,
80
- vars: true,
81
- evil: true,
82
- white: true,
83
- forin: true,
84
- passfail: false,
85
- newcap: true,
86
- nomen: true,
87
- plusplus: true,
88
- regexp: true,
89
- maxerr: 50,
90
- indent: 4});
91
- RHINO_CALL
71
+ call = Bullring::Helper::jslint_call(script)
92
72
 
93
- duration, result = context_wrapper {context.eval(jslintCall + "JSLINT.errors")}
73
+ duration, result = context_wrapper {context.eval(call)}
94
74
 
95
75
  result = result.collect{|obj| obj.respond_to?(:to_h) ? obj.to_h : obj}
96
76
  end
97
77
  end
98
78
 
99
79
  def run(script, options)
100
- Rhino::Context.open(:sealed => @options[:run_is_sealed], :restrictable => @options[:run_is_restrictable]) do |context|
80
+ # Don't do a merge b/c jruby and ruby don't play nicely for some reason
81
+ @default_options.each{|k,v| options[k] = v}
82
+
83
+ Rhino::Context.open(:sealed => options[:run_is_sealed], :restrictable => options[:run_is_restrictable]) do |context|
101
84
 
102
85
  (options['library_names'] || []).each do |library_name|
103
- library_script = @library_scripts[library_name] || fetch_library_script!(library_name)
86
+ library_script = get_library(library_name)
104
87
  context_wrapper {context.eval(library_script)}
105
88
  end
106
89
 
107
- context.timeout_limit = @options[:run_timeout_secs]
90
+ context.timeout_limit = options[:run_timeout_secs]
108
91
 
109
92
  duration, result = context_wrapper {context.eval(script)}
110
93
  result.respond_to?(:to_h) ? result.to_h : result
@@ -120,12 +103,11 @@ module Bullring
120
103
  exit
121
104
  end
122
105
 
123
- def self.start(myPort, clientPort)
124
- DRb.start_service "druby://127.0.0.1:#{myPort}", Bullring::RhinoServer.new
125
- DRb.thread.join
106
+ def self.start(host, registry_port)
107
+ RhinoServer.new(host, registry_port)
126
108
  end
127
109
 
128
- protected
110
+ protected
129
111
 
130
112
  def context_wrapper
131
113
  begin
@@ -137,11 +119,20 @@ module Bullring
137
119
 
138
120
  return duration, result
139
121
  rescue Rhino::JSError => e
140
- logger.debug {"#{logname}: JSError! Cause: " + e.cause + "; Message: " + e.message}
141
- raise Bullring::JSError, e.message.to_s, caller
122
+ logger.debug {"#{logname}: JSError! #{e.inspect}"}
123
+
124
+ error = Bullring::JSError.new(e.message.to_s)
125
+
126
+ if e.message.respond_to?(:keys)
127
+ e.message.each do |k,v|
128
+ error[k.to_s] = v.to_s
129
+ end
130
+ end
131
+
132
+ raise error
142
133
  rescue Rhino::RunawayScriptError, Rhino::ScriptTimeoutError => e
143
134
  logger.debug {"#{logname}: Runaway Script: " + e.inspect}
144
- raise Bullring::JSError, "Script took too long to run", caller
135
+ raise Bullring::JSError, "Script took too long to run"
145
136
  rescue NameError => e
146
137
  logger.debug {"#{logname}: Name error: " + e.inspect}
147
138
  rescue StandardError => e
@@ -149,53 +140,23 @@ module Bullring
149
140
  raise
150
141
  end
151
142
  end
152
-
153
- ESCAPE_MAP = {
154
- '\\' => '\\\\',
155
- "\r\n" => '\n',
156
- "\n" => '\n',
157
- "\r" => '\n',
158
- '"' => '\"',
159
- "'" => '\''
160
- }
161
-
162
- def prepare_source(source)
163
- # escape javascript characters (similar to Rails escape_javascript)
164
- source.gsub!(/(\\|\r\n|[\n\r"'])/u) {|match| ESCAPE_MAP[match] }
165
- source
166
- end
167
143
 
168
- # Goes back to the setup provider to the get the named script or throws an
169
- # exception if there is no such script to retrieve.
170
- def fetch_library_script!(name)
171
- logger.debug {"#{logname}: The script named #{name} was not available so trying to fetch from clients"}
172
-
173
- while (provider = @setup_providers.last)
174
- begin
175
- library_script = provider.libraries[name]
176
- break if !library_script.nil?
177
- rescue DRb::DRbConnError => e
178
- logger.debug {"#{logname}: Could not connect to setup provider (its process probably died): " + e.inspect}
179
- rescue StandardError => e
180
- logger.error {"#{logname}: Encountered an unknown error searching setup providers for a script named #{name}: " + e.inspect}
181
- ensure
182
- # Toss the last element so we can continue searching prior elements
183
- setup_providers.pop
184
- end
185
- end
186
-
187
- # If after looking through the providers we are still empty handed, raise an error
188
- raise NameError, "Client doesn't have script named #{name}", caller if library_script.nil?
144
+ # Grab the library from the registry server
145
+ def fetch_library(name)
146
+ library_script = @server_registry['library', name]
189
147
 
190
- add_library(name, library_script)
148
+ logger.debug {"#{logname}: Tried to fetch script '#{name}' from the registry and it " +
149
+ "was #{'not ' if library_script.nil?}found."}
150
+
151
+ raise NameError, "Server cannot find a script named #{name}" if library_script.nil?
152
+
153
+ library_script
191
154
  end
192
155
 
193
- def logname; "Bullring Server"; end
156
+ def logname; "Bullring (Rhino Server)"; end
194
157
 
195
158
  end
196
159
 
197
- class JSError < StandardError; end
198
-
199
160
  end
200
161
 
201
162
  #
@@ -203,11 +164,11 @@ end
203
164
  #
204
165
 
205
166
  command = ARGV[0]
206
- myPort = ARGV[1]
207
- clientPort = ARGV[2]
167
+ host = ARGV[1]
168
+ registry_port = ARGV[2]
208
169
 
209
170
  case command
210
171
  when "start"
211
- Bullring::RhinoServer.start(myPort, clientPort)
172
+ Bullring::RhinoServer.start(host, registry_port)
212
173
  end
213
174