rjr 0.17.1 → 0.18.1

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
  SHA1:
3
- metadata.gz: df6830242efa865dde4af4008827688172011746
4
- data.tar.gz: 33c559f6fa14957b7aa5929f3030ab4455e93b8e
3
+ metadata.gz: f5a404d0bde0749357c01f0e57696e73ff39ea6d
4
+ data.tar.gz: 0c5394cf7df7774def9553b772c1cb92c53504de
5
5
  SHA512:
6
- metadata.gz: 240533c8a5aafa5980337b18fae10bf4f24a9e72e93ce6e88f42c82169ee81fbb5f850a5817a6ed1091f9ed62e96145e3b478f67b2122c15c39dbf13a29ff131
7
- data.tar.gz: 56ef3f372c94eead71df0d5b534122a244c3602b4aab84c3c181d40711066c8ab7da303f3cb8f676531d6150e0f1c6be0c2836320bbda749a53f3451cdc7f5f0
6
+ metadata.gz: cf24b7e0fc705957af5ffe74879ab053a78393f33b28070cde205cb04a3879282d492dec85efd29938a6f51c27bee5a1ec3b6b6294e683d6bed7ed1cc0dfb1bb
7
+ data.tar.gz: ed2bf6a3203387e00aeb5c84f0d836c50833ddd4901c581085ae66c8b286cddbba356ea0023bf8cbd6221c5b693a5508675ad9697f70023cdc319dd6f1f58335
data/examples/unix.rb ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/ruby
2
+ # A RJR unix-node example
3
+ #
4
+ # Copyright (C) 2013 Mohammed Morsi <mo@morsi.org>
5
+ # Licensed under the Apache License, Version 2.0
6
+
7
+ require 'rjr/nodes/unix'
8
+
9
+ server = RJR::Nodes::Unix.new :socketname => './server.sock', :node_id => "server"
10
+ server.dispatcher.handle('method') { |i|
11
+ puts "server: #{i}"
12
+ @rjr_callback.notify "callback", i.downcase
13
+ "#{i}".upcase
14
+ }
15
+ server.listen
16
+
17
+ client = RJR::Nodes::Unix.new :node_id => "client"
18
+ client.dispatcher.handle('callback') { |i|
19
+ puts "callback: #{i}"
20
+ #client.halt
21
+ }
22
+
23
+ client.notify "./server.sock", "method", "Hello World"
24
+ # => nil
25
+
26
+ client.invoke "./server.sock", "method", "Hello World"
27
+ # => HELLO WORLD
28
+
29
+ #client.join
@@ -0,0 +1 @@
1
+ # TODO read/write jsonrpc from a watched file (eg EM's inotify interface)
data/lib/rjr/nodes/tcp.rb CHANGED
@@ -16,7 +16,7 @@ module RJR
16
16
  module Nodes
17
17
 
18
18
  # @private
19
- # Helper class intialized by eventmachine encapsulating a socket connection
19
+ # Helper class intialized by eventmachine encapsulating a tcp socket connection
20
20
  class TCPConnection < EventMachine::Connection
21
21
  attr_reader :host
22
22
  attr_reader :port
@@ -209,7 +209,7 @@ class TCP < RJR::Node
209
209
  #sleep 0.01 until conn.get_outbound_data_size == 0
210
210
  nil
211
211
  end
212
- end
212
+ end # class TCP
213
213
 
214
214
  end # module Nodes
215
215
  end # module RJR
