wamp_client 0.1.4 → 0.2.0

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +34 -32
  3. data/lib/wamp/client/auth.rb +0 -27
  4. data/lib/wamp/client/check.rb +0 -27
  5. data/lib/wamp/client/connection.rb +40 -113
  6. data/lib/wamp/client/event.rb +78 -0
  7. data/lib/wamp/client/manager/base.rb +39 -0
  8. data/lib/wamp/client/manager/base_multiple.rb +37 -0
  9. data/lib/wamp/client/manager/establish.rb +168 -0
  10. data/lib/wamp/client/manager/registration.rb +183 -0
  11. data/lib/wamp/client/manager/require.rb +3 -0
  12. data/lib/wamp/client/manager/subscription.rb +55 -0
  13. data/lib/wamp/client/request/base.rb +125 -0
  14. data/lib/wamp/client/request/call.rb +111 -0
  15. data/lib/wamp/client/request/publish.rb +72 -0
  16. data/lib/wamp/client/request/register.rb +79 -0
  17. data/lib/wamp/client/request/require.rb +6 -0
  18. data/lib/wamp/client/request/subscribe.rb +78 -0
  19. data/lib/wamp/client/request/unregister.rb +71 -0
  20. data/lib/wamp/client/request/unsubscribe.rb +72 -0
  21. data/lib/wamp/client/response.rb +136 -0
  22. data/lib/wamp/client/serializer.rb +0 -29
  23. data/lib/wamp/client/session.rb +172 -839
  24. data/lib/wamp/client/transport/base.rb +4 -77
  25. data/lib/wamp/client/transport/event_machine_base.rb +0 -27
  26. data/lib/wamp/client/transport/faye_web_socket.rb +4 -31
  27. data/lib/wamp/client/transport/web_socket_event_machine.rb +3 -30
  28. data/lib/wamp/client/version.rb +1 -28
  29. data/lib/wamp/client.rb +1 -28
  30. data/spec/spec_helper.rb +3 -137
  31. data/spec/support/faye_web_socket_client_stub.rb +43 -0
  32. data/spec/support/test_transport.rb +50 -0
  33. data/spec/support/web_socket_event_machine_client_stub.rb +39 -0
  34. data/spec/wamp/client/connection_spec.rb +4 -4
  35. data/spec/wamp/client/session_spec.rb +135 -135
  36. data/spec/wamp/client/transport_spec.rb +2 -2
  37. data/wamp_client.gemspec +10 -9
  38. metadata +59 -38
  39. data/lib/wamp/client/defer.rb +0 -70
