wamp_client 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +28 -26
  3. data/lib/{wamp_client.rb → wamp/client.rb} +8 -8
  4. data/lib/{wamp_client → wamp/client}/auth.rb +13 -11
  5. data/lib/wamp/client/check.rb +86 -0
  6. data/lib/wamp/client/connection.rb +249 -0
  7. data/lib/{wamp_client → wamp/client}/defer.rb +29 -27
  8. data/lib/wamp/client/message.rb +1322 -0
  9. data/lib/{wamp_client → wamp/client}/serializer.rb +26 -24
  10. data/lib/wamp/client/session.rb +1001 -0
  11. data/lib/wamp/client/transport/base.rb +152 -0
  12. data/lib/{wamp_client → wamp/client}/transport/event_machine_base.rb +19 -17
  13. data/lib/wamp/client/transport/faye_web_socket.rb +85 -0
  14. data/lib/wamp/client/transport/web_socket_event_machine.rb +88 -0
  15. data/lib/{wamp_client → wamp/client}/version.rb +5 -3
  16. data/scripts/gen_message.rb +54 -53
  17. data/spec/spec_helper.rb +3 -3
  18. data/spec/{auth_spec.rb → wamp/client/auth_spec.rb} +2 -2
  19. data/spec/{check_spec.rb → wamp/client/check_spec.rb} +2 -2
  20. data/spec/{connection_spec.rb → wamp/client/connection_spec.rb} +7 -7
  21. data/spec/{message_spec.rb → wamp/client/message_spec.rb} +298 -298
  22. data/spec/{session_spec.rb → wamp/client/session_spec.rb} +134 -134
  23. data/spec/{transport_spec.rb → wamp/client/transport_spec.rb} +4 -4
  24. data/wamp_client.gemspec +2 -2
  25. metadata +50 -50
  26. data/lib/wamp_client/check.rb +0 -84
  27. data/lib/wamp_client/connection.rb +0 -247
  28. data/lib/wamp_client/message.rb +0 -1348
  29. data/lib/wamp_client/session.rb +0 -1000
  30. data/lib/wamp_client/transport/base.rb +0 -151
  31. data/lib/wamp_client/transport/faye_web_socket.rb +0 -83
  32. data/lib/wamp_client/transport/web_socket_event_machine.rb +0 -86