@@ -0,0 +1,66 @@
1
+ # RJR Template Node
2
+ #
3
+ # Just serves as a minimal example of a node, should
4
+ # not be used. Developers can copy / base additional
5
+ # transport types off this template
6
+ #
7
+ # Copyright (C) 2013 Mohammed Morsi <mo@morsi.org>
8
+ # Licensed under the Apache License, Version 2.0
9
+
10
+ require 'rjr/node'
11
+
12
+ module RJR
13
+ module Nodes
14
+
15
+ class Template < RJR::Node
16
+ RJR_NODE_TYPE = :tpl
17
+
18
+ # Template Node Initializer
19
+ def initialize(args = {})
20
+ super(args)
21
+ end
22
+
23
+ def to_s
24
+ "RJR::Nodes::Template<>"
25
+ end
26
+
27
+ # Send data using specified connection
28
+ #
29
+ # Implementation of {RJR::Node#send_msg}
30
+ def send_msg(data, connection)
31
+ # TODO
32
+ end
33
+
34
+ # Instruct Node to start listening for and dispatching rpc requests
35
+ #
36
+ # Implementation of {RJR::Node#listen}
37
+ def listen
38
+ # TODO
39
+ self
40
+ end
41
+
42
+ # Instructs node to send rpc request, and wait for / return response.
43
+ #
44
+ # Implementation of {RJR::Node#invoke}
45
+ # @param [String] optional_destination if the transport requires it, param
46
+ # to specify the target of this request, if not remove this param
47
+ # @param [String] rpc_method json-rpc method to invoke on destination
48
+ # @param [Array] args array of arguments to convert to json and invoke remote method wtih
49
+ def invoke(optional_destination, rpc_method, *args)
50
+ # TODO
51
+ end
52
+
53
+ # Instructs node to send rpc notification (immadiately returns / no response is generated)
54
+ #
55
+ # Implementation of {RJR::Node#notify}
56
+ # @param [String] optional_destination if the transport requires it, param
57
+ # to specify the target of this request, if not remove this param
58
+ # @param [String] rpc_method json-rpc method to invoke on destination
59
+ # @param [Array] args array of arguments to convert to json and invoke remote method wtih
60
+ def notify(optional_destination, rpc_method, *args)
61
+ # TODO
62
+ end
63
+ end # class Template
64
+
65
+ end # module Nodes
66
+ end # module RJR
@@ -0,0 +1,192 @@
1
+ # RJR Unix Socket Node
2
+ #
3
+ # Implements the RJR::Node interface to issue and satisty JSON-RPC requests
4
+ # via Unix Sockets
5
+ #
6
+ # Copyright (C) 2013 Mohammed Morsi <mo@morsi.org>
7
+ # Licensed under the Apache License, Version 2.0
8
+
9
+ # TODO extract common bits between here &
10
+ # tcp node into common base socked module
11
+
12
+ require 'thread'
13
+ require 'eventmachine'
14
+
15
+ require 'rjr/node'
16
+ require 'rjr/message'
17
+
18
+ module RJR
19
+ module Nodes
20
+
21
+ # @private
22
+ # Helper class intialized by eventmachine encapsulating a unix socket connection
23
+ class UnixConnection < EventMachine::Connection
24
+ attr_reader :socketname
25
+
26
+ # UnixConnection intializer
27
+ #
28
+ # Specify the Unix Node establishing the connection and
29
+ # optionaly socketname which this connection is connected to
30
+ def initialize(args = {})
31
+ @rjr_node = args[:rjr_node]
32
+ @socketname = args[:socketname]
33
+
34
+ @send_lock = Mutex.new
35
+ @data = ""
36
+ end
37
+
38
+ # {EventMachine::Connection#receive_data} callback, handle request / response messages
39
+ def receive_data(data)
40
+ # a large json-rpc message may be split over multiple packets
41
+ # (invocations of receive_data)
42
+ # and multiple messages may be concatinated into one packet
43
+ @data += data
44
+ while extracted = MessageUtil.retrieve_json(@data)
45
+ msg, @data = *extracted
46
+ @rjr_node.send(:handle_message, msg, self) # XXX private method
47
+ end
48
+ end
49
+
50
+ # Send data safely using local connection
51
+ def send_msg(data)
52
+ @send_lock.synchronize{
53
+ Unix.em.schedule { send_data(data) }
54
+ }
55
+ end
56
+ end
57
+
58
+ # Unix node definition, listen for and invoke json-rpc requests via Unix Sockets
59
+ #
60
+ # Clients should specify the socketname when listening for requests and
61
+ # when invoking them.
62
+ #
63
+ # TODO client / server examples
64
+ #
65
+ class Unix < RJR::Node
66
+ RJR_NODE_TYPE = :unix
67
+
68
+ attr_accessor :connections
69
+
70
+ private
71
+ # Internal helper, initialize new client
72
+ def init_client(args={}, &on_init)
73
+ socketname = args[:socketname]
74
+ connection = nil
75
+ @connections_lock.synchronize {
76
+ connection = @connections.find { |c|
77
+ socketname == c.socketname
78
+ }
79
+ if connection.nil?
80
+ connection =
81
+ EventMachine::connect_unix_domain socketname,
82
+ nil, UnixConnection, args
83
+ @connections << connection
84
+ end
85
+ }
86
+ on_init.call(connection) # TODO move to unixnode event ?
87
+ end
88
+
89
+ public
90
+
91
+ # Unix initializer
92
+ # @param [Hash] args the options to create the unix node with
93
+ # @option args [String] :socketname the name of the socket which to listen on
94
+ def initialize(args = {})
95
+ super(args)
96
+ @socketname = args[:socketname]
97
+
98
+ @connections = []
99
+ @connections_lock = Mutex.new
100
+ end
101
+
102
+ def to_s
103
+ "RJR::Nodes::Unix<#{@node_id},#{@socketname}>"
104
+ end
105
+
106
+ # Send data using specified connection
107
+ #
108
+ # Implementation of {RJR::Node#send_msg}
109
+ def send_msg(data, connection)
110
+ connection.send_msg(data)
111
+ end
112
+
113
+ # Instruct Node to start listening for and dispatching rpc requests
114
+ #
115
+ # Implementation of {RJR::Node#listen}
116
+ def listen
117
+ @@em.schedule {
118
+ @@em.start_unix_domain_server @socketname, nil, UnixConnection, { :rjr_node => self }
119
+ }
120
+ self
121
+ end
122
+
123
+ # Instructs node to send rpc request, and wait for / return response.
124
+ #
125
+ # Implementation of {RJR::Node#invoke}
126
+ #
127
+ # Do not invoke directly from em event loop or callback as will block the message
128
+ # subscription used to receive responses
129
+ #
130
+ # @param [String] socketname name of socket which destination node is
131
+ # listening on
132
+ # @param [String] rpc_method json-rpc method to invoke on destination
133
+ # @param [Array] args array of arguments to convert to json and invoke remote method wtih
134
+ def invoke(socketname, rpc_method, *args)
135
+ message = RequestMessage.new :method => rpc_method,
136
+ :args => args,
137
+ :headers => @message_headers
138
+ connection = nil
139
+ @@em.schedule {
140
+ init_client(:socketname => socketname,
141
+ :rjr_node => self) { |c|
142
+ connection = c
143
+ c.send_msg message.to_s
144
+ }
145
+ }
146
+
147
+ # TODO optional timeout for response ?
148
+ result = wait_for_result(message)
149
+
150
+ if result.size > 2
151
+ raise Exception, result[2]
152
+ end
153
+ return result[1]
154
+ end
155
+
156
+ # Instructs node to send rpc notification (immadiately returns / no response is generated)
157
+ #
158
+ # Implementation of {RJR::Node#notify}
159
+ #
160
+ # @param [String] socketname name of socket which
161
+ # destination node is listening on
162
+ # @param [String] rpc_method json-rpc method to invoke on destination
163
+ # @param [Array] args array of arguments to convert to json and invoke remote method wtih
164
+ def notify(socketname, rpc_method, *args)
165
+ # will block until message is published
166
+ published_l = Mutex.new
167
+ published_c = ConditionVariable.new
168
+
169
+ invoked = false
170
+ conn = nil
171
+ message = NotificationMessage.new :method => rpc_method,
172
+ :args => args,
173
+ :headers => @message_headers
174
+ @@em.schedule {
175
+ init_client(:socketname => socketname,
176
+ :rjr_node => self) { |c|
177
+ conn = c
178
+ c.send_msg message.to_s
179
+ # XXX, this should be invoked only when we are sure event
180
+ # machine sent message. Shouldn't pose a problem unless event
181
+ # machine is killed immediately after
182
+ published_l.synchronize { invoked = true ; published_c.signal }
183
+ }
184
+ }
185
+ published_l.synchronize { published_c.wait published_l unless invoked }
186
+ #sleep 0.01 until conn.get_outbound_data_size == 0
187
+ nil
188
+ end
189
+ end # class Unix
190
+
191
+ end # module Nodes
192
+ end # module RJR
data/lib/rjr/nodes/web.rb CHANGED
@@ -8,6 +8,8 @@
8
8
  # Copyright (C) 2012-2013 Mohammed Morsi <mo@morsi.org>
