pomelo-citrus-rpc 0.0.2

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.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +20 -0
  3. data/Rakefile +0 -0
  4. data/citrus-rpc.gemspec +32 -0
  5. data/example/client.rb +43 -0
  6. data/example/remote/test/service.rb +9 -0
  7. data/example/server.rb +20 -0
  8. data/lib/citrus-rpc.rb +16 -0
  9. data/lib/citrus-rpc/rpc-client/client.rb +328 -0
  10. data/lib/citrus-rpc/rpc-client/mailboxes/ws_mailbox.rb +164 -0
  11. data/lib/citrus-rpc/rpc-client/mailstation.rb +363 -0
  12. data/lib/citrus-rpc/rpc-client/proxy.rb +37 -0
  13. data/lib/citrus-rpc/rpc-client/router.rb +63 -0
  14. data/lib/citrus-rpc/rpc-server/acceptors/ws_acceptor.rb +143 -0
  15. data/lib/citrus-rpc/rpc-server/dispatcher.rb +36 -0
  16. data/lib/citrus-rpc/rpc-server/gateway.rb +58 -0
  17. data/lib/citrus-rpc/rpc-server/server.rb +92 -0
  18. data/lib/citrus-rpc/util/constants.rb +20 -0
  19. data/lib/citrus-rpc/util/utils.rb +42 -0
  20. data/lib/citrus-rpc/version.rb +7 -0
  21. data/spec/mock-remote/area/add_one_remote.rb +13 -0
  22. data/spec/mock-remote/area/add_three_remote.rb +9 -0
  23. data/spec/mock-remote/area/who_am_i_remote.rb +9 -0
  24. data/spec/mock-remote/connector/who_am_i_remote.rb +9 -0
  25. data/spec/rpc-client/client_spec.rb +166 -0
  26. data/spec/rpc-client/mailstaion_spec.rb +235 -0
  27. data/spec/rpc-client/proxy_spec.rb +8 -0
  28. data/spec/rpc-client/router_spec.rb +8 -0
  29. data/spec/rpc-client/ws_mailbox_spec.rb +144 -0
  30. data/spec/rpc-server/client/mock-tcp-client.rb +6 -0
  31. data/spec/rpc-server/client/mock-ws-client.rb +48 -0
  32. data/spec/rpc-server/dispatcher_spec.rb +88 -0
  33. data/spec/rpc-server/gateway_spec.rb +206 -0
  34. data/spec/rpc-server/server_spec.rb +79 -0
  35. data/spec/rpc-server/ws_acceptor_spec.rb +138 -0
  36. data/spec/spec_helper.rb +25 -0
  37. metadata +179 -0
