pomelo-citrus-rpc 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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