9
9
  # Licensed under the Apache License, Version 2.0
10
10
 
11
+ # TODO rename to HTTP
12
+
11
13
  skip_module = false
12
14
  begin
13
15
  require 'evma_httpserver'
@@ -0,0 +1 @@
1
+ # TODO
data/lib/rjr/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RJR
2
- VERSION = '0.17.1'
2
+ VERSION = '0.18.1'
3
3
  end
data/site/jrw.js CHANGED
@@ -65,19 +65,80 @@ RJR.JRMessage.convert_params = function(params){
65
65
  for(var p = 0; p < params.length; p++){
66
66
  var param = params[p];
67
67
  if(RJR.is_jr_object(param)){
68
- // FIXME need to check each param property as well (converting if necessary)
69
- var json_class = param['json_class'];
70
- delete param['json_class'];
71
- jrparams.push({json_class: json_class,
72
- data : param});
73
- }else if(RJR.is_array(param))
68
+ jrparams.push(RJR.JRMessage.convert_obj_to_jr_obj(param));
69
+ }else if(RJR.is_array(param)){
70
+ /// TODO s/convert_params/convert_array_to_jr_array here ?
71
+ /// (or could the whole convert_params method could be
72
+ /// consolidated with that one ?)
74
73
  jrparams.push(RJR.JRMessage.convert_params(param));
75
- else
74
+ }else
76
75
  jrparams.push(param);
77
76
  }