@@ -1,1000 +0,0 @@
1
- =begin
2
-
3
- Copyright (c) 2016 Eric Chapman
4
-
5
- MIT License
6
-
7
- Permission is hereby granted, free of charge, to any person obtaining
8
- a copy of this software and associated documentation files (the
9
- "Software"), to deal in the Software without restriction, including
10
- without limitation the rights to use, copy, modify, merge, publish,
11
- distribute, sublicense, and/or sell copies of the Software, and to
12
- permit persons to whom the Software is furnished to do so, subject to
13
- the following conditions:
14
-
15
- The above copyright notice and this permission notice shall be
16
- included in all copies or substantial portions of the Software.
17
-
18
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
-
26
- =end
27
-
28
- require 'wamp_client/transport/base'
29
- require 'wamp_client/message'
30
- require 'wamp_client/check'
31
- require 'wamp_client/version'
32
-
33
- module WampClient
34
-
35
- WAMP_FEATURES = {
36
- caller: {
37
- features: {
38
- caller_identification: true,
39
- call_timeout: true,
40
- call_canceling: true,
41
- progressive_call_results: true
42
- }
43
- },
44
- callee: {
45
- features: {
46
- caller_identification: true,
47
- ##call_trustlevels: true,
48
- pattern_based_registration: true,
49
- shared_registration: true,
50
- ##call_timeout: true,
51
- call_canceling: true,
52
- progressive_call_results: true,
53
- registration_revocation: true
54
- }
55
- },
56
- publisher: {
57
- features: {
58
- publisher_identification: true,
59
- subscriber_blackwhite_listing: true,
60
- publisher_exclusion: true
61
- }
62
- },
63
- subscriber: {
64
- features: {
65
- publisher_identification: true,
66
- ##publication_trustlevels: true,
67
- pattern_based_subscription: true,
68
- subscription_revocation: true
69
- ##event_history: true,
70
- }
71
- }
72
- }
73
-
74
- class CallResult
75
- attr_accessor :args, :kwargs
76
-
77
- def initialize(args=nil, kwargs=nil)
78
- self.args = args || []
79
- self.kwargs = kwargs || {}
80
- end
81
- end
82
-
83
- class CallError < Exception
84
- attr_accessor :error, :args, :kwargs
85
-
86
- def initialize(error, args=nil, kwargs=nil)
87
- self.error = error
88
- self.args = args || []
89
- self.kwargs = kwargs || {}
90
- end
91
- end
92
-
93
- class Subscription
94
- attr_accessor :topic, :handler, :options, :session, :id
95
-
96
- def initialize(topic, handler, options, session, id)
97
- self.topic = topic
98
- self.handler = handler
99
- self.options = options
100
- self.session = session
101
- self.id = id
102
- end
103
-
104
- def unsubscribe
105
- self.session.unsubscribe(self)
106
- end
107
-
108
- end
109
-
110
- class Registration
111
- attr_accessor :procedure, :handler, :i_handler, :options, :session, :id
112
-
113
- def initialize(procedure, handler, options, i_handler, session, id)
114
- self.procedure = procedure
115
- self.handler = handler
116
- self.options = options
117
- self.i_handler = i_handler
118
- self.session = session
119
- self.id = id
120
- end
121
-
122
- def unregister
123
- self.session.unregister(self)
124
- end
125
-
126
- end
127
-
128
- class Call
129
- attr_accessor :session, :id
130
-
131
- def initialize(session, id)
132
- self.session = session
133
- self.id = id
134
- end
135
-
136
- def cancel(mode='skip')
137
- self.session.cancel(self, mode)
138
- end
139
-
140
- end
141
-
142
- class Session
143
- include WampClient::Check
144
-
145
- # on_join callback is called when the session joins the router. It has the following parameters
146
- # @param details [Hash] Object containing information about the joined session
147
- @on_join
148
- def on_join(&on_join)
149
- @on_join = on_join
150
- end
151
-
152
- # on_leave callback is called when the session leaves the router. It has the following attributes
153
- # @param reason [String] The reason the session left the router
154
- # @param details [Hash] Object containing information about the left session
155
- @on_leave
156
- def on_leave(&on_leave)
157
- @on_leave = on_leave
158
- end
159
-
160
- # on_challenge callback is called when an authentication challenge is received from the router. It has the
161
- # following attributes
162
- # @param authmethod [String] The type of auth being requested
163
- # @param extra [Hash] Hash containing additional information
164
- # @return signature, extras
165
- @on_challenge
166
- def on_challenge(&on_challenge)
167
- @on_challenge = on_challenge
168
- end
169
-
170
- # Simple setter for callbacks
171
- def on(event, &callback)
172
- case event
173
- when :join
174
- self.on_join(&callback)
175
- when :challenge
176
- self.on_challenge(&callback)
177
- when :leave
178
- self.on_leave(&callback)
179
- else
180
- raise RuntimeError, "Unknown on(event) '#{event}'"
181
- end
182
- end
183
-
184
- attr_accessor :id, :realm, :transport, :verbose, :options
185
-
186
- # Private attributes
187
- attr_accessor :_goodbye_sent, :_requests, :_subscriptions, :_registrations, :_defers
188
-
189
- # Constructor
190
- # @param transport [WampClient::Transport::Base] The transport that the session will use
191
- # @param options [Hash] Hash containing different session options
192
- # @option options [String] :authid The authentication ID
193
- # @option options [Array] :authmethods Different auth methods that this client supports
194
- def initialize(transport, options={})
195
-
196
- # Parameters
197
- self.id = nil
198
- self.realm = nil
199
- self.options = options || {}
200
- self.verbose = self.options[:verbose]
201
-
202
- # Outstanding Requests
203
- self._requests = {
204
- publish: {},
205
- subscribe: {},
206
- unsubscribe: {},
207
- call: {},
208
- register: {},
209
- unregister: {}
210
- }
211
-
212
- # Init Subs and Regs in place
213
- self._subscriptions = {}
214
- self._registrations = {}
215
- self._defers = {}
216
-
217
- # Setup Transport
218
- self.transport = transport
219
- self.transport.on_message do |msg|
220
- self._receive_message(msg)
221
- end
222
-
223
- # Other parameters
224
- self._goodbye_sent = false
225
-
226
- # Setup session callbacks
227
- @on_join = nil
228
- @on_leave = nil
229
- @on_challenge = nil
230
-
231
- end
232
-
233
- # Returns 'true' if the session is open
234
- def is_open?
235
- !self.id.nil?
236
- end
237
-
238
- # Joins the WAMP Router
239
- # @param realm [String] The name of the realm
240
- def join(realm)
241
- if is_open?
242
- raise RuntimeError, "Session must be closed to call 'join'"
243
- end
244
-
245
- self.class.check_uri('realm', realm)
246
-
247
- self.realm = realm
248
-
249
- details = {}
250
- details[:roles] = WAMP_FEATURES
251
- details[:agent] = "Ruby-WampClient-#{WampClient::VERSION}"
252
- details[:authid] = self.options[:authid] if self.options[:authid]
253
- details[:authmethods] = self.options[:authmethods] if self.options[:authmethods]
254
-
255
- # Send Hello message
256
- hello = WampClient::Message::Hello.new(realm, details)
257
- self._send_message(hello)
258
- end
259
-
260
- # Leaves the WAMP Router
261
- # @param reason [String] URI signalling the reason for leaving
262
- def leave(reason='wamp.close.normal', message='user initiated')
263
- unless is_open?
264
- raise RuntimeError, "Session must be opened to call 'leave'"
265
- end
266
-
267
- self.class.check_uri('reason', reason, true)
268
- self.class.check_string('message', message, true)
269
-
270
- details = {}
271
- details[:message] = message
272
-
273
- # Send Goodbye message
274
- goodbye = WampClient::Message::Goodbye.new(details, reason)
275
- self._send_message(goodbye)
276
- self._goodbye_sent = true
277
- end
278
-
279
- # Generates an ID according to the specification (Section 5.1.2)
280
- def _generate_id
281
- rand(0..9007199254740992)
282
- end
283
-
284
- # Converts and error message to a hash
285
- # @param msg [WampClient::Message::Error]
286
- def _error_to_hash(msg)
287
- {
288
- error: msg.error,
289
- args: msg.arguments,
290
- kwargs: msg.argumentskw
291
- }
292
- end
293
-
294
- # Sends a message
295
- # @param msg [WampClient::Message::Base]
296
- def _send_message(msg)
297
- puts 'TX: ' + msg.to_s if self.verbose
298
- self.transport.send_message(msg.payload)
299
- end
300
-
301
- # Processes received messages
302
- # @param msg [Array]
303
- def _receive_message(msg)
304
-
305
- message = WampClient::Message::Base.parse(msg)
306
-
307
- if self.verbose
308
- puts 'RX: ' + message.to_s if message
309
- puts 'RX(non-wamp): ' + msg.to_s unless message
310
- end
311
-
312
- # WAMP Session is not open
313
- if self.id.nil?
314
-
315
- # Parse the welcome message
316
- if message.is_a? WampClient::Message::Welcome
317
- self.id = message.session
318
- @on_join.call(message.details) unless @on_join.nil?
319
- elsif message.is_a? WampClient::Message::Challenge
320
-
321
- if @on_challenge
322
- signature, extra = @on_challenge.call(message.authmethod, message.extra)
323
- else
324
- signature = nil
325
- extra = nil
326
- end
327
-
328
- signature ||= ''
329
- extra ||= {}
330
-
331
- authenticate = WampClient::Message::Authenticate.new(signature, extra)
332
- self._send_message(authenticate)
333
-
334
- elsif message.is_a? WampClient::Message::Abort
335
- @on_leave.call(message.reason, message.details) unless @on_leave.nil?
336
- end
337
-
338
- # Wamp Session is open
339
- else
340
-
341
- # If goodbye, close the session
342
- if message.is_a? WampClient::Message::Goodbye
343
-
344
- # If we didn't send the goodbye, respond
345
- unless self._goodbye_sent
346
- goodbye = WampClient::Message::Goodbye.new({}, 'wamp.error.goodbye_and_out')
347
- self._send_message(goodbye)
348
- end
349
-
350
- # Close out session
351
- self.id = nil
352
- self.realm = nil
353
- self._goodbye_sent = false
354
- @on_leave.call(message.reason, message.details) unless @on_leave.nil?
355
-
356
- else
357
-
358
- # Process Errors
359
- if message.is_a? WampClient::Message::Error
360
- if message.request_type == WampClient::Message::Types::SUBSCRIBE
361
- self._process_SUBSCRIBE_error(message)
362
- elsif message.request_type == WampClient::Message::Types::UNSUBSCRIBE
363
- self._process_UNSUBSCRIBE_error(message)
364
- elsif message.request_type == WampClient::Message::Types::PUBLISH
365
- self._process_PUBLISH_error(message)
366
- elsif message.request_type == WampClient::Message::Types::REGISTER
367
- self._process_REGISTER_error(message)
368
- elsif message.request_type == WampClient::Message::Types::UNREGISTER
369
- self._process_UNREGISTER_error(message)
370
- elsif message.request_type == WampClient::Message::Types::CALL
371
- self._process_CALL_error(message)
372
- else
373
- # TODO: Some Error?? Not Implemented yet
374
- end
375
-
376
- # Process Messages
377
- else
378
- if message.is_a? WampClient::Message::Subscribed
379
- self._process_SUBSCRIBED(message)
380
- elsif message.is_a? WampClient::Message::Unsubscribed
381
- self._process_UNSUBSCRIBED(message)
382
- elsif message.is_a? WampClient::Message::Published
383
- self._process_PUBLISHED(message)
384
- elsif message.is_a? WampClient::Message::Event
385
- self._process_EVENT(message)
386
- elsif message.is_a? WampClient::Message::Registered
387
- self._process_REGISTERED(message)
388
- elsif message.is_a? WampClient::Message::Unregistered
389
- self._process_UNREGISTERED(message)
390
- elsif message.is_a? WampClient::Message::Invocation
391
- self._process_INVOCATION(message)
392
- elsif message.is_a? WampClient::Message::Interrupt
393
- self._process_INTERRUPT(message)
394
- elsif message.is_a? WampClient::Message::Result
395
- self._process_RESULT(message)
396
- else
397
- # TODO: Some Error?? Not Implemented yet
398
- end
399
- end
400
-
401
- end
402
- end
403
-
404
- end
405
-
406
- #region Subscribe Logic
407
-
408
- # Subscribes to a topic
409
- # @param topic [String] The topic to subscribe to
410
- # @param handler [lambda] The handler(args, kwargs, details) when an event is received
411
- # @param options [Hash] The options for the subscription
412
- # @param callback [block] The callback(subscription, error) called to signal if the subscription was a success or not
413
- def subscribe(topic, handler, options={}, &callback)
414
- unless is_open?
415
- raise RuntimeError, "Session must be open to call 'subscribe'"
416
- end
417
-
418
- self.class.check_uri('topic', topic)
419
- self.class.check_dict('options', options)
420
- self.class.check_nil('handler', handler, false)
421
-
422
- # Create a new subscribe request
423
- request = self._generate_id
424
- self._requests[:subscribe][request] = {t: topic, h: handler, o: options, c: callback}
425
-
426
- # Send the message
427
- subscribe = WampClient::Message::Subscribe.new(request, options, topic)
428
- self._send_message(subscribe)
429
- end
430
-
431
- # Processes the response to a subscribe request
432
- # @param msg [WampClient::Message::Subscribed] The response from the subscribe
433
- def _process_SUBSCRIBED(msg)
434
-
435
- # Remove the pending subscription, add it to the registered ones, and inform the caller
436
- s = self._requests[:subscribe].delete(msg.subscribe_request)
437
- if s
438
-
439
- details = {}
440
- details[:topic] = s[:t] unless details[:topic]
441
- details[:type] = 'subscribe'
442
- details[:session] = self
443
-
444
- n_s = Subscription.new(s[:t], s[:h], s[:o], self, msg.subscription)
445
- self._subscriptions[msg.subscription] = n_s
446
- c = s[:c]
447
- c.call(n_s, nil, details) if c
448
- end
449
-
450
- end
451
-
452
- # Processes an error from a request
453
- # @param msg [WampClient::Message::Error] The response from the subscribe
454
- def _process_SUBSCRIBE_error(msg)
455
-
456
- # Remove the pending subscription and inform the caller of the failure
457
- s = self._requests[:subscribe].delete(msg.request_request)
458
- if s
459
-
460
- details = msg.details || {}
461
- details[:topic] = s[:t] unless details[:topic]
462
- details[:type] = 'subscribe'
463
- details[:session] = self
464
-
465
- c = s[:c]
466
- c.call(nil, self._error_to_hash(msg), details) if c
467
- end
468
-
469
- end
470
-
471
- # Processes and event from the broker
472
- # @param msg [WampClient::Message::Event] An event that was published
473
- def _process_EVENT(msg)
474
-
475
- args = msg.publish_arguments || []
476
- kwargs = msg.publish_argumentskw || {}
477
-
478
- s = self._subscriptions[msg.subscribed_subscription]
479
- if s
480
- details = msg.details || {}
481
- details[:publication] = msg.published_publication
482
- details[:session] = self
483
-
484
- h = s.handler
485
- h.call(args, kwargs, details) if h
486
- end
487
-
488
- end
489
-
490
- #endregion
491
-
492
- #region Unsubscribe Logic
493
-
494
- # Unsubscribes from a subscription
495
- # @param subscription [Subscription] The subscription object from when the subscription was created
496
- # @param callback [block] The callback(subscription, error, details) called to signal if the subscription was a success or not
497
- def unsubscribe(subscription, &callback)
498
- unless is_open?
499
- raise RuntimeError, "Session must be open to call 'unsubscribe'"
500
- end
501
-
502
- self.class.check_nil('subscription', subscription, false)
503
-
504
- # Create a new unsubscribe request
505
- request = self._generate_id
506
- self._requests[:unsubscribe][request] = { s: subscription, c: callback }
507
-
508
- # Send the message
509
- unsubscribe = WampClient::Message::Unsubscribe.new(request, subscription.id)
510
- self._send_message(unsubscribe)
511
- end
512
-
513
- # Processes the response to a unsubscribe request
514
- # @param msg [WampClient::Message::Unsubscribed] The response from the unsubscribe
515
- def _process_UNSUBSCRIBED(msg)
516
-
517
- # Remove the pending unsubscription, add it to the registered ones, and inform the caller
518
- s = self._requests[:unsubscribe].delete(msg.unsubscribe_request)
519
- if s
520
- n_s = s[:s]
521
- self._subscriptions.delete(n_s.id)
522
-
523
- details = {}
524
- details[:topic] = s[:s].topic
525
- details[:type] = 'unsubscribe'
526
- details[:session] = self
527
-
528
- c = s[:c]
529
- c.call(n_s, nil, details) if c
530
- end
531
-
532
- end
533
-
534
-
535
- # Processes an error from a request
536
- # @param msg [WampClient::Message::Error] The response from the subscribe
537
- def _process_UNSUBSCRIBE_error(msg)
538
-
539
- # Remove the pending subscription and inform the caller of the failure
540
- s = self._requests[:unsubscribe].delete(msg.request_request)
541
- if s
542
-
543
- details = msg.details || {}
544
- details[:topic] = s[:s].topic unless details[:topic]
545
- details[:type] = 'unsubscribe'
546
- details[:session] = self
547
-
548
- c = s[:c]
549
- c.call(nil, self._error_to_hash(msg), details) if c
550
- end
551
-
552
- end
553
-
554
- #endregion
555
-
556
- #region Publish Logic
557
-
558
- # Publishes and event to a topic
559
- # @param topic [String] The topic to publish the event to
560
- # @param args [Array] The arguments
561
- # @param kwargs [Hash] The keyword arguments
562
- # @param options [Hash] The options for the publish
563
- # @param callback [block] The callback(publish, error, details) called to signal if the publish was a success or not
564
- def publish(topic, args=nil, kwargs=nil, options={}, &callback)
565
- unless is_open?
566
- raise RuntimeError, "Session must be open to call 'publish'"
567
- end
568
-
569
- self.class.check_uri('topic', topic)
570
- self.class.check_dict('options', options)
571
- self.class.check_list('args', args, true)
572
- self.class.check_dict('kwargs', kwargs, true)
573
-
574
- # Create a new publish request
575
- request = self._generate_id
576
- self._requests[:publish][request] = {t: topic, a: args, k: kwargs, o: options, c: callback} if options[:acknowledge]
577
-
578
- # Send the message
579
- publish = WampClient::Message::Publish.new(request, options, topic, args, kwargs)
580
- self._send_message(publish)
581
- end
582
-
583
- # Processes the response to a publish request
584
- # @param msg [WampClient::Message::Published] The response from the subscribe
585
- def _process_PUBLISHED(msg)
586
-
587
- # Remove the pending publish and alert the callback
588
- p = self._requests[:publish].delete(msg.publish_request)
589
- if p
590
-
591
- details = {}
592
- details[:topic] = p[:t]
593
- details[:type] = 'publish'
594
- details[:publication] = msg.publication
595
- details[:session] = self
596
-
597
- c = p[:c]
598
- c.call(p, nil, details) if c
599
- end
600
-
601
- end
602
-
603
- # Processes an error from a publish request
604
- # @param msg [WampClient::Message::Error] The response from the subscribe
605
- def _process_PUBLISH_error(msg)
606
-
607
- # Remove the pending publish and inform the caller of the failure
608
- s = self._requests[:publish].delete(msg.request_request)
609
- if s
610
-
611
- details = msg.details || {}
612
- details[:topic] = s[:t] unless details[:topic]
613
- details[:type] = 'publish'
614
- details[:session] = self
615
-
616
- c = s[:c]
617
- c.call(nil, self._error_to_hash(msg), details) if c
618
- end
619
-
620
- end
621
-
622
- #endregion
623
-
624
- #region Register Logic
625
-
626
- # Register to a procedure
627
- # @param procedure [String] The procedure to register for
628
- # @param handler [lambda] The handler(args, kwargs, details) when an invocation is received
629
- # @param options [Hash, nil] The options for the registration
630
- # @param interrupt [lambda] The handler(request, mode) when an interrupt is received
631
- # @param callback [block] The callback(registration, error, details) called to signal if the registration was a success or not
632
- def register(procedure, handler, options=nil, interrupt=nil, &callback)
633
- unless is_open?
634
- raise RuntimeError, "Session must be open to call 'register'"
635
- end
636
-
637
- options ||= {}
638
-
639
- self.class.check_uri('procedure', procedure)
640
- self.class.check_nil('handler', handler, false)
641
-
642
- # Create a new registration request
643
- request = self._generate_id
644
- self._requests[:register][request] = {p: procedure, h: handler, i: interrupt, o: options, c: callback}
645
-
646
- # Send the message
647
- register = WampClient::Message::Register.new(request, options, procedure)
648
- self._send_message(register)
649
- end
650
-
651
- # Processes the response to a register request
652
- # @param msg [WampClient::Message::Registered] The response from the subscribe
653
- def _process_REGISTERED(msg)
654
-
655
- # Remove the pending subscription, add it to the registered ones, and inform the caller
656
- r = self._requests[:register].delete(msg.register_request)
657
- if r
658
- n_r = Registration.new(r[:p], r[:h], r[:o], r[:i], self, msg.registration)
659
- self._registrations[msg.registration] = n_r
660
-
661
- details = {}
662
- details[:procedure] = r[:p]
663
- details[:type] = 'register'
664
- details[:session] = self
665
-
666
- c = r[:c]
667
- c.call(n_r, nil, details) if c
668
- end
669
-
670
- end
671
-
672
- # Processes an error from a request
673
- # @param msg [WampClient::Message::Error] The response from the register
674
- def _process_REGISTER_error(msg)
675
-
676
- # Remove the pending registration and inform the caller of the failure
677
- r = self._requests[:register].delete(msg.request_request)
678
- if r
679
-
680
- details = msg.details || {}
681
- details[:procedure] = r[:p] unless details[:procedure]
682
- details[:type] = 'register'
683
- details[:session] = self
684
-
685
- c = r[:c]
686
- c.call(nil, self._error_to_hash(msg), details) if c
687
- end
688
-
689
- end
690
-
691
- # Sends an error back to the caller
692
- # @param request[Integer] - The request ID
693
- # @param error
694
- def _send_INVOCATION_error(request, error, check_defer=false)
695
- # Prevent responses for defers that have already completed or had an error
696
- if check_defer and not self._defers[request]
697
- return
698
- end
699
-
700
- if error.nil?
701
- error = CallError.new('wamp.error.runtime')
702
- elsif not error.is_a?(CallError)
703
- error = CallError.new('wamp.error.runtime', [error.to_s])
704
- end
705
-
706
- error_msg = WampClient::Message::Error.new(WampClient::Message::Types::INVOCATION, request, {}, error.error, error.args, error.kwargs)
707
- self._send_message(error_msg)
708
- end
709
-
710
- # Sends a result for the invocation
711
- # @param request [Integer] - The id of the request
712
- # @param result [CallError, CallResult, anything] - If it is a CallError, the error will be returned
713
- # @param options [Hash] - The options to be sent with the yield
714
- def yield(request, result, options={}, check_defer=false)
715
- # Prevent responses for defers that have already completed or had an error
716
- if check_defer and not self._defers[request]
717
- return
718
- end
719
-
720
- if result.nil?
721
- result = CallResult.new
722
- elsif result.is_a?(CallError)
723
- # Do nothing
724
- elsif not result.is_a?(CallResult)
725
- result = CallResult.new([result])
726
- end
727
-
728
- if result.is_a?(CallError)
729
- self._send_INVOCATION_error(request, result)
730
- else
731
- yield_msg = WampClient::Message::Yield.new(request, options, result.args, result.kwargs)
732
- self._send_message(yield_msg)
733
- end
734
- end
735
-
736
-
737
- # Processes and event from the broker
738
- # @param msg [WampClient::Message::Invocation] An procedure that was called
739
- def _process_INVOCATION(msg)
740
-
741
- request = msg.request
742
- args = msg.call_arguments || []
743
- kwargs = msg.call_argumentskw || {}
744
-
745
- details = msg.details || {}
746
- details[:request] = request
747
- details[:session] = self
748
-
749
- r = self._registrations[msg.registered_registration]
750
- if r
751
- h = r.handler
752
- if h
753
- begin
754
- value = h.call(args, kwargs, details)
755
-
756
- # If a defer was returned, handle accordingly
757
- if value.is_a? WampClient::Defer::CallDefer
758
- value.request = request
759
- value.registration = msg.registered_registration
760
-
761
- # Store the defer
762
- self._defers[request] = value
763
-
764
- # On complete, send the result
765
- value.on_complete do |defer, result|
766
- self.yield(defer.request, result, {}, true)
767
- self._defers.delete(defer.request)
768
- end
769
-
770
- # On error, send the error
771
- value.on_error do |defer, error|
772
- self._send_INVOCATION_error(defer.request, error, true)
773
- self._defers.delete(defer.request)
774
- end
775
-
776
- # For progressive, return the progress
777
- if value.is_a? WampClient::Defer::ProgressiveCallDefer
778
- value.on_progress do |defer, result|
779
- self.yield(defer.request, result, {progress: true}, true)
780
- end
781
- end
782
-
783
- # Else it was a normal response
784
- else
785
- self.yield(request, value)
786
- end
787
-
788
- rescue Exception => error
789
- self._send_INVOCATION_error(request, error)
790
- end
791
-
792
- end
793
- end
794
- end
795
-
796
- # Processes the interrupt
797
- # @param msg [WampClient::Message::Interrupt] An interrupt to a procedure
798
- def _process_INTERRUPT(msg)
799
-
800
- request = msg.invocation_request
801
- mode = msg.options[:mode]
802
-
803
- defer = self._defers[request]
804
- if defer
805
- r = self._registrations[defer.registration]
806
- if r
807
- # If it exists, call the interrupt handler to inform it of the interrupt
808
- i = r.i_handler
809
- error = nil
810
- if i
811
- begin
812
- error = i.call(request, mode)
813
- rescue Exception => e
814
- error = e
815
- end
816
- end
817
-
818
- error ||= 'interrupt'
819
-
820
- # Send the error back to the client
821
- self._send_INVOCATION_error(request, error, true)
822
- end
823
-
824
- # Delete the defer
825
- self._defers.delete(request)
826
- end
827
-
828
- end
829
-
830
- #endregion
831
-
832
- #region Unregister Logic
833
-
834
- # Unregisters from a procedure
835
- # @param registration [Registration] The registration object from when the registration was created
836
- # @param callback [block] The callback(registration, error, details) called to signal if the unregistration was a success or not
837
- def unregister(registration, &callback)
838
- unless is_open?
839
- raise RuntimeError, "Session must be open to call 'unregister'"
840
- end
841
-
842
- self.class.check_nil('registration', registration, false)
843
-
844
- # Create a new unsubscribe request
845
- request = self._generate_id
846
- self._requests[:unregister][request] = { r: registration, c: callback }
847
-
848
- # Send the message
849
- unregister = WampClient::Message::Unregister.new(request, registration.id)
850
- self._send_message(unregister)
851
- end
852
-
853
- # Processes the response to a unregister request
854
- # @param msg [WampClient::Message::Unregistered] The response from the unsubscribe
855
- def _process_UNREGISTERED(msg)
856
-
857
- # Remove the pending unregistration, add it to the registered ones, and inform the caller
858
- r = self._requests[:unregister].delete(msg.unregister_request)
859
- if r
860
- r_s = r[:r]
861
- self._registrations.delete(r_s.id)
862
-
863
- details = {}
864
- details[:procedure] = r_s.procedure
865
- details[:type] = 'unregister'
866
- details[:session] = self
867
-
868
- c = r[:c]
869
- c.call(r_s, nil, details) if c
870
- end
871
-
872
- end
873
-
874
- # Processes an error from a request
875
- # @param msg [WampClient::Message::Error] The response from the subscribe
876
- def _process_UNREGISTER_error(msg)
877
-
878
- # Remove the pending subscription and inform the caller of the failure
879
- r = self._requests[:unregister].delete(msg.request_request)
880
- if r
881
-
882
- details = msg.details || {}
883
- details[:procedure] = r[:r].procedure unless details[:procedure]
884
- details[:type] = 'unregister'
885
- details[:session] = self
886
-
887
- c = r[:c]
888
- c.call(nil, self._error_to_hash(msg), details) if c
889
- end
890
-
891
- end
892
-
893
- #endregion
894
-
895
- #region Call Logic
896
-
897
- # Publishes and event to a topic
898
- # @param procedure [String] The procedure to invoke
899
- # @param args [Array] The arguments
900
- # @param kwargs [Hash] The keyword arguments
901
- # @param options [Hash] The options for the call
902
- # @param callback [block] The callback(result, error, details) called to signal if the call was a success or not
903
- # @return [Call] An object representing the call
904
- def call(procedure, args=nil, kwargs=nil, options={}, &callback)
905
- unless is_open?
906
- raise RuntimeError, "Session must be open to call 'call'"
907
- end
908
-
909
- self.class.check_uri('procedure', procedure)
910
- self.class.check_dict('options', options)
911
- self.class.check_list('args', args, true)
912
- self.class.check_dict('kwargs', kwargs, true)
913
-
914
- # Create a new call request
915
- request = self._generate_id
916
- self._requests[:call][request] = {p: procedure, a: args, k: kwargs, o: options, c: callback}
917
-
918
- # Send the message
919
- msg = WampClient::Message::Call.new(request, options, procedure, args, kwargs)
920
- self._send_message(msg)
921
-
922
- call = Call.new(self, request)
923
-
924
- # Timeout Logic
925
- if options[:timeout] and options[:timeout] > 0
926
- self.transport.add_timer(options[:timeout]) do
927
- # Once the timer expires, if the call hasn't completed, cancel it
928
- if self._requests[:call][call.id]
929
- call.cancel
930
- end
931
- end
932
- end
933
-
934
- call
935
- end
936
-
937
- # Processes the response to a publish request
938
- # @param msg [WampClient::Message::Result] The response from the call
939
- def _process_RESULT(msg)
940
-
941
- details = msg.details || {}
942
-
943
- call = self._requests[:call][msg.call_request]
944
-
945
- # Don't remove if progress is true and the options had receive_progress true
946
- self._requests[:call].delete(msg.call_request) unless (details[:progress] and (call and call[:o][:receive_progress]))
947
-
948
- if call
949
- details[:procedure] = call[:p] unless details[:procedure]
950
- details[:type] = 'call'
951
- details[:session] = self
952
-
953
- c = call[:c]
954
- c.call(CallResult.new(msg.yield_arguments, msg.yield_argumentskw), nil, details) if c
955
- end
956
-
957
- end
958
-
959
- # Processes an error from a call request
960
- # @param msg [WampClient::Message::Error] The response from the call
961
- def _process_CALL_error(msg)
962
-
963
- # Remove the pending publish and inform the caller of the failure
964
- call = self._requests[:call].delete(msg.request_request)
965
- if call
966
-
967
- details = msg.details || {}
968
- details[:procedure] = call[:p] unless details[:procedure]
969
- details[:type] = 'call'
970
- details[:session] = self
971
-
972
- c = call[:c]
973
- c.call(nil, self._error_to_hash(msg), details) if c
974
- end
975
-
976
- end
977
-
978
- #endregion
979
-
980
- #region Cancel Logic
981
-
982
- # Cancels a call
983
- # @param call [Call] - The call object
984
- # @param mode [String] - The mode of the skip. Options are 'skip', 'kill', 'killnowait'
985
- def cancel(call, mode='skip')
986
- unless is_open?
987
- raise RuntimeError, "Session must be open to call 'cancel'"
988
- end
989
-
990
- self.class.check_nil('call', call, false)
991
-
992
- # Send the message
993
- cancel = WampClient::Message::Cancel.new(call.id, { mode: mode })
994
- self._send_message(cancel)
995
- end
996
-
997
- #endregion
998
-
999
- end
1000
- end