nodo 1.5.5 → 1.6.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3cef66bc4b1d53b20500110ac7acbc226ec361b6aaed569874ce8568a6718242
4
- data.tar.gz: ab2cae6eef01d53ebc1c471a5e08edfd37a263178adc49aa459c98dfcea4e92f
3
+ metadata.gz: 95d8c9823753373c6be5ad0c493e7f14346950b611d4ca0d90c5a96bcabfa5e6
4
+ data.tar.gz: 3ad4b37694f4ef33cfadad03794ce7b4bf2a9fd42dc4e0abb319ec981e529b33
5
5
  SHA512:
6
- metadata.gz: 9bf90e8b56366f2e42039026575db43a0c5a9808a677a533c3e211c9ae211a8f06b2ea0890550e22fca259f9fa416c0e96017a676538a3eb673f2a66caa0996a
7
- data.tar.gz: 2573e2dfd199bb9f8e25dc11c5dcb49e0ba6f29796aaa523656fa1020e0d8ce325ab411cf2d60413ac0557407fec4a132ba51d75075585a0e7b56d76bfc42811
6
+ metadata.gz: 0e0004a84541cb4edd4cc398250fe17ee5623aed13f1bbb76b31eee531867906cffd87c5e0f71b50c0c72fdae4f26e57d24f654fdd2623bee90b20c60f3ff0b4
7
+ data.tar.gz: 539b75f4a8283f4db872db614158403129651f4b0811d9e7f9ef5dfa1f506bedcf238fa0b93896fe776ae936bbc8eba9cbd44ea86fa8f80b87142e5d69cfe957
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
- [![Gem Version](https://badge.fury.io/rb/nodo.svg)](http://badge.fury.io/rb/nodo) [![build](https://github.com/mtgrosser/nodo/actions/workflows/build.yml/badge.svg)](https://github.com/mtgrosser/nodo/actions/workflows/build.yml)
1
+ [![Gem Version](https://badge.fury.io/rb/nodo.svg)](http://badge.fury.io/rb/nodo)
2
+ [![build](https://github.com/mtgrosser/nodo/actions/workflows/build.yml/badge.svg)](https://github.com/mtgrosser/nodo/actions/workflows/build.yml)
2
3
 
3
4
  # Nōdo – call Node.js from Ruby
4
5
 
@@ -107,13 +108,7 @@ To set a custom path:
107
108
  Nodo.modules_root = 'path/to/node_modules'
108
109
  ```
109
110
 
110
- For Rails applications, it will be set to `vendor/node_modules`.
111
- To use the Rails 6 default of putting `node_modules` to `RAILS_ROOT`:
112
-
113
- ```ruby
114
- # config/initializers/nodo.rb
115
- Nodo.modules_root = Rails.root.join('node_modules')
116
- ```
111
+ Also see: [Clean your Rails root](#Clean-your-Rails-root)
117
112
 
118
113
  ### Defining JS constants
119
114
 
@@ -175,8 +170,17 @@ end
175
170
 
176
171
  ### Limiting function execution time
177
172
 
178
- The default timeout for a single JS function call is 60 seconds due to the
179
- `Net::HTTP` default. It can be overridden on a per-function basis:
173
+ The default timeout for a single JS function call is 60 seconds and can be
174
+ set globally:
175
+
176
+ ```ruby
177
+ Nodo.timeout = 5
178
+ ```
179
+
180
+ If the execution of a single function call exceeds the timeout, `Nodo::TimeoutError`
181
+ is raised.
182
+
183
+ The timeout can also be set on a per-function basis:
180
184
 
181
185
  ```ruby
182
186
  class Foo < Nodo::Core
@@ -185,6 +189,105 @@ class Foo < Nodo::Core
185
189
  JS
186
190
  end
187
191
 
188
- foo.new.sleep(2)
192
+ Foo.new.sleep(2)
189
193
  => Nodo::TimeoutError raised
190
194
  ```
195
+
196
+ ### Logging
197
+
198
+ By default, JS errors will be logged to `STDOUT`.
199
+
200
+ To set a custom logger:
201
+
202
+ ```ruby
203
+ Nodo.logger = Logger.new('nodo.log')
204
+ ```
205
+
206
+ In Rails applications, `Rails.logger` will automatically be set.
207
+
208
+
209
+ ### Debugging
210
+
211
+ To get verbose debug output, set
212
+
213
+ ```ruby
214
+ Nodo.debug = true
215
+ ```
216
+
217
+ before instantiating any worker instances. The debug mode will be active during
218
+ the current process run.
219
+
220
+ To print a debug message from JS code:
221
+
222
+ ```js
223
+ nodo.debug("Debug message");
224
+ ```
225
+
226
+ ### Evaluation
227
+
228
+ While `Nodo` is mainly function-based, it is possible to evaluate JS code in the
229
+ context of the defined object.
230
+
231
+ ```ruby
232
+ foo = Foo.new.evaluate("3 + 5")
233
+ => 8
234
+ ```
235
+
236
+ Evaluated code can access functions, required dependencies and constants:
237
+
238
+ ```ruby
239
+ class Foo < Nodo::Core
240
+ const :BAR, 'bar'
241
+ require :uuid
242
+ function :hello, code: '() => "world"'
243
+ end
244
+
245
+ foo = Foo.new
246
+
247
+ foo.evaluate('BAR')
248
+ => "bar"
249
+
250
+ foo.evaluate('uuid.v4()')
251
+ => "f258bef3-0d6f-4566-ad39-d8dec973ef6b"
252
+
253
+ foo.evaluate('hello()')
254
+ => "world"
255
+ ```
256
+
257
+ Variables defined by evaluation are local to the current instance:
258
+
259
+ ```ruby
260
+ one = Foo.new
261
+ one.evaluate('a = 1')
262
+ two = Foo.new
263
+ two.evaluate('a = 2')
264
+ one.evaluate('a') => 1
265
+ two.evaluate('a') => 2
266
+ ```
267
+
268
+ ⚠️ Evaluation comes with the usual caveats:
269
+
270
+ - Avoid modifying any of your predefined identifiers. Remember that in JS,
271
+ as in Ruby, constants are not necessarily constant.
272
+ - Never evaluate any code which includes un-checked user data. The Node.js process
273
+ has full read/write access to your filesystem! 💥
274
+
275
+
276
+ ## Clean your Rails root
277
+
278
+ For Rails applications, Nodo enables you to move `node_modules`, `package.json` and
279
+ `yarn.lock` into your application's `vendor` folder by setting the `NODE_PATH` in
280
+ an initializer:
281
+
282
+ ```ruby
283
+ # config/initializers/nodo.rb
284
+ Nodo.modules_root = Rails.root.join('vendor', 'node_modules')
285
+ ```
286
+
287
+ The rationale for this is NPM modules being external vendor dependencies, which
288
+ should not clutter the application root directory.
289
+
290
+ With this new default, all `yarn` operations should be done after `cd`ing to `vendor`.
291
+
292
+ This repo provides an [adapted version](https://github.com/mtgrosser/nodo/blob/master/install/yarn.rake)
293
+ of the `yarn:install` rake task which will automatically take care of the vendored module location.
data/lib/nodo/constant.rb CHANGED
@@ -7,7 +7,7 @@ module Nodo
7
7
  end
8
8
 
9
9
  def to_js
10
- "const #{name} = #{value.to_json};\n"
10
+ "const #{name} = __nodo_klass__.#{name} = #{value.to_json};\n"
11
11
  end
12
12
  end
13
13
  end
data/lib/nodo/core.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  module Nodo
2
2
  class Core
3
3
  SOCKET_NAME = 'nodo.sock'
4
- DEFINE_METHOD = '__nodo_define_class__'
5
- TIMEOUT = 5
4
+ DEFINE_METHOD = '__nodo_define_class__'.freeze
5
+ EVALUATE_METHOD = '__nodo_evaluate__'.freeze
6
+ GC_METHOD = '__nodo_gc__'.freeze
7
+ INTERNAL_METHODS = [DEFINE_METHOD, EVALUATE_METHOD, GC_METHOD].freeze
8
+ LAUNCH_TIMEOUT = 5
6
9
  ARRAY_CLASS_ATTRIBUTES = %i[dependencies constants scripts].freeze
7
10
  HASH_CLASS_ATTRIBUTES = %i[functions].freeze
8
11
  CLASS_ATTRIBUTES = (ARRAY_CLASS_ATTRIBUTES + HASH_CLASS_ATTRIBUTES).freeze
@@ -10,6 +13,7 @@ module Nodo
10
13
  @@node_pid = nil
11
14
  @@tmpdir = nil
12
15
  @@mutex = Mutex.new
16
+ @@exiting = nil
13
17
 
14
18
  class << self
15
19
  extend Forwardable
@@ -21,15 +25,11 @@ module Nodo
21
25
  subclass.send "#{attr}=", send(attr).dup
22
26
  end
23
27
  end
24
-
28
+
25
29
  def instance
26
30
  @instance ||= new
27
31
  end
28
32
 
29
- def class_function(*methods)
30
- singleton_class.def_delegators(:instance, *methods)
31
- end
32
-
33
33
  def class_defined?
34
34
  !!class_defined
35
35
  end
@@ -42,6 +42,7 @@ module Nodo
42
42
  define_method "#{attr}=" do |value|
43
43
  instance_variable_set :"@#{attr}", value
44
44
  end
45
+ protected "#{attr}="
45
46
  end
46
47
 
47
48
  ARRAY_CLASS_ATTRIBUTES.each do |attr|
@@ -55,28 +56,6 @@ module Nodo
55
56
  instance_variable_get(:"@#{attr}") || instance_variable_set(:"@#{attr}", {})
56
57
  end
57
58
  end
58
-
59
- def require(*mods)
60
- deps = mods.last.is_a?(Hash) ? mods.pop : {}
61
- mods = mods.map { |m| [m, m] }.to_h
62
- self.dependencies = dependencies + mods.merge(deps).map { |name, package| Dependency.new(name, package) }
63
- end
64
-
65
- def function(name, _code = nil, timeout: 60, code: nil)
66
- raise ArgumentError, "reserved method name #{name.inspect}" if Nodo::Core.method_defined?(name)
67
- code = (code ||= _code).strip
68
- raise ArgumentError, 'function code is required' if '' == code
69
- self.functions = functions.merge(name => Function.new(name, _code || code, caller.first, timeout))
70
- define_method(name) { |*args| call_js_method(name, args) }
71
- end
72
-
73
- def const(name, value)
74
- self.constants = constants + [Constant.new(name, value)]
75
- end
76
-
77
- def script(code)
78
- self.scripts = scripts + [Script.new(code)]
79
- end
80
59
 
81
60
  def generate_core_code
82
61
  <<~JS
@@ -94,7 +73,7 @@ module Nodo
94
73
  nodo.core.close(() => { process.exit(0) });
95
74
  };
96
75
 
97
- process.on('SIGINT', shutdown);
76
+ // process.on('SIGINT', shutdown);
98
77
  process.on('SIGTERM', shutdown);
99
78
 
100
79
  nodo.core.run(socket);
@@ -104,8 +83,7 @@ module Nodo
104
83
  def generate_class_code
105
84
  <<~JS
106
85
  (() => {
107
- const __nodo_log = nodo.log;
108
- const __nodo_klass__ = {};
86
+ const __nodo_klass__ = { nodo: global.nodo };
109
87
  #{dependencies.map(&:to_js).join}
110
88
  #{constants.map(&:to_js).join}
111
89
  #{functions.values.map(&:to_js).join}
@@ -115,14 +93,57 @@ module Nodo
115
93
  JS
116
94
  end
117
95
 
96
+ protected
97
+
98
+ def finalize_context(context_id)
99
+ proc do
100
+ if not @@exiting and core = Nodo::Core.instance
101
+ core.send(:call_js_method, GC_METHOD, context_id)
102
+ end
103
+ end
104
+ end
105
+
118
106
  private
119
107
 
108
+ def require(*mods)
109
+ deps = mods.last.is_a?(Hash) ? mods.pop : {}
110
+ mods = mods.map { |m| [m, m] }.to_h
111
+ self.dependencies = dependencies + mods.merge(deps).map { |name, package| Dependency.new(name, package) }
112
+ end
113
+
114
+ def function(name, _code = nil, timeout: Nodo.timeout, code: nil)
115
+ raise ArgumentError, "reserved method name #{name.inspect}" if reserved_method_name?(name)
116
+ code = (code ||= _code).strip
117
+ raise ArgumentError, 'function code is required' if '' == code
118
+ loc = caller_locations(1, 1)[0]
119
+ source_location = "#{loc.path}:#{loc.lineno}: in `#{name}'"
120
+ self.functions = functions.merge(name => Function.new(name, _code || code, source_location, timeout))
121
+ define_method(name) { |*args| call_js_method(name, args) }
122
+ end
123
+
124
+ def class_function(*methods)
125
+ singleton_class.def_delegators(:instance, *methods)
126
+ end
127
+
128
+ def const(name, value)
129
+ self.constants = constants + [Constant.new(name, value)]
130
+ end
131
+
132
+ def script(code)
133
+ self.scripts = scripts + [Script.new(code)]
134
+ end
135
+
120
136
  def nodo_js
121
137
  Pathname.new(__FILE__).dirname.join('nodo.js').to_s.to_json
122
138
  end
139
+
140
+ def reserved_method_name?(name)
141
+ Nodo::Core.method_defined?(name, false) || Nodo::Core.private_method_defined?(name, false) || name.to_s == DEFINE_METHOD
142
+ end
123
143
  end
124
144
 
125
145
  def initialize
146
+ raise ClassError, :new if self.class == Nodo::Core
126
147
  @@mutex.synchronize do
127
148
  ensure_process_is_spawned
128
149
  wait_for_socket
@@ -130,6 +151,13 @@ module Nodo
130
151
  end
131
152
  end
132
153
 
154
+ def evaluate(code)
155
+ ensure_context_is_defined
156
+ call_js_method(EVALUATE_METHOD, code)
157
+ end
158
+
159
+ private
160
+
133
161
  def node_pid
134
162
  @@node_pid
135
163
  end
@@ -146,6 +174,17 @@ module Nodo
146
174
  self.class.clsid
147
175
  end
148
176
 
177
+ def context_defined?
178
+ @context_defined
179
+ end
180
+
181
+ def log_exception(e)
182
+ return unless logger = Nodo.logger
183
+ message = "\n#{e.class} (#{e.message})"
184
+ message << ":\n\n#{e.backtrace.join("\n")}" if e.backtrace
185
+ logger.error message
186
+ end
187
+
149
188
  def ensure_process_is_spawned
150
189
  return if node_pid
151
190
  spawn_process
@@ -157,11 +196,22 @@ module Nodo
157
196
  self.class.class_defined = true
158
197
  end
159
198
 
199
+ def ensure_context_is_defined
200
+ return if context_defined?
201
+ @@mutex.synchronize do
202
+ call_js_method(EVALUATE_METHOD, '')
203
+ ObjectSpace.define_finalizer(self, self.class.send(:finalize_context, self.object_id))
204
+ @context_defined = true
205
+ end
206
+ end
207
+
160
208
  def spawn_process
161
209
  @@tmpdir = Pathname.new(Dir.mktmpdir('nodo'))
162
210
  env = Nodo.env.merge('NODE_PATH' => Nodo.modules_root.to_s)
211
+ env['NODO_DEBUG'] = '1' if Nodo.debug
163
212
  @@node_pid = Process.spawn(env, Nodo.binary, '-e', self.class.generate_core_code, '--', socket_path.to_s, err: :out)
164
213
  at_exit do
214
+ @@exiting = true
165
215
  Process.kill(:SIGTERM, node_pid) rescue Errno::ECHILD
166
216
  Process.wait(node_pid) rescue Errno::ECHILD
167
217
  FileUtils.remove_entry(tmpdir) if File.directory?(tmpdir)
@@ -171,7 +221,7 @@ module Nodo
171
221
  def wait_for_socket
172
222
  start = Time.now
173
223
  socket = nil
174
- while Time.now - start < TIMEOUT
224
+ while Time.now - start < LAUNCH_TIMEOUT
175
225
  begin
176
226
  break if socket = UNIXSocket.new(socket_path)
177
227
  rescue Errno::ENOENT, Errno::ECONNREFUSED, Errno::ENOTDIR
@@ -184,10 +234,16 @@ module Nodo
184
234
 
185
235
  def call_js_method(method, args)
186
236
  raise CallError, 'Node process not ready' unless node_pid
187
- raise CallError, "Class #{clsid} not defined" unless self.class.class_defined? || method == DEFINE_METHOD
237
+ raise CallError, "Class #{clsid} not defined" unless self.class.class_defined? || INTERNAL_METHODS.include?(method)
188
238
  function = self.class.functions[method]
189
- raise NameError, "undefined function `#{method}' for #{self.class}" unless function || method == DEFINE_METHOD
190
- request = Net::HTTP::Post.new("/#{clsid}/#{method}", 'Content-Type': 'application/json')
239
+ raise NameError, "undefined function `#{method}' for #{self.class}" unless function || INTERNAL_METHODS.include?(method)
240
+ context_id = case method
241
+ when DEFINE_METHOD then 0
242
+ when GC_METHOD then args.first
243
+ else
244
+ object_id
245
+ end
246
+ request = Net::HTTP::Post.new("/#{clsid}/#{context_id}/#{method}", 'Content-Type': 'application/json')
191
247
  request.body = JSON.dump(args)
192
248
  client = Client.new("unix://#{socket_path}")
193
249
  client.read_timeout = function.timeout if function
@@ -207,9 +263,14 @@ module Nodo
207
263
  def handle_error(response, function)
208
264
  if response.body
209
265
  result = parse_response(response)
210
- raise JavaScriptError.new(result['error'], function) if result.is_a?(Hash) && result.key?('error')
266
+ error = if result.is_a?(Hash) && result['error'].is_a?(Hash)
267
+ attrs = result['error']
268
+ (attrs['nodo_dependency'] ? DependencyError : JavaScriptError).new(attrs, function)
269
+ end
211
270
  end
212
- raise CallError, "Node returned #{response.code}"
271
+ error ||= CallError.new("Node returned #{response.code}")
272
+ log_exception(error)
273
+ raise error
213
274
  end
214
275
 
215
276
  def parse_response(response)
@@ -7,7 +7,16 @@ module Nodo
7
7
  end
8
8
 
9
9
  def to_js
10
- "const #{name} = require(#{package.to_json});\n"
10
+ <<~JS
11
+ const #{name} = __nodo_klass__.#{name} = (() => {
12
+ try {
13
+ return require(#{package.to_json});
14
+ } catch(e) {
15
+ e.nodo_dependency = #{package.to_json};
16
+ throw e;
17
+ }
18
+ })();
19
+ JS
11
20
  end
12
21
  end
13
22
  end
data/lib/nodo/errors.rb CHANGED
@@ -2,6 +2,11 @@ module Nodo
2
2
  class Error < StandardError; end
3
3
  class TimeoutError < Error; end
4
4
  class CallError < Error; end
5
+ class ClassError < Error
6
+ def initialize(method = nil)
7
+ super("Cannot call method `#{method}' on Nodo::Core, use subclass instead")
8
+ end
9
+ end
5
10
 
6
11
  class JavaScriptError < Error
7
12
  attr_reader :attributes
@@ -37,13 +42,23 @@ module Nodo
37
42
  end
38
43
 
39
44
  def generate_message
40
- message = "#{attributes['message'] || 'Unknown error'}"
41
- if loc = attributes['loc']
42
- message << loc.inject(' in') { |s, (key, value)| s << " #{key}: #{value}" }
43
- end
44
- message
45
+ message = "#{attributes['message'] || attributes['name'] || 'Unknown error'}"
46
+ message << format_location(attributes['loc'])
47
+ end
48
+
49
+ def format_location(loc)
50
+ return '' unless loc
51
+ loc.inject(' in') { |s, (key, value)| s << " #{key}: #{value}" }
45
52
  end
46
53
  end
47
54
 
48
- class DependencyError < JavaScriptError; end
55
+ class DependencyError < JavaScriptError
56
+ private
57
+
58
+ def generate_message
59
+ message = "#{attributes['message'] || attributes['name'] || 'Dependency error'}\n"
60
+ message << "The specified dependency '#{attributes['nodo_dependency']}' could not be loaded. "
61
+ message << "Run 'yarn add #{attributes['nodo_dependency']}' to install it.\n"
62
+ end
63
+ end
49
64
  end
data/lib/nodo/nodo.js CHANGED
@@ -1,5 +1,8 @@
1
1
  module.exports = (function() {
2
2
  const DEFINE_METHOD = '__nodo_define_class__';
3
+ const EVALUATE_METHOD = '__nodo_evaluate__';
4
+ const GC_METHOD = '__nodo_gc__';
5
+ const DEBUG = process.env.NODO_DEBUG;
3
6
 
4
7
  const vm = require('vm');
5
8
  const http = require('http');
@@ -9,6 +12,7 @@ module.exports = (function() {
9
12
 
10
13
  let server, closing;
11
14
  const classes = {};
15
+ const contexts = {};
12
16
 
13
17
  function render_error(e) {
14
18
  let errInfo = {};
@@ -24,7 +28,7 @@ module.exports = (function() {
24
28
  function respond_with_error(res, code, name) {
25
29
  res.statusCode = code;
26
30
  const rendered = render_error(name);
27
- log(`Error ${code} ${rendered}`);
31
+ debug(`Error ${code} ${rendered}`);
28
32
  res.end(rendered, 'utf8');
29
33
  }
30
34
 
@@ -35,34 +39,41 @@ module.exports = (function() {
35
39
  if (start) {
36
40
  timing = ` in ${(performance.now() - start).toFixed(2)}ms`;
37
41
  }
38
- log(`Completed 200 OK${timing}`);
42
+ debug(`Completed 200 OK${timing}\n`);
39
43
  }
40
44
 
41
- function log(message) {
42
- // fs.appendFileSync('log/nodo.log', `${message}\n`);
43
- // console.log(`[Nodo] ${message}`);
45
+ function debug(message) {
46
+ if (DEBUG) {
47
+ // fs.appendFileSync('log/nodo.log', `${message}\n`);
48
+ console.log(`[Nodo] ${message}`);
49
+ }
44
50
  }
45
51
 
46
52
  const core = {
47
53
  run: (socket) => {
48
- log('Starting up...');
54
+ debug('Starting up...');
49
55
  server = http.createServer((req, res) => {
50
56
  const start = performance.now();
51
57
 
52
58
  res.setHeader('Content-Type', 'application/json');
53
- log(`${req.method} ${req.url}`);
59
+ debug(`${req.method} ${req.url}`);
54
60
 
55
61
  if (req.method !== 'POST' || !req.url.startsWith('/')) {
56
62
  return respond_with_error(res, 405, 'Method Not Allowed');
57
63
  }
58
64
 
59
65
  const url = req.url.substring(1);
60
- const [class_name, method] = url.split('/');
61
- let klass;
66
+ const [class_name, object_id, method] = url.split('/');
67
+ let klass, context;
62
68
 
63
69
  if (classes.hasOwnProperty(class_name)) {
64
70
  klass = classes[class_name];
65
- if (!klass.hasOwnProperty(method)) {
71
+ if (EVALUATE_METHOD == method) {
72
+ if (!contexts.hasOwnProperty(object_id)) {
73
+ contexts[object_id] = vm.createContext({ require: require, ...klass });
74
+ }
75
+ context = contexts[object_id];
76
+ } else if (!klass.hasOwnProperty(method) && !GC_METHOD == method) {
66
77
  return respond_with_error(res, 404, `Method ${class_name}#${method} not found`);
67
78
  }
68
79
  } else if (DEFINE_METHOD != method) {
@@ -84,13 +95,21 @@ module.exports = (function() {
84
95
 
85
96
  try {
86
97
  if (DEFINE_METHOD == method) {
87
- let new_class = vm.runInThisContext(input, class_name);
88
- classes[class_name] = new_class;
98
+ classes[class_name] = vm.runInThisContext(input, class_name);
89
99
  respond_with_data(res, class_name, start);
100
+ } else if (EVALUATE_METHOD == method) {
101
+ Promise.resolve(vm.runInNewContext(input, context)).then((result) => {
102
+ respond_with_data(res, result, start);
103
+ }).catch((error) => {
104
+ respond_with_error(res, 500, error);
105
+ });
106
+ } else if (GC_METHOD == method) {
107
+ delete contexts[object_id];
108
+ respond_with_data(res, true, start);
90
109
  } else {
91
- Promise.resolve(klass[method].apply(null, input)).then(function (result) {
110
+ Promise.resolve(klass[method].apply(null, input)).then((result) => {
92
111
  respond_with_data(res, result, start);
93
- }).catch(function(error) {
112
+ }).catch((error) => {
94
113
  respond_with_error(res, 500, error);
95
114
  });
96
115
  }
@@ -103,12 +122,12 @@ module.exports = (function() {
103
122
 
104
123
  //server.maxConnections = 64;
105
124
  server.listen(socket, () => {
106
- log(`server ready, listening on ${socket} (max connections: ${server.maxConnections})`);
125
+ debug(`server ready, listening on ${socket} (max connections: ${server.maxConnections})`);
107
126
  });
108
127
  },
109
128
 
110
129
  close: (finalizer) => {
111
- log("Shutting down");
130
+ debug("Shutting down");
112
131
  if (!closing) {
113
132
  closing = true;
114
133
  server.close(finalizer);
@@ -116,5 +135,5 @@ module.exports = (function() {
116
135
  }
117
136
  };
118
137
 
119
- return { core: core, log: log };
138
+ return { core: core, debug: debug };
120
139
  })();
data/lib/nodo/railtie.rb CHANGED
@@ -3,6 +3,7 @@ require 'active_support'
3
3
 
4
4
  class Nodo::Railtie < Rails::Railtie
5
5
  initializer 'nodo' do |app|
6
- Nodo.modules_root = Rails.root.join('vendor', 'node_modules')
6
+ Nodo.env['NODE_ENV'] = Rails.env.to_s
7
+ Nodo.logger = Rails.logger
7
8
  end
8
9
  end
data/lib/nodo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Nodo
2
- VERSION = '1.5.5'
2
+ VERSION = '1.6.2'
3
3
  end
data/lib/nodo.rb CHANGED
@@ -3,16 +3,20 @@ require 'json'
3
3
  require 'fileutils'
4
4
  require 'tmpdir'
5
5
  require 'tempfile'
6
+ require 'logger'
6
7
  require 'socket'
7
8
  require 'forwardable'
8
9
 
9
10
  module Nodo
10
11
  class << self
11
- attr_accessor :modules_root, :env, :binary
12
+ attr_accessor :modules_root, :env, :binary, :logger, :debug, :timeout
12
13
  end
13
14
  self.modules_root = './node_modules'
14
15
  self.env = {}
15
16
  self.binary = 'node'
17
+ self.logger = Logger.new(STDOUT)
18
+ self.debug = false
19
+ self.timeout = 60
16
20
  end
17
21
 
18
22
  require_relative 'nodo/version'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nodo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.5
4
+ version: 1.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthias Grosser