78
77
  return jrparams;
79
78
  }
80
79
 
80
+ // Convert single json object to jr object
81
+ RJR.JRMessage.convert_obj_to_jr_obj= function(obj){
82
+ var jr_obj = $.extend(true, {}, obj)
83
+ var json_class = jr_obj['json_class'];
84
+ delete jr_obj['json_class'];
85
+
86
+ /// iterate over object properties
87
+ for(var p in jr_obj){
88
+ if(RJR.is_jr_object(jr_obj[p]))
89
+ jr_obj[p] = RJR.JRMessage.convert_obj_to_jr_obj(jr_obj[p]);
90
+ else if(RJR.is_array(jr_obj[p]))
91
+ jr_obj[p] = RJR.JRMessage.convert_array_to_jr_array(jr_obj[p]);
92
+ }
93
+
94
+ return {json_class: json_class,
95
+ data : jr_obj};
96
+ }
97
+
98
+ // Convert single json object from jr object
99
+ RJR.JRMessage.convert_obj_from_jr_obj = function(jr_obj){
100
+ var obj = $.extend(true, {}, jr_obj)
101
+ if(obj.data){
102
+ $.extend(obj, obj.data);
103
+ delete obj['data'];
104
+ }
105
+
106
+ for(var p in obj){
107
+ if(RJR.is_jr_object(obj[p]))
108
+ obj[p] = RJR.JRMessage.convert_obj_from_jr_obj(obj[p]);
109
+ else if(RJR.is_array(obj[p]))
110
+ obj[p] = RJR.JRMessage.convert_array_from_jr_array(obj[p]);
111
+ }
112
+
113
+ return obj;
114
+ }
115
+
116
+ // Recursively convert array to jr object array
117
+ RJR.JRMessage.convert_array_to_jr_array = function(array){
118
+ var jr_array = $.extend(true, [], array)
119
+ for(var a = 0; a < jr_array.length; a++){
120
+ if(RJR.is_jr_object(jr_array[a]))
121
+ jr_array[a] = RJR.JRMessage.convert_obj_to_jr_obj(jr_array[a]);
122
+ else if(RJR.is_array(jr_array[a]))
123
+ jr_array[a] = RJR.JRMesage.convert_array_to_jr_array(jr_array[a]);
124
+ }
125
+
126
+ return jr_array;
127
+ }
128
+
129
+ // Convert json object array from jr object array
130
+ RJR.JRMessage.convert_array_from_jr_array = function(jr_array){
131
+ var array = $.extend(true, [], jr_array)
132
+ for(var a = 0; a < array.length; a++){
133
+ if(RJR.is_jr_object(array[a]))
134
+ array[a] = RJR.JRMessage.convert_obj_from_jr_obj(array[a]);
135
+ else if(RJR.is_array(jr_array[a]))
136
+ array[a] = RJR.JRMessage.convert_array_from_jr_array(array[a]);
137
+ }
138
+
139
+ return array;
140
+ }
141
+
81
142
  // Parse a json string to a JRMessage