@@ -0,0 +1,42 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 5 July 2014
4
+
5
+ module CitrusRpc
6
+ # Utils
7
+ #
8
+ #
9
+ module Utils
10
+ # EventEmitter
11
+ #
12
+ #
13
+ module EventEmitter
14
+ # Register event
15
+ #
16
+ # @param [String] event
17
+ def on event, &block
18
+ @on_blocks ||= {}
19
+ @on_blocks[event] = block
20
+ end
21
+
22
+ # Register event once
23
+ #
24
+ # @param [String] event
25
+ def once event, &block
26
+ @once_blocks ||= {}
27
+ @once_blocks[event] = block
28
+ end
29
+
30
+ # Emit event
31
+ def emit *args
32
+ event = args.shift
33
+ if @once_blocks && block = @once_blocks[event]
34
+ @once_blocks.delete event
35
+ elsif !@on_blocks || !block = @on_blocks[event]
36
+ return
37
+ end
38
+ block.call *args
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,7 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 5 July 2014
4
+
5
+ module CitrusRpc
6
+ VERSION = '0.0.2'
7
+ end
@@ -0,0 +1,13 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 5 July 2014
4
+
5
+ class AddOneRemote < Citrus::AppRemote
6
+ def do value, &block
7
+ block.call nil, value + 1
8
+ end
9
+
10
+ def add_two value, &block
11
+ block.call nil, value + 2
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 5 July 2014
4
+
5
+ class AddThreeRemote < Citrus::AppRemote
6
+ def do value, &block
7
+ block.call nil, value + 3
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 5 July 2014
4
+
5
+ class WhoAmIAreaRemote < Citrus::AppRemote
6
+ def do &block
7
+ block.call nil, @app[:server_id]
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 5 July 2014
4
+
5
+ class WhoAmIRemote < Citrus::AppRemote
6
+ def do &block
7
+ block.call nil, @app[:server_id]
8
+ end
9
+ end
@@ -0,0 +1,166 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 5 July 2014
4
+
5
+ require File.expand_path('../../spec_helper', __FILE__)
6
+
7
+ describe Client do
8
+
9
+ dirname = File.expand_path File.dirname(__FILE__)
10
+ records = [
11
+ { :namespace => 'user', :server_type => 'area', :path => dirname + '/../mock-remote/area' },
12
+ { :namespace => 'sys', :server_type => 'connector', :path => dirname + '/../mock-remote/connector' }
13
+ ]
14
+
15
+ server_list = [
16
+ { :id => 'area-server-1', :server_type => 'area', :host => '127.0.0.1', :port => 3333 },
17
+ { :id => 'connector-server-1', :server_type => 'connector', :host => '127.0.0.1', :port => 4444 },
18
+ { :id => 'connector-server-2', :server_type => 'connector', :host => '127.0.0.1', :port => 5555 }
19
+ ]
20
+
21
+ describe '#create' do
22
+ it 'should be ok when created with empty options' do
23
+ client = Client.new
24
+ expect(client).to be_an_instance_of Client
25
+
26
+ EM.run {
27
+ client.start { |err|
28
+ expect(err).to be_nil
29
+ client.stop true
30
+ }
31
+
32
+ EM.add_timer(0.1) { EM.stop_event_loop }
33
+ }
34
+ end
35
+
36
+ it 'should add proxies by add_proxies method' do
37
+ client = Client.new
38
+ expect(client).to be_an_instance_of Client
39
+
40
+ client.add_proxies records
41
+ records.each { |record|
42
+ namespace = record[:namespace]
43
+ server_type = record[:server_type]
44
+ expect(client.proxies).to respond_to namespace
45
+ expect(client.proxies[namespace]).to respond_to server_type
46
+ }
47
+ end
48
+
49
+ it 'should replace the default router when created by passing router argument' do
50
+ route_count = 0
51
+ callback_count = 0
52
+
53
+ server = server_list[1]
54
+ server_id = server[:id]
55
+
56
+ router = Proc.new do |route_param, msg, route_context, &block|
57
+ route_count = route_count + 1
58
+ block.call nil, server_id
59
+ end
60
+
61
+ EM.run {
62
+ server_list.each { |server|
63
+ Server.new( :records => records, :port => server[:port],
64
+ :context => { :server_id => server[:id] }).start
65
+ }
66
+
67
+ client = Client.new :router => router
68
+ client.add_proxies records
69
+ client.add_server server
70
+
71
+ client.start { |err|
72
+ expect(err).to be_nil
73
+
74
+ client.proxies.sys.connector.whoAmIRemote.do(nil) { |err, sid|
75
+ callback_count = callback_count + 1
76
+ expect(sid).to eq server_id
77
+ }
78
+ }
79
+
80
+ EM.add_timer(0.1) {
81
+ expect(route_count).to eq 1
82
+ expect(callback_count).to eq 1
83
+ EM.stop_event_loop
84
+ }
85
+ }
86
+ end
87
+ end
88
+
89
+ describe '#status' do
90
+ it 'should return an error if started twice' do
91
+ client = Client.new
92
+ EM.run {
93
+ client.start { |err|
94
+ expect(err).to be_nil
95
+ client.start { |err|
96
+ expect(err).to be
97
+ }
98
+ }
99
+
100
+ EM.add_timer(0.1) { EM.stop_event_loop }
101
+ }
102
+ end
103
+
104
+ it 'should ignore the later operation if stopped twice' do
105
+ client = Client.new
106
+ EM.run {
107
+ client.start { |err|
108
+ expect(err).to be_nil
109
+ client.stop
110
+ client.stop
111
+ }
112
+
113
+ EM.add_timer(0.1) { EM.stop_event_loop }
114
+ }
115
+ end
116
+
117
+ it 'should return an error when doing rpc invoke with the client not started' do
118
+ client = Client.new
119
+ EM.run {
120
+ client.rpc_invoke(server_list[0][:id], '') { |err|
121
+ expect(err).to be
122
+ }
123
+
124
+ EM.add_timer(0.1) { EM.stop_event_loop }
125
+ }
126
+ end
127
+
128
+ it 'should return an error when doing rpc invoke after the client stopped' do
129
+ server_id = server_list[0][:id]
130
+
131
+ client = Client.new
132
+ client.add_server server_list[0]
133
+
134
+ EM.run {
135
+ server_list.each { |server|
136
+ Server.new( :records => records, :port => server[:port],
137
+ :context => { :server_id => server[:id] }).start
138
+ }
139
+
140
+ msg = {
141
+ 'namespace' => 'user',
142
+ 'server_type' => 'area',
143
+ 'service' => 'whoAmIAreaRemote',
144
+ 'method' => 'do',
145
+ 'args' => []
146
+ };
147
+
148
+ client.start { |err|
149
+ expect(err).to be_nil
150
+
151
+ client.rpc_invoke(server_id, msg) { |err|
152
+ expect(err).to be_nil
153
+ client.stop true
154
+ EM.add_timer(0.1) {
155
+ client.rpc_invoke(server_id, msg) { |err|
156
+ expect(err).to be
157
+ }
158
+ }
159
+ }
160
+ }
161
+
162
+ EM.add_timer(0.2) { EM.stop_event_loop }
163
+ }
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,235 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 5 July 2014
4
+
5
+ require File.expand_path('../../spec_helper', __FILE__)
6
+
7
+ describe MailStation do
8
+
9
+ dirname = File.expand_path File.dirname(__FILE__)
10
+ records = [
11
+ { :namespace => 'user', :server_type => 'area', :path => dirname + '/../mock-remote/area' },
12
+ { :namespace => 'sys', :server_type => 'connector', :path => dirname + '/../mock-remote/connector' }
13
+ ]
14
+
15
+ server_list = [
16
+ { :id => 'area-server-1', :server_type => 'area', :host => '127.0.0.1', :port => 3333 },
17
+ { :id => 'connector-server-1', :server_type => 'connector', :host => '127.0.0.1', :port => 4444 },
18
+ { :id => 'connector-server-2', :server_type => 'connector', :host => '127.0.0.1', :port => 5555 }
19
+ ]
20
+
21
+ msg = {
22
+ 'namespace' => 'user',
23
+ 'server_type' => 'area',
24
+ 'service' => 'whoAmIAreaRemote',
25
+ 'method' => 'do',
26
+ 'args' => []
27
+ }
28
+
29
+ describe '#create' do
30
+ it 'should be ok when created with empty options' do
31
+ EM.run {
32
+ station = MailStation.new
33
+ expect(station).to be
34
+
35
+ station.start { |err|
36
+ expect(err).to be_nil
37
+ EM.stop_event_loop
38
+ }
39
+ }
40
+ end
41
+
42
+ it 'should change the default mailbox class by passing mailbox class argument' do
43
+ MockMailBox = Class.new
44
+
45
+ station = MailStation.new :mailbox_class => MockMailBox
46
+ expect(station).to be
47
+ expect(station.mailbox_class).to eql MockMailBox
48
+ end
49
+ end
50
+
51
+ describe '#add server' do
52
+ it 'should add server info into the mail station' do
53
+ station = MailStation.new
54
+ expect(station).to be
55
+
56
+ server_list.each { |server|
57
+ station.add_server server
58
+ }
59
+
60
+ servers = station.servers
61
+ server_list.each { |item|
62
+ server = servers[item[:id]]
63
+ expect(server).to be
64
+ expect(server).to eql item
65
+ }
66
+ end
67
+ end
68
+
69
+ describe '#dispatch' do
70
+ it 'should send the request to the right remote server and get the response from callback' do
71
+ callback_count = 0
72
+ count = 0
73
+
74
+ station = MailStation.new
75
+ expect(station).to be
76
+
77
+ server_list.each { |server|
78
+ station.add_server server
79
+ }
80
+
81
+ EM.run do
82
+ server_list.each { |server|
83
+ Server.new(
84
+ :records => records,
85
+ :port => server[:port],
86
+ :context => { :server_id => server[:id] }
87
+ ).start
88
+ }
89
+
90
+ func = Proc.new { |server_id|
91
+ Proc.new { |err, remote_id|
92
+ expect(remote_id).to be
93
+ expect(remote_id).to eql server_id
94
+ callback_count = callback_count + 1
95
+ }
96
+ }
97
+
98
+ station.start { |err|
99
+ server_list.each { |server|
100
+ count = count + 1
101
+ station.dispatch server[:id], msg, nil, func.call(server[:id])
102
+ }
103
+ }
104
+
105
+ EM.add_timer(0.1) {
106
+ expect(callback_count).to eql count
107
+ EM.stop_event_loop
108
+ }
109
+ end
110
+ end
111
+
112
+ it 'should update the mailbox map by add server after start' do
113
+ callback_count = 0
114
+ count = 0
115
+
116
+ station = MailStation.new
117
+ expect(station).to be
118
+
119
+ server_list.each { |server|
120
+ station.add_server server
121
+ }
122
+
123
+ EM.run {
124
+ server_list.each { |server|
125
+ Server.new(
126
+ :records => records,
127
+ :port => server[:port],
128
+ :context => { :server_id => server[:id] }
129
+ ).start
130
+ }
131
+
132
+ server = server_list[0]
133
+
134
+ block = Proc.new { |err, remote_id|
135
+ expect(remote_id).to be
136
+ expect(remote_id).to eql server[:id]
137
+ callback_count = callback_count + 1
138
+ }
139
+
140
+ station.start { |err|
141
+ station.add_server server
142
+ station.dispatch server[:id], msg, nil, block
143
+ }
144
+
145
+ EM.add_timer(0.1) {
146
+ expect(callback_count).to eql 1
147
+ EM.stop_event_loop
148
+ }
149
+ }
150
+ end
151
+ end
152
+
153
+ describe '#close' do
154
+ it 'should emit a close event for each mailbox close' do
155
+ close_event_count = 0
156
+
157
+ server_ids = []
158
+ mailbox_ids = []
159
+
160
+ station = MailStation.new
161
+ expect(station).to be
162
+
163
+ EM.run {
164
+ server_list.each { |server|
165
+ Server.new(
166
+ :records => records,
167
+ :port => server[:port],
168
+ :context => { :server_id => server[:id] }
169
+ ).start
170
+
171
+ station.add_server server
172
+
173
+ server_ids << server[:id]
174
+ }
175
+
176
+ server_ids.sort
177
+
178
+ func = Proc.new { |server_id|
179
+ Proc.new { |err, remote_id|
180
+ expect(remote_id).to be
181
+ expect(remote_id).to eql server_id
182
+ }
183
+ }
184
+
185
+ station.start { |err|
186
+ server_list.each { |server|
187
+ station.dispatch server[:id], msg, nil, func.call(server[:id])
188
+ }
189
+ station.on(:close) { |mailbox_id|
190
+ mailbox_ids << mailbox_id
191
+ close_event_count = close_event_count + 1
192
+ }
193
+ }
194
+
195
+ EM.add_timer(0.1) {
196
+ station.stop true
197
+ EM.add_timer(0.1) {
198
+ expect(close_event_count).to eql server_ids.length
199
+ mailbox_ids.sort
200
+ expect(mailbox_ids).to eql server_ids
201
+ EM.stop_event_loop
202
+ }
203
+ }
204
+ }
205
+ end
206
+
207
+ it 'should return an error when trying to dispatch message with a closed station' do
208
+ error_count = 0
209
+
210
+ station = MailStation.new
211
+ expect(station).to be
212
+
213
+ server_list.each { |server|
214
+ station.add_server server
215
+ }
216
+
217
+ EM.run do
218
+ station.start { |err|
219
+ station.stop
220
+ server_list.each { |server|
221
+ station.dispatch server[:id], msg, nil, proc{ |err, remote_id|
222
+ expect(err).to be
223
+ error_count = error_count + 1
224
+ }
225
+ }
226
+ }
227
+
228
+ EM.add_timer(0.1) {
229
+ expect(error_count).to eql server_list.length
230
+ EM.stop_event_loop
231
+ }
232
+ end
233
+ end
234
+ end
235
+ end