rhoconnect 4.0.0.beta.12 → 4.0.0.beta.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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)
|