82
143
  RJR.JRMessage.parse = function(json){
83
144
  var data = $.evalJSON(json);
@@ -0,0 +1,71 @@
1
+ require 'rjr/nodes/unix'
2
+
3
+ module RJR::Nodes
4
+ describe Unix do
5
+ describe "#send_msg" do
6
+ it "should send message using the specifed connection"
7
+ end
8
+
9
+ describe "#listen" do
10
+ it "should listen for messages" do
11
+ rn = rni = rnt = p = invoked = nil
12
+ server = Unix.new :node_id => 'unix',
13
+ :socketname => './test.sock'
14
+ server.dispatcher.handle('foobar') { |param|
15
+ rn = @rjr_node
16
+ rni = @rjr_node_id
17
+ rnt = @rjr_node_type
18
+ p = param
19
+ invoked = true
20
+ }
21
+ server.listen
22
+
23
+ # issue request
24
+ Unix.new.invoke './test.sock', 'foobar', 'myparam'
25
+ server.halt.join
26
+ rn.should == server
27
+ rni.should == 'unix'
28
+ rnt.should == :unix
29
+ p.should == 'myparam'
30
+ invoked.should == true
31
+ end
32
+ end
33
+
34
+ describe "#invoke" do
35
+ it "should invoke request" do
36
+ server = Unix.new :node_id => 'unix',
37
+ :socketname => './test.sock'
38
+ server.dispatcher.handle('foobar') { |param|
39
+ 'retval'
40
+ }
41
+ server.listen
42
+
43
+ client = Unix.new
44
+ res = client.invoke './test.sock', 'foobar', 'myparam'
45
+ server.halt.join
46
+ res.should == 'retval'
47
+ end
48
+ end
49
+
50
+ describe "#notify" do
51
+ it "should send notification" do
52
+ server = Unix.new :node_id => 'unix',
53
+ :socketname => './test.sock'
54
+ server.dispatcher.handle('foobar') { |param|
55
+ 'retval'
56
+ }
57
+ server.listen
58
+
59
+ client = Unix.new
60
+ res = client.notify './test.sock', 'foobar', 'myparam'
61
+ server.halt.join
62
+ res.should == nil
63
+ end
64
+ end
65
+
66
+ # TODO test callbacks over unix interface
67
+ # TODO ensure closed / error event handlers are invoked
68
+ end
69
+ end
70
+
71
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rjr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.1
4
+ version: 0.18.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mo Morsi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-17 00:00:00.000000000 Z
11
+ date: 2013-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -69,6 +69,7 @@ files:
69
69
  - examples/complete.rb
70
70
  - examples/amqp.rb
71
71
  - examples/client.rb
72
+ - examples/unix.rb
72
73
  - lib/rjr/semaphore.rb
73
74
  - lib/rjr/em_adapter.rb
74
75
  - lib/rjr/errors.rb
@@ -86,7 +87,11 @@ files:
86
87
  - lib/rjr/nodes/tcp2.rb
87
88
  - lib/rjr/nodes/local.rb
88
89
  - lib/rjr/nodes/amqp.rb
90
+ - lib/rjr/nodes/xmpp.rb
91
+ - lib/rjr/nodes/file.rb
92
+ - lib/rjr/nodes/template.rb
89
93
  - lib/rjr/nodes/easy.rb
94
+ - lib/rjr/nodes/unix.rb
90
95
  - lib/rjr/nodes/missing.rb
91
96
  - lib/rjr/nodes/multi.rb
92
97
  - lib/rjr/dispatcher.rb
@@ -99,6 +104,7 @@ files:
99
104
  - README.md
100
105
  - specs/dispatcher_spec.rb
101
106
  - specs/node_spec.rb
107
+ - specs/nodes/unix_spec.rb
102
108
  - specs/nodes/multi_spec.rb
103
109
  - specs/nodes/tcp_spec.rb
104
110
  - specs/nodes/web_spec.rb
@@ -149,6 +155,7 @@ summary: JSON RPC server and client library over amqp, websockets, http, etc
149
155
  test_files:
150
156
  - specs/dispatcher_spec.rb
151
157
  - specs/node_spec.rb
158
+ - specs/nodes/unix_spec.rb
152
159
  - specs/nodes/multi_spec.rb
153
160
  - specs/nodes/tcp_spec.rb
154
161
  - specs/nodes/web_spec.rb