@@ -0,0 +1,168 @@
1
+ require_relative "base"
2
+
3
+ module Wamp
4
+ module Client
5
+ module Manager
6
+
7
+ class Establish < Base
8
+ attr_accessor :goodbye_sent, :id, :realm
9
+
10
+ WAMP_FEATURES = {
11
+ caller: {
12
+ features: {
13
+ caller_identification: true,
14
+ call_timeout: true,
15
+ call_canceling: true,
16
+ progressive_call_results: true
17
+ }
18
+ },
19
+ callee: {
20
+ features: {
21
+ caller_identification: true,
22
+ ##call_trustlevels: true,
23
+ pattern_based_registration: true,
24
+ shared_registration: true,
25
+ ##call_timeout: true,
26
+ call_canceling: true,
27
+ progressive_call_results: true,
28
+ registration_revocation: true
29
+ }
30
+ },
31
+ publisher: {
32
+ features: {
33
+ publisher_identification: true,
34
+ subscriber_blackwhite_listing: true,
35
+ publisher_exclusion: true
36
+ }
37
+ },
38
+ subscriber: {
39
+ features: {
40
+ publisher_identification: true,
41
+ ##publication_trustlevels: true,
42
+ pattern_based_subscription: true,
43
+ subscription_revocation: true
44
+ ##event_history: true,
45
+ }
46
+ }
47
+ }
48
+
49
+ # Constructor
50
+ #
51
+ def initialize(session, send_message)
52
+ super session, send_message
53
+
54
+ self.id = nil
55
+ self.realm = nil
56
+ self.goodbye_sent = false
57
+ end
58
+
59
+ # Returns true if the session is open
60
+ #
61
+ def is_open?
62
+ self.id != nil
63
+ end
64
+
65
+ # Will attempt to join a router
66
+ #
67
+ def join(realm)
68
+
69
+ # Set the realm
70
+ self.realm = realm
71
+
72
+ # Create the details
73
+ details = {}
74
+ details[:roles] = WAMP_FEATURES
75
+ details[:agent] = "Ruby-Wamp::Client-#{VERSION}"
76
+ details[:authid] = self.session.options[:authid] if self.session.options[:authid]
77
+ details[:authmethods] = self.session.options[:authmethods] if self.session.options[:authmethods]
78
+
79
+ # Create the message
80
+ hello = Message::Hello.new(realm, details)
81
+
82
+ # Send it
83
+ send_message(hello)
84
+ end
85
+
86
+ # Leave the session
87
+ def leave(reason, message)
88
+
89
+ # Create the details
90
+ details = {}
91
+ details[:message] = message
92
+
93
+ # Create the goobdbye message
94
+ goodbye = Message::Goodbye.new(details, reason)
95
+
96
+ # Send it
97
+ send_message(goodbye)
98
+
99
+ # Send it
100
+ self.goodbye_sent = true
101
+ end
102
+
103
+ # Handles the goodbye message
104
+ #
105
+ def goodbye(message)
106
+ # If we didn't send the goodbye, respond
107
+ unless self.goodbye_sent
108
+ goodbye = Message::Goodbye.new({}, 'wamp.error.goodbye_and_out')
109
+ send_message(goodbye)
110
+ end
111
+
112
+ # Close out session
113
+ self.id = nil
114
+ self.realm = nil
115
+ self.goodbye_sent = false
116
+
117
+ # Trigger leave event
118
+ trigger :leave, message.reason, message.details
119
+ end
120
+
121
+ # Handles the welcome message
122
+ #
123
+ def welcome(message)
124
+ # Get the session ID
125
+ self.id = message.session
126
+
127
+ # Log the message
128
+ logger.info("#{self.session.class.name} joined session with realm '#{message.details[:realm]}'")
129
+
130
+ # Trigger join event
131
+ trigger :join, message.details
132
+ end
133
+
134
+ # Handles a challenge message
135
+ #
136
+ def challenge(message)
137
+ # Log challenge received
138
+ logger.debug("#{self.session.class.name} auth challenge '#{message.authmethod}', extra: #{message.extra}")
139
+
140
+ # Call the callback if set
141
+ signature, extra = trigger :challenge, message.authmethod, message.extra
142
+
143
+ # Set with initial values
144
+ signature ||= ''
145
+ extra ||= {}
146
+
147
+ # Create the message
148
+ authenticate = Message::Authenticate.new(signature, extra)
149
+
150
+ # Send it
151
+ send_message(authenticate)
152
+ end
153
+
154
+ # Handles an abort message
155
+ #
156
+ def abort(message)
157
+ # Log leaving the session
158
+ logger.info("#{self.session.class.name} left session '#{message.reason}'")
159
+
160
+ # Trigger the leave event
161
+ trigger :leave, message.reason, message.details
162
+ end
163
+
164
+ end
165
+
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,183 @@
1
+ require_relative "base_multiple"
2
+ require 'wamp/client/response'
3
+
4
+ module Wamp
5
+ module Client
6
+ module Manager
7
+
8
+ class RegistrationObject
9
+ attr_accessor :procedure, :handler, :i_handler, :options, :session, :id
10
+
11
+ def initialize(procedure, handler, options, i_handler, session, id)
12
+ self.procedure = procedure
13
+ self.handler = handler
14
+ self.options = options
15
+ self.i_handler = i_handler
16
+ self.session = session
17
+ self.id = id
18
+ end
19
+
20
+ def unregister
21
+ self.session.unregister(self)
22
+ end
23
+
24
+ end
25
+
26
+ class Registration < BaseMultiple
27
+ attr_reader :defers
28
+
29
+ # Constructor
30
+ #
31
+ # @param session [Wamp::Client::Session] - The session
32
+ # @param success [Block] - A block to run when the request was successful
33
+ def initialize(session, send_message)
34
+ super session, send_message
35
+ @defers = {}
36
+ end
37
+
38
+ # Processes an incoming call
39
+ #
40
+ # @param message [Message::Event] - The incoming invoke message
41
+ def invoke(message)
42
+
43
+ # Get the arguments
44
+ registration_id = message.registered_registration
45
+ request_id = message.request
46
+ args = message.call_arguments || []
47
+ kwargs = message.call_argumentskw || {}
48
+
49
+ # If we have a registration, execute it
50
+ registration = self.objects[registration_id]
51
+ if registration
52
+
53
+ # Create the details
54
+ details = message.details || {}
55
+ details[:request] = request_id
56
+ details[:procedure] = registration.procedure
57
+ details[:session] = self
58
+
59
+ handler = registration.handler
60
+ if handler
61
+ # Use the invoke wrapper to process the result
62
+ value = Response.invoke_handler do
63
+ handler.call(args, kwargs, details)
64
+ end
65
+
66
+ # If a defer was returned, handle accordingly
67
+ if value.is_a? Response::CallDefer
68
+ value.request = request_id
69
+ value.registration = registration_id
70
+
71
+ # Store the defer
72
+ self.defers[request_id] = value
73
+
74
+ # On complete, send the result
75
+ value.on :complete do |defer, result|
76
+ result = Response::CallResult.ensure(result)
77
+ self.yield(defer.request, result, {}, true)
78
+ end
79
+
80
+ # On error, send the error
81
+ value.on :error do |defer, error|
82
+ error = Response::CallError.ensure(error)
83
+ self.yield(defer.request, error, {}, true)
84
+ end
85
+
86
+ # For progressive, return the progress
87
+ if value.is_a? Response::ProgressiveCallDefer
88
+ value.on :progress do |defer, result|
89
+ result = Response::CallResult.ensure(result)
90
+ self.yield(defer.request, result, { progress: true }, true)
91
+ end
92
+ end
93
+
94
+ # Else it was a normal response
95
+ else
96
+ self.yield(request_id, value)
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ # Processes a yield request
103
+ #
104
+ def yield(request_id, result, options={}, check_defer=false)
105
+ # Prevent responses for defers that have already completed or had an error
106
+ if check_defer and not self.defers[request_id]
107
+ return
108
+ end
109
+
110
+ # Wrap the result accordingly
111
+ result = Response::CallResult.ensure(result, allow_error: true)
112
+
113
+ # Send either the error or the response
114
+ if result.is_a?(Response::CallError)
115
+ send_error(request_id, result)
116
+ else
117
+ yield_msg = Message::Yield.new(request_id, options, result.args, result.kwargs)
118
+ send_message(yield_msg)
119
+ end
120
+
121
+ # Remove the defer if this was not a progress update
122
+ if check_defer and not options[:progress]
123
+ self.defers.delete(request_id)
124
+ end
125
+
126
+ end
127
+
128
+ # Call Interrupt Handler
129
+ #
130
+ def interrupt(message)
131
+
132
+ # Get parameters
133
+ request_id = message.invocation_request
134
+ mode = message.options[:mode]
135
+
136
+ # Check if we have a pending request
137
+ defer = self.defers[request_id]
138
+ if defer
139
+ registration = self.objects[defer.registration]
140
+ if registration
141
+ # If it exists, call the interrupt handler to inform it of the interrupt
142
+ i_handler = registration.i_handler
143
+ error = nil
144
+ if i_handler
145
+ error = Response.invoke_handler error: true do
146
+ i_handler.call(request_id, mode)
147
+ end
148
+
149
+ # Add a default reason if none was supplied
150
+ error.args << "interrupt" if error.args.count == 0
151
+ end
152
+
153
+ # Send the error back to the client
154
+ send_error(request_id, error)
155
+ end
156
+
157
+ # Delete the defer
158
+ self.defers.delete(request_id)
159
+ end
160
+
161
+ end
162
+
163
+ private
164
+
165
+ def send_error(request_id, error)
166
+ # Make sure the response is an error
167
+ error = Response::CallError.ensure(error)
168
+
169
+ # Create error message
170
+ error_msg = Message::Error.new(
171
+ Message::Types::INVOCATION,
172
+ request_id, {},
173
+ error.error, error.args, error.kwargs)
174
+
175
+ # Send it
176
+ send_message(error_msg)
177
+ end
178
+
179
+ end
180
+
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,3 @@
1
+ require 'wamp/client/manager/subscription'
2
+ require 'wamp/client/manager/registration'
3
+ require 'wamp/client/manager/establish'
@@ -0,0 +1,55 @@
1
+ require_relative "base_multiple"
2
+
3
+ module Wamp
4
+ module Client
5
+ module Manager
6
+
7
+ class SubscriptionObject
8
+ attr_accessor :topic, :handler, :options, :session, :id
9
+
10
+ def initialize(topic, handler, options, session, id)
11
+ self.topic = topic
12
+ self.handler = handler
13
+ self.options = options
14
+ self.session = session
15
+ self.id = id
16
+ end
17
+
18
+ def unsubscribe
19
+ self.session.unsubscribe(self)
20
+ end
21
+
22
+ end
23
+
24
+ class Subscription < BaseMultiple
25
+
26
+ # Processes and incoming event
27
+ #
28
+ # @param message [Message::Event] - The incoming event message
29
+ def event(message)
30
+
31
+ # Get the arguments
32
+ subscription_id = message.subscribed_subscription
33
+ args = message.publish_arguments || []
34
+ kwargs = message.publish_argumentskw || {}
35
+
36
+ # If we have a subscription, execute it
37
+ subscription = self.objects[subscription_id]
38
+ if subscription
39
+
40
+ # Create the detials
41
+ details = message.details || {}
42
+ details[:publication] = message.published_publication
43
+ details[:topic] = subscription.topic
44
+ details[:session] = self.session
45
+
46
+ # Call the handler
47
+ handler = subscription.handler
48
+ handler.call(args, kwargs, details) if handler
49
+ end
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,125 @@
1
+ module Wamp
2
+ module Client
3
+ module Request
4
+
5
+ class Message::Error
6
+ def request_id
7
+ self.request_request
8
+ end
9
+ end
10
+
11
+ # The request base class is used to abstract all of the requests that
12
+ # will go to the broker/dealer. The model supports a request followed
13
+ # by a response that is either a "success" or an error
14
+ class Base
15
+ attr_reader :requests, :session, :send_message_callback, :on_success
16
+
17
+ # Constructor
18
+ #
19
+ # @param session [Wamp::Client::Session] - The session
20
+ # @param send_message [lambda] - A lambda to send the message
21
+ # @param success [Block] - A block to run when the request was successful
22
+ def initialize(session, send_message, &on_success)
23
+ @requests = {}
24
+ @session = session
25
+ @send_message_callback = send_message
26
+ @on_success = on_success
27
+ end
28
+
29
+ # Generates a new ID for the request according to the specification
30
+ # (Section 5.1.2)
31
+ #
32
+ # @param [Int] - A new ID
33
+ def generate_id
34
+ rand(0..9007199254740992)
35
+ end
36
+
37
+ # Makes the request to the broker/dealer
38
+ #
39
+ # @return [Int] - request_id
40
+ def request(*args, &callback)
41
+
42
+ # Generate an ID
43
+ request_id = self.generate_id
44
+
45
+ # Get the unique lookup/message for the request
46
+ lookup, message = self.create_request(request_id, *args, &callback)
47
+
48
+ # Store in the pending requests
49
+ self.requests[request_id] = lookup if lookup
50
+
51
+ # Send the message
52
+ send_message(message)
53
+
54
+ request_id
55
+ end
56
+
57
+ # Called when the response was a success
58
+ #
59
+ def success(message)
60
+ # Get the request_id
61
+ request_id = message.request_id
62
+
63
+ # Get the lookup
64
+ lookup = self.requests[request_id]
65
+
66
+ # Parse the result
67
+ callback, result, details, should_keep = self.process_success(message, lookup)
68
+
69
+ if callback and details
70
+ # Add items to details
71
+ details[:session] = self.session
72
+
73
+ # Call the callback
74
+ callback.call(result, nil, details) if callback
75
+ end
76
+
77
+ # Delete if "should_keep" if false
78
+ self.requests.delete(request_id) unless should_keep
79
+ end
80
+
81
+ def error(message)
82
+ # Get the request_id
83
+ request_id = message.request_id
84
+
85
+ # Get the lookup
86
+ lookup = self.requests.delete(request_id)
87
+
88
+ # Parse the result
89
+ callback, details = self.process_error(message, lookup)
90
+
91
+ if callback and details
92
+ # Add items to details
93
+ details[:session] = self.session
94
+
95
+ # Create the error
96
+ error = Response::CallError.from_message(message)
97
+
98
+ # Call the callback
99
+ callback.call(nil, error.to_hash, details) if callback
100
+ end
101
+ end
102
+
103
+ #region Override Methods
104
+ def create_request(*args)
105
+ end
106
+
107
+ def process_success(message, lookup)
108
+ end
109
+
110
+ def process_error(message, lookup)
111
+ end
112
+ #endregion
113
+
114
+ private
115
+
116
+ # Sends a message
117
+ #
118
+ def send_message(message)
119
+ self.send_message_callback.call(message) if self.send_message_callback
120
+ end
121
+
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,111 @@
1
+ require_relative "base"
2
+ require "wamp/client/message"
3
+
4
+ module Wamp
5
+ module Client
6
+ module Request
7
+
8
+ class Message::Result
9
+ def request_id
10
+ self.call_request
11
+ end
12
+ end
13
+
14
+ class CallObject
15
+ attr_accessor :session, :id
16
+
17
+ def initialize(session, id)
18
+ self.session = session
19
+ self.id = id
20
+ end
21
+
22
+ def cancel(mode='skip')
23
+ self.session.cancel(self, mode)
24
+ end
25
+
26
+ end
27
+
28
+ class Call < Base
29
+
30
+ # Method specific to this request that will cancel it
31
+ #
32
+ def cancel(request_id, mode='skip')
33
+
34
+ # If the request is still in flight
35
+ if self.requests[request_id]
36
+ # Create the message
37
+ message = Message::Cancel.new(request_id, { mode: mode })
38
+
39
+ # Send it
40
+ send_message(message)
41
+ end
42
+
43
+ end
44
+
45
+ def create_request(request_id, procedure, args=nil, kwargs=nil, options={}, &callback)
46
+
47
+ # Create the lookup
48
+ lookup = {p: procedure, a: args, k: kwargs, o: options, c: callback}
49
+
50
+ # Create the message
51
+ message = Message::Call.new(request_id, options, procedure, args, kwargs)
52
+
53
+ # Return
54
+ [lookup, message]
55
+ end
56
+
57
+ def process_success(message, lookup)
58
+ if lookup
59
+ # Get the params
60
+ procedure = lookup[:p]
61
+ options = lookup[:o] || {}
62
+ callback = lookup[:c]
63
+
64
+ # Create the details
65
+ details = message.details || {}
66
+ details[:procedure] = procedure unless details[:procedure]
67
+ details[:type] = 'call'
68
+
69
+ # Set the should keep flag if this is a progress message
70
+ should_keep = details[:progress]
71
+
72
+ # Only return the information if not progress or receive progress is true
73
+ if not details[:progress] or (details[:progress] and options[:receive_progress])
74
+
75
+ # Create the response
76
+ result = Response::CallResult.from_yield_message(message)
77
+
78
+ # Return the values
79
+ [callback, result.to_hash, details, should_keep]
80
+
81
+ else
82
+ [nil, nil, nil, should_keep]
83
+ end
84
+ else
85
+ [nil, nil, nil]
86
+ end
87
+ end
88
+
89
+ def process_error(message, lookup)
90
+ if lookup
91
+ # Get the params
92
+ procedure = lookup[:p]
93
+ callback = lookup[:c]
94
+
95
+ # Create the details
96
+ details = message.details || {}
97
+ details[:procedure] = procedure unless details[:procedure]
98
+ details[:type] = 'call'
99
+
100
+ # Return the values
101
+ [callback, details]
102
+ else
103
+ [nil, nil]
104
+ end
105
+ end
106
+
107
+ end
108
+
109
+ end
110
+ end
111
+ end