wamp_client 0.1.4 → 0.2.0

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