rhoconnect 4.0.0.beta.12 → 4.0.0.beta.24
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +34 -0
- data/Gemfile +5 -8
- data/Gemfile.lock +34 -32
- data/Rakefile +2 -12
- data/bench/run_bench.sh +1 -1
- data/bench/spec/bench_spec_helper.rb +3 -5
- data/bin/rhoconnect +20 -13
- data/commands/dtach/dtach_install.rb +3 -3
- data/commands/generators/update.rb +1 -0
- data/commands/parser.rb +180 -0
- data/commands/rhoconnect/config.rb +8 -4
- data/commands/rhoconnect/get_token.rb +3 -1
- data/commands/rhoconnect/routes.rb +34 -0
- data/commands/rhoconnect/secret.rb +1 -1
- data/commands/rhoconnect/set_admin_password.rb +2 -1
- data/commands/rhoconnect/startbg.rb +4 -4
- data/commands/rhoconnect/stop.rb +2 -2
- data/commands/rhoconnect_console/console.rb +6 -6
- data/commands/rhoconnect_spec/spec.rb +2 -1
- data/commands/rhoconnect_war/war.rb +1 -0
- data/commands/utilities/redis_runner.rb +2 -2
- data/doc/data-partitioning.txt +20 -7
- data/doc/extending-rhoconnect-server.txt +36 -7
- data/doc/push-client-setup-rps.txt +3 -3
- data/doc/source-adapters-js.txt +41 -4
- data/doc/source-adapters.txt +3 -0
- data/generators/templates/application/rcgemfile +1 -5
- data/generators/templates/application/spec/spec_helper.rb +0 -9
- data/generators/templates/source/models/js/model.js +8 -0
- data/generators/templates/source/models/ruby/model.rb +5 -11
- data/install.sh +2 -2
- data/installer/unix-like/rho_connect_install_constants.rb +3 -3
- data/installer/utils/delete_from_s3.rb +3 -6
- data/installer/utils/download_from_s3.rb +5 -9
- data/installer/utils/verify_checksum.rb +16 -11
- data/js-adapters/ballroom.js +9 -0
- data/js-adapters/exceptions.js +60 -0
- data/js-adapters/node.rb +14 -5
- data/js-adapters/node_channel.rb +68 -48
- data/js-adapters/rhoconnect_helpers.js +8 -2
- data/js-adapters/router.js +16 -14
- data/lib/rhoconnect.rb +5 -5
- data/lib/rhoconnect/client.rb +2 -2
- data/lib/rhoconnect/condition/add_parameter.rb +21 -0
- data/lib/rhoconnect/controller/clients_controller.rb +1 -1
- data/lib/rhoconnect/controller/js_base.rb +1 -2
- data/lib/rhoconnect/controller/system_controller.rb +33 -10
- data/lib/rhoconnect/db_adapter.rb +1 -1
- data/lib/rhoconnect/document.rb +11 -3
- data/lib/rhoconnect/handler/changes.rb +20 -19
- data/lib/rhoconnect/handler/changes/engine.rb +48 -25
- data/lib/rhoconnect/handler/changes/hooks.rb +36 -0
- data/lib/rhoconnect/handler/changes/runner.rb +12 -2
- data/lib/rhoconnect/handler/helpers.rb +4 -4
- data/lib/rhoconnect/jobs/source_job.rb +1 -1
- data/lib/rhoconnect/model/base.rb +32 -8
- data/lib/rhoconnect/model/helpers.rb +15 -0
- data/lib/rhoconnect/model/helpers/find_duplicates_on_update.rb +85 -0
- data/lib/rhoconnect/model/js_base.rb +23 -28
- data/lib/rhoconnect/server.rb +23 -18
- data/lib/rhoconnect/source.rb +10 -17
- data/lib/rhoconnect/store.rb +36 -57
- data/lib/rhoconnect/test_methods.rb +5 -4
- data/lib/rhoconnect/utilities.rb +7 -5
- data/lib/rhoconnect/version.rb +2 -2
- data/lib/rhoconnect/web-console/server.rb +17 -16
- data/rhoconnect.gemspec +23 -24
- data/spec/apps/rhotestapp/controllers/js/js_sample_controller.js +4 -0
- data/spec/apps/rhotestapp/models/js/js_sample.js +36 -0
- data/spec/apps/rhotestapp/models/ruby/sample_adapter.rb +34 -19
- data/spec/async_spec.rb +1 -1
- data/spec/cli/cli_spec.rb +69 -31
- data/spec/client_sync_spec.rb +30 -13
- data/spec/controllers/js_base_spec.rb +10 -4
- data/spec/jobs/source_job_spec.rb +1 -1
- data/spec/models/{js_model_spec.rb → js_base_spec.rb} +63 -13
- data/spec/server/server_spec.rb +20 -0
- data/spec/server/stats_spec.rb +7 -17
- data/spec/source_adapter_spec.rb +6 -0
- data/spec/source_sync_spec.rb +219 -54
- data/spec/spec_helper.rb +8 -13
- data/spec/store_spec.rb +6 -4
- data/spec/test_methods_spec.rb +4 -4
- metadata +14 -27
- data/commands/execute.rb +0 -48
- data/commands/utilities/utilities.rb +0 -6
- data/generators/templates/application/controllers/application_controller.rb +0 -17
- data/lib/rhoconnect/js_adapter.rb +0 -79
@@ -5,15 +5,12 @@
|
|
5
5
|
gem 'win32-process', '= 0.6.6', :platforms => [:mswin, :mingw]
|
6
6
|
|
7
7
|
# use thin and eventmachine everywhere except JRuby
|
8
|
-
platforms :ruby, :
|
8
|
+
platforms :ruby, :mingw do
|
9
9
|
gem "eventmachine", "~> 1.0.0"
|
10
10
|
# using thin by default
|
11
11
|
gem 'thin'
|
12
|
-
end
|
13
|
-
|
14
12
|
# for async framework
|
15
13
|
# for Async, Eventful execution
|
16
|
-
platforms :ruby_19, :mingw_19 do
|
17
14
|
gem 'rack-fiber_pool'
|
18
15
|
gem 'async-rack'
|
19
16
|
end
|
@@ -37,5 +34,4 @@ group :test do
|
|
37
34
|
gem 'rspec', '~> 2.10.0'
|
38
35
|
gem 'rack-test', '>= 0.5.3', :require => "rack/test"
|
39
36
|
gem 'rhomobile-debug', ">= 1.0.2"
|
40
|
-
gem 'capybara'
|
41
37
|
end
|
@@ -17,15 +17,6 @@ include Rhoconnect
|
|
17
17
|
require 'rhoconnect/application/init'
|
18
18
|
require 'rhoconnect/test_methods'
|
19
19
|
|
20
|
-
require 'capybara'
|
21
|
-
require 'capybara/dsl'
|
22
|
-
|
23
|
-
Capybara.app = Sinatra::Application
|
24
|
-
|
25
|
-
RSpec.configure do |config|
|
26
|
-
config.include Capybara
|
27
|
-
end
|
28
|
-
|
29
20
|
shared_examples_for "SpecHelper" do
|
30
21
|
include Rhoconnect::TestMethods
|
31
22
|
|
@@ -43,6 +43,14 @@ var <%=class_name%> = function(){
|
|
43
43
|
// TODO: Logout from the data source if necessary.
|
44
44
|
resp.send(true);
|
45
45
|
};
|
46
|
+
|
47
|
+
this.storeBlob = function(resp){
|
48
|
+
// TODO: Handle post requests for blobs here.
|
49
|
+
// Reference the blob object's path with resp.params.path.
|
50
|
+
new rc.Exception(
|
51
|
+
resp, "Please provide some code to handle blobs if you are using them."
|
52
|
+
);
|
53
|
+
};
|
46
54
|
};
|
47
55
|
|
48
56
|
module.exports = new <%=class_name%>();
|
@@ -38,15 +38,9 @@ class <%=class_name%> < Rhoconnect::Model::Base
|
|
38
38
|
# TODO: Logout from the data source if necessary
|
39
39
|
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
# Uncomment this code and override it by creating a copy of the file somewhere
|
47
|
-
# and returning the path to that file (then don't call super!):
|
48
|
-
# i.e. /mnt/myimages/soccer.png
|
49
|
-
#def store_blob(object,field_name,blob)
|
50
|
-
# super #=> returns blob[:tempfile]
|
51
|
-
#end
|
41
|
+
def store_blob(object,field_name,blob)
|
42
|
+
# TODO: Handle post requests for blobs here.
|
43
|
+
# make sure you store the blob object somewhere permanently
|
44
|
+
raise "Please provide some code to handle blobs if you are using them."
|
45
|
+
end
|
52
46
|
end
|
data/install.sh
CHANGED
@@ -258,10 +258,10 @@ rubyVersion=""
|
|
258
258
|
rubyBinDir=""
|
259
259
|
|
260
260
|
# Define ruby and nodejs versions to be installed ...
|
261
|
-
RUBY_PATCH="
|
261
|
+
RUBY_PATCH="p429"
|
262
262
|
RUBY_VERSION="ruby-1.9.3-${RUBY_PATCH}"
|
263
263
|
|
264
|
-
NODE_VERSION=v0.10.
|
264
|
+
NODE_VERSION=v0.10.5
|
265
265
|
NODE_URL=http://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}.tar.gz
|
266
266
|
ARCH=$([[ `uname -m` == x86_64 ]] && echo "x64" || echo "x86")
|
267
267
|
NODE_BIN_URL=http://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-${ARCH}.tar.gz
|
@@ -8,10 +8,10 @@ module Constants
|
|
8
8
|
"libaprutil1-dev",
|
9
9
|
"dtach"]
|
10
10
|
|
11
|
-
RUBY = "ruby-1.9.3-
|
12
|
-
REDIS = "redis-2.6.
|
11
|
+
RUBY = "ruby-1.9.3-p429"
|
12
|
+
REDIS = "redis-2.6.13"
|
13
13
|
SQLITE3 = "sqlite-autoconf-3071502"
|
14
|
-
NGINX = "nginx-1.
|
14
|
+
NGINX = "nginx-1.4.1"
|
15
15
|
PASSENGER_ROOT = "/opt/rhoconnect/lib/ruby/gems/1.9.1/gems/passenger"
|
16
16
|
|
17
17
|
SOFTWARE = [ REDIS, SQLITE3, RUBY, NGINX ]
|
@@ -9,7 +9,6 @@ USER_DATA = `wget -q -O - http://169.254.169.254/latest/user-data`.split("\n")
|
|
9
9
|
|
10
10
|
bucket_name = ARGV[0].strip
|
11
11
|
channel = ARGV[1].strip
|
12
|
-
files = []
|
13
12
|
|
14
13
|
def get_access_keys
|
15
14
|
access_key = USER_DATA[0].to_s.strip
|
@@ -20,11 +19,9 @@ end #get_access_keys
|
|
20
19
|
|
21
20
|
AWS::S3::Base.establish_connection!(get_access_keys)
|
22
21
|
|
23
|
-
objects = Bucket.objects(bucket_name)
|
24
|
-
|
25
|
-
objects.each
|
26
|
-
files << "#{obj.key}" if obj.key =~ /^#{channel}/
|
27
|
-
end
|
22
|
+
objects = Bucket.objects(bucket_name, :prefix => channel)
|
23
|
+
files = []
|
24
|
+
objects.each { |obj| files << "#{obj.key}" }
|
28
25
|
|
29
26
|
files.each do |file|
|
30
27
|
puts "Deleting #{file}"
|
@@ -9,7 +9,6 @@ USER_DATA = `wget -q -O - http://169.254.169.254/latest/user-data`.split("\n")
|
|
9
9
|
|
10
10
|
bucket_name = 'rhoconnect'
|
11
11
|
channel = ARGV[0]
|
12
|
-
files = []
|
13
12
|
|
14
13
|
exit if ARGV.length != 1
|
15
14
|
|
@@ -21,16 +20,13 @@ end #cmd
|
|
21
20
|
def get_access_keys
|
22
21
|
access_key = USER_DATA[0].to_s.strip
|
23
22
|
secret_access_key = USER_DATA[1].to_s.strip
|
24
|
-
keys = { :access_key_id => access_key,
|
25
|
-
|
26
|
-
end #get_access_keys
|
23
|
+
keys = { :access_key_id => access_key, :secret_access_key => secret_access_key}
|
24
|
+
end
|
27
25
|
|
28
26
|
AWS::S3::Base.establish_connection!(get_access_keys)
|
29
|
-
|
30
|
-
|
31
|
-
objects.each
|
32
|
-
files << "#{obj.key}" if obj.key =~ /^#{channel}/
|
33
|
-
end
|
27
|
+
objects = Bucket.objects(bucket_name, :prefix => channel)
|
28
|
+
files = []
|
29
|
+
objects.each { |obj| files << "#{obj.key}" }
|
34
30
|
|
35
31
|
# Remove the files before downloading new in case they already exist
|
36
32
|
cmd "rm -rf #{channel}" if File.directory? channel
|
@@ -25,25 +25,30 @@ dir_to_compare = ARGV[1]
|
|
25
25
|
|
26
26
|
# Downoad Packages from S3
|
27
27
|
cmd "ruby ./installer/utils/download_from_s3.rb #{dir_to_compare}"
|
28
|
-
|
29
28
|
# Create the checksum to compare against the one from the S3 repo
|
30
29
|
cmd "ruby ./installer/utils/create_sha1.rb #{dir_to_compare} ."
|
30
|
+
old_sha1_h = YAML.load(File.read(checksum_hash))
|
31
|
+
new_sha1_h = YAML.load(File.read("./sha1_hash"))
|
32
|
+
|
33
|
+
match = true
|
34
|
+
old_sha1_h.each do |k,v|
|
35
|
+
unless new_sha1_h[k]
|
36
|
+
puts "Error! Checksum mismatch for file #{v}"
|
37
|
+
match = false
|
38
|
+
end
|
39
|
+
end
|
31
40
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
if checksum(old_sha1_h.keys) != checksum(new_sha1_h.keys)
|
41
|
+
unless match
|
42
|
+
puts
|
36
43
|
puts "Checksums do not match!"
|
37
|
-
|
38
44
|
puts "Expected sha1/file"
|
39
|
-
old_sha1_h = YAML.load(File.read(checksum_hash)).sort
|
45
|
+
old_sha1_h = YAML.load(File.read(checksum_hash)).sort
|
40
46
|
old_sha1_h.each { |k,v| puts "#{k}: #{v}" }
|
41
|
-
|
42
47
|
puts "Got sha1/file"
|
43
|
-
new_sha1_h = YAML.load(File.read("./sha1_hash")).sort
|
48
|
+
new_sha1_h = YAML.load(File.read("./sha1_hash")).sort
|
44
49
|
new_sha1_h.each { |k,v| puts "#{k}: #{v}" }
|
45
|
-
|
50
|
+
puts
|
46
51
|
exit 2
|
47
|
-
end
|
52
|
+
end
|
48
53
|
|
49
54
|
puts "Checksums match!"
|
data/js-adapters/ballroom.js
CHANGED
@@ -19,6 +19,15 @@ var _m_name = null;
|
|
19
19
|
//TODO: Don't have test-specific code here
|
20
20
|
var prefixDir = '/spec/apps/rhotestapp';
|
21
21
|
|
22
|
+
//TODO: This has to be changed in the future
|
23
|
+
// The only reason for this - on Windows Node.js
|
24
|
+
// dies and leaves hanging opened sockets
|
25
|
+
// Proper way: have a global domain as a safety valve
|
26
|
+
process.on('uncaughtException', function(err) {
|
27
|
+
client_sub.quit();
|
28
|
+
client_pub.quit();
|
29
|
+
});
|
30
|
+
|
22
31
|
var controllerName = function(n){
|
23
32
|
_c_name = n;
|
24
33
|
registeredControllers[_c_name] = {};
|
@@ -0,0 +1,60 @@
|
|
1
|
+
var util = require('util');
|
2
|
+
|
3
|
+
//Setup exception handlers
|
4
|
+
var AbstractException = function (resp,msg,constr) {
|
5
|
+
Error.captureStackTrace(this, constr || this);
|
6
|
+
this.message = msg || 'Error';
|
7
|
+
resp.exception = {"error": {"error_type": this.name, "message": this.message, "stacktrace": this.stack} };
|
8
|
+
resp.send(null);
|
9
|
+
};
|
10
|
+
|
11
|
+
var Exception = function (resp,msg) {
|
12
|
+
Exception.super_.call(this, resp, msg, this.constructor);
|
13
|
+
};
|
14
|
+
|
15
|
+
var LoginException = function (resp,msg) {
|
16
|
+
LoginException.super_.call(this, resp, msg, this.constructor);
|
17
|
+
};
|
18
|
+
|
19
|
+
var LogoffException = function (resp,msg) {
|
20
|
+
LogoffException.super_.call(this, resp, msg, this.constructor);
|
21
|
+
};
|
22
|
+
|
23
|
+
var ServerTimeoutException = function (resp,msg) {
|
24
|
+
ServerTimeoutException.super_.call(this, resp, msg, this.constructor);
|
25
|
+
};
|
26
|
+
|
27
|
+
var ServerErrorException = function (resp,msg) {
|
28
|
+
ServerErrorException.super_.call(this, resp, msg, this.constructor);
|
29
|
+
};
|
30
|
+
|
31
|
+
var ObjectConflictErrorException = function (resp,msg) {
|
32
|
+
ObjectConflictErrorException.super_.call(this, resp, msg, this.constructor);
|
33
|
+
};
|
34
|
+
|
35
|
+
// Setup the types for each exception
|
36
|
+
util.inherits(AbstractException, Error);
|
37
|
+
util.inherits(Exception, AbstractException);
|
38
|
+
util.inherits(LoginException, AbstractException);
|
39
|
+
util.inherits(LogoffException, AbstractException);
|
40
|
+
util.inherits(ServerTimeoutException, AbstractException);
|
41
|
+
util.inherits(ServerErrorException, AbstractException);
|
42
|
+
util.inherits(ObjectConflictErrorException, AbstractException);
|
43
|
+
|
44
|
+
|
45
|
+
// Default names
|
46
|
+
AbstractException.prototype.name = 'AbstractException';
|
47
|
+
Exception.prototype.name = 'Exception';
|
48
|
+
LoginException.prototype.name = 'LoginException';
|
49
|
+
LogoffException.prototype.name = 'LogoffException';
|
50
|
+
ServerTimeoutException.prototype.name = 'ServerTimeoutException';
|
51
|
+
ServerErrorException.prototype.name = 'ServerErrorException';
|
52
|
+
ObjectConflictErrorException.prototype.name = 'ObjectConflictErrorException';
|
53
|
+
|
54
|
+
// Public exceptions
|
55
|
+
module.exports.Exception = Exception;
|
56
|
+
module.exports.LoginException = LoginException;
|
57
|
+
module.exports.LogoffException = LogoffException;
|
58
|
+
module.exports.ServerTimeoutException = ServerTimeoutException;
|
59
|
+
module.exports.ServerErrorException = ServerErrorException;
|
60
|
+
module.exports.ObjectConflictErrorException = ObjectConflictErrorException;
|
data/js-adapters/node.rb
CHANGED
@@ -7,7 +7,7 @@ module Rhoconnect
|
|
7
7
|
@started = false
|
8
8
|
@pipe = nil
|
9
9
|
|
10
|
-
def self.shell_node
|
10
|
+
def self.shell_node(opts = {})
|
11
11
|
package_file = File.join(Dir.pwd,'package.json')
|
12
12
|
if not File.exists?(package_file)
|
13
13
|
Rhoconnect.use_node = false
|
@@ -18,7 +18,7 @@ module Rhoconnect
|
|
18
18
|
if which("node")
|
19
19
|
begin
|
20
20
|
if @started
|
21
|
-
kill_process
|
21
|
+
kill_process(opts)
|
22
22
|
end
|
23
23
|
@started = true
|
24
24
|
dir = File.expand_path(File.dirname(__FILE__))
|
@@ -28,7 +28,7 @@ module Rhoconnect
|
|
28
28
|
file = File.join(dir,"server.js")
|
29
29
|
args = [sub_env, "node", file, "#{$$}", Rhoconnect.environment.to_s]
|
30
30
|
@pipe = IO.popen(args)
|
31
|
-
log "
|
31
|
+
log "Starting Node.js process: #{@pipe.pid}"
|
32
32
|
@pipe
|
33
33
|
rescue Exception=>e
|
34
34
|
puts "Node.js startup error: #{e.message}\n"
|
@@ -41,9 +41,18 @@ module Rhoconnect
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
def self.kill_process
|
44
|
+
def self.kill_process(opts = {})
|
45
45
|
log "Stopping Node.js process: #{@pipe.pid}" if @pipe
|
46
|
-
|
46
|
+
if opts[:force]
|
47
|
+
begin
|
48
|
+
Process.kill('KILL', @pipe.pid)
|
49
|
+
Process.waitpid(@pipe.pid)
|
50
|
+
rescue
|
51
|
+
# Process not found, don't worry about killing it
|
52
|
+
end
|
53
|
+
else
|
54
|
+
NodeChannel.exit_node
|
55
|
+
end
|
47
56
|
@started = false
|
48
57
|
@pipe = nil
|
49
58
|
end
|
data/js-adapters/node_channel.rb
CHANGED
@@ -11,7 +11,7 @@ module Rhoconnect
|
|
11
11
|
TIMEOUT = 30 # seconds
|
12
12
|
PUB_CHANNEL = "#{$$}RedisSUB" # pub channel must link to redis sub channel
|
13
13
|
SUB_CHANNEL = "#{$$}RedisPUB" # sub channel must link to redis pub channel
|
14
|
-
@message_thread,@
|
14
|
+
@message_thread,@redis_subscriber,@redis_publisher = nil
|
15
15
|
|
16
16
|
class << self
|
17
17
|
attr_accessor :thrd, :register_semaphore, :register_condition
|
@@ -20,22 +20,22 @@ module Rhoconnect
|
|
20
20
|
TIMEOUT
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
23
|
+
def redis_subscriber
|
24
24
|
url = Rhoconnect.redis.is_a?(Array) ? Rhoconnect.redis[0] : Rhoconnect.redis
|
25
25
|
db_inst = RedisImpl.new
|
26
26
|
db_inst.create(url)
|
27
|
-
@
|
27
|
+
@redis_subscriber ||= db_inst.db
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
30
|
+
def redis_publisher
|
31
31
|
url = Rhoconnect.redis.is_a?(Array) ? Rhoconnect.redis[0] : Rhoconnect.redis
|
32
32
|
db_inst = RedisImpl.new
|
33
33
|
db_inst.create(url)
|
34
|
-
@
|
34
|
+
@redis_publisher ||= db_inst.db
|
35
35
|
end
|
36
36
|
|
37
37
|
def exit_node
|
38
|
-
NodeChannel.
|
38
|
+
NodeChannel.redis_publisher.publish(PUB_CHANNEL,{:route => 'deregister'}.to_json)
|
39
39
|
end
|
40
40
|
|
41
41
|
def bootstrap
|
@@ -54,58 +54,85 @@ module Rhoconnect
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def publish_channel_and_wait(msg,curr_model)
|
57
|
-
unique_id =
|
57
|
+
unique_id = get_random_uuid
|
58
58
|
msg.merge!(:request_id => unique_id)
|
59
59
|
RESULT_HASH[unique_id] = {}
|
60
60
|
RESULT_HASH[unique_id][:status] = 'waiting'
|
61
|
-
|
62
|
-
NodeChannel.wait_for_result(unique_id,curr_model)
|
61
|
+
publish_channel(PUB_CHANNEL,msg,unique_id,curr_model)
|
63
62
|
end
|
64
63
|
|
65
64
|
def check_channel
|
66
|
-
NodeChannel.
|
65
|
+
NodeChannel.redis_subscriber.subscribe(SUB_CHANNEL) do |on|
|
67
66
|
on.message do |channel,msg|
|
68
67
|
m = JSON.parse(msg)
|
69
|
-
#puts "received message: #{m.inspect}"
|
70
68
|
if m['exit'] == true
|
71
|
-
NodeChannel.
|
69
|
+
NodeChannel.redis_subscriber.unsubscribe
|
72
70
|
end
|
73
71
|
route_message(m)
|
74
72
|
end
|
75
73
|
end
|
76
74
|
end
|
77
75
|
|
78
|
-
def publish_channel(msg)
|
79
|
-
|
76
|
+
def publish_channel(channel,msg,unique_id = nil,curr_model = nil)
|
77
|
+
result = {}
|
78
|
+
num_clients = NodeChannel.redis_publisher.publish(channel,msg.to_json)
|
79
|
+
if num_clients >= 1
|
80
|
+
result = NodeChannel.wait_for_result(unique_id,curr_model) if unique_id and curr_model
|
81
|
+
else
|
82
|
+
log "ERROR: Cannot communicate with Node.js process."
|
83
|
+
if Rhoconnect.restart_node_on_error
|
84
|
+
t = Thread.new do
|
85
|
+
# Shutdown our ruby subscription by issuing redis channel instruction
|
86
|
+
NodeChannel.redis_subscriber.publish(SUB_CHANNEL,{'exit' => true}.to_json)
|
87
|
+
end
|
88
|
+
t.join
|
89
|
+
Rhoconnect.start_nodejs_channels(force: true)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
result
|
80
93
|
end
|
81
94
|
|
82
95
|
def wait_for_result(key,curr_model)
|
83
96
|
begin
|
84
97
|
Timeout::timeout(TIMEOUT) do
|
85
98
|
while(RESULT_HASH[key][:status] == 'waiting') do
|
86
|
-
if
|
99
|
+
if RESULT_HASH[key][:pending_js_requests] and result_id = RESULT_HASH[key][:pending_js_requests][0]
|
87
100
|
#do some logic and return data with memory
|
88
|
-
|
89
|
-
|
90
|
-
RESULT_HASH[key][:
|
91
|
-
|
92
|
-
|
101
|
+
data = RESULT_HASH[key][result_id][:process_request]
|
102
|
+
msg_result = process_message(curr_model,data)
|
103
|
+
RESULT_HASH[key][result_id][:process_result] = msg_result
|
104
|
+
RESULT_HASH[key][:pending_js_requests] = RESULT_HASH[key][:pending_js_requests].drop(1)
|
105
|
+
if RESULT_HASH[key][:pending_js_requests].length == 0 and not RESULT_HASH[key][:result].nil?
|
106
|
+
RESULT_HASH[key][:status] = 'done'
|
107
|
+
end
|
108
|
+
publish_channel(PUB_CHANNEL,msg_result)
|
93
109
|
end
|
110
|
+
Thread.pass
|
94
111
|
end
|
95
112
|
end
|
96
113
|
rescue Exception=>e
|
97
114
|
RESULT_HASH[key][:status] = 'broken'
|
98
115
|
RESULT_HASH[key][:result] = "exception #{e.message}\n#{e.backtrace}"
|
99
|
-
log "Timeout on wait, setting JavaScript result state to broken: #{e.
|
116
|
+
log "Timeout on wait, setting JavaScript result state to broken: #{e.message}"
|
100
117
|
log e.backtrace.join("\n")
|
101
118
|
end
|
102
|
-
|
103
119
|
#request waiting either timed out or returned response
|
120
|
+
res = {}
|
104
121
|
if RESULT_HASH[key][:status] == 'broken' or RESULT_HASH[key][:status] == 'waiting'
|
105
122
|
res = RESULT_HASH.delete(key)
|
106
|
-
elsif RESULT_HASH[key]
|
107
|
-
|
108
|
-
|
123
|
+
elsif RESULT_HASH[key] and RESULT_HASH[key][:result].is_a?(Hash) and RESULT_HASH[key][:result]['error_type']
|
124
|
+
include Rhoconnect::Model
|
125
|
+
res = RESULT_HASH.delete(key)[:result]
|
126
|
+
klass = res['error_type']
|
127
|
+
exception = nil
|
128
|
+
|
129
|
+
if klass and const_defined?(klass)
|
130
|
+
exception = const_get(klass).new(res['message'])
|
131
|
+
else
|
132
|
+
exception = Exception.new(res['message'])
|
133
|
+
end
|
134
|
+
exception.set_backtrace(res['stacktrace'].split("\n"))
|
135
|
+
raise exception
|
109
136
|
else
|
110
137
|
res = RESULT_HASH.delete(key)
|
111
138
|
end
|
@@ -115,25 +142,31 @@ module Rhoconnect
|
|
115
142
|
def route_message(msg)
|
116
143
|
case msg['route']
|
117
144
|
when 'request'
|
118
|
-
|
119
|
-
RESULT_HASH[msg['request_id']][:
|
120
|
-
|
145
|
+
result_id = get_random_uuid
|
146
|
+
RESULT_HASH[msg['request_id']][:pending_js_requests] ||= []
|
147
|
+
RESULT_HASH[msg['request_id']][:pending_js_requests] << result_id
|
148
|
+
RESULT_HASH[msg['request_id']][result_id] = {}
|
149
|
+
RESULT_HASH[msg['request_id']][result_id][:process_result] = 'waiting'
|
150
|
+
RESULT_HASH[msg['request_id']][result_id][:process_request] = msg
|
121
151
|
when 'response'
|
122
152
|
return if RESULT_HASH[msg['request_id']] == nil
|
123
153
|
if msg['error'] and msg['error'].size > 1
|
124
|
-
RESULT_HASH[msg['request_id']][:result] =
|
154
|
+
RESULT_HASH[msg['request_id']][:result] = msg['error']
|
125
155
|
RESULT_HASH[msg['request_id']][:status] = 'done'
|
126
156
|
else
|
127
157
|
RESULT_HASH[msg['request_id']][:result] = msg["result"]
|
128
|
-
RESULT_HASH[msg['request_id']][:
|
158
|
+
pending_js_requests = RESULT_HASH[msg['request_id']][:pending_js_requests]
|
159
|
+
if not pending_js_requests or pending_js_requests.length == 0
|
160
|
+
RESULT_HASH[msg['request_id']][:status] = 'done'
|
161
|
+
end
|
129
162
|
end
|
130
163
|
when 'register'
|
131
164
|
@register_semaphore.synchronize do
|
132
165
|
begin
|
133
166
|
register_routes(msg)
|
134
167
|
rescue Exception => e
|
135
|
-
|
136
|
-
|
168
|
+
log "Error registering JavaScript routes: #{e.inspect}"
|
169
|
+
log e.backtrace.join("\n")
|
137
170
|
raise e
|
138
171
|
ensure
|
139
172
|
@register_condition.signal
|
@@ -142,25 +175,14 @@ module Rhoconnect
|
|
142
175
|
end
|
143
176
|
end
|
144
177
|
|
145
|
-
def wait_for_process_result(key)
|
146
|
-
Timeout::timeout(TIMEOUT){
|
147
|
-
while(RESULT_HASH[key][:process_result] == 'waiting') do
|
148
|
-
sleep 0.001
|
149
|
-
end
|
150
|
-
}
|
151
|
-
publish_channel(RESULT_HASH[key][:process_result])
|
152
|
-
end
|
153
|
-
|
154
178
|
def process_message(curr_model,data)
|
155
|
-
# puts "proccessing msg #{data.inspect}"
|
156
179
|
klass = curr_model
|
157
180
|
klass = Object.const_get(data['kls']) if data['kls']
|
158
181
|
if klass.respond_to?(data['function'].to_sym)
|
159
182
|
if data['args'] and data['args'].size > 0
|
160
183
|
if(data['function'] == 'stash_result')
|
161
184
|
klass.send('result=',data['args'])
|
162
|
-
klass.send(data['function'])
|
163
|
-
process_res = nil
|
185
|
+
res = klass.send(data['function'])
|
164
186
|
else
|
165
187
|
res = klass.send(data['function'],*data['args'])
|
166
188
|
end
|
@@ -171,12 +193,10 @@ module Rhoconnect
|
|
171
193
|
raise Exception.new("Method #{data['function']} not found in model #{curr_model.class.name.to_s}.")
|
172
194
|
end
|
173
195
|
|
174
|
-
process_res = res
|
175
196
|
unless res.is_a?(String) or res.is_a?(TrueClass) or res.is_a?(FalseClass) or res.nil?
|
176
|
-
|
197
|
+
res = res.to_hash
|
177
198
|
end
|
178
|
-
|
179
|
-
{:result=>process_res,:callback=>data['callback'],:request_id=>data['request_id'],:route=>'response'}
|
199
|
+
{:result=>res,:callback=>data['callback'],:request_id=>data['request_id'],:route=>'response'}
|
180
200
|
end
|
181
201
|
|
182
202
|
def register_routes(hsh)
|