dot_net_services 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/LICENSE +21 -24
  2. data/README +26 -16
  3. data/Rakefile +65 -0
  4. data/lib/acs/saml_token_provider.rb +54 -0
  5. data/lib/acs/shared_secret_token_provider.rb +55 -0
  6. data/lib/acs/simple_api_auth_token_provider.rb +57 -0
  7. data/lib/acs/simple_web_token_provider.rb +54 -0
  8. data/lib/acs/token_constants.rb +112 -0
  9. data/lib/acs/token_info.rb +33 -0
  10. data/lib/acs/token_provider.rb +74 -0
  11. data/lib/acs/token_validator.rb +114 -0
  12. data/lib/common/dot_net_services_environment.rb +61 -0
  13. data/lib/common/environment.yml +23 -0
  14. data/lib/common/host_name_config.yml +45 -0
  15. data/lib/dot_net_services.rb +31 -144
  16. data/lib/service_bus/http_proxy.rb +34 -0
  17. data/lib/service_bus/locked_message_info.rb +34 -0
  18. data/lib/service_bus/message_buffer.rb +313 -0
  19. data/lib/service_bus/message_buffer_constants.rb +48 -0
  20. data/lib/service_bus/message_buffer_policy.rb +55 -0
  21. data/lib/service_bus/requests.rb +95 -0
  22. data/test/config/test_config.yml +40 -0
  23. data/test/dot_net_services_environment_test.rb +54 -0
  24. data/test/message_buffer_test.rb +96 -0
  25. data/test/token_test.rb +98 -0
  26. metadata +50 -48
  27. data/lib/dot_net_services/authentication.rb +0 -168
  28. data/lib/dot_net_services/error.rb +0 -4
  29. data/lib/dot_net_services/message_buffer.rb +0 -283
  30. data/lib/dot_net_services/session.rb +0 -308
  31. data/lib/net/http/create_mb.rb +0 -14
  32. data/lib/net/http/retrieve.rb +0 -14
  33. data/lib/net/http/subscribe.rb +0 -14
  34. data/lib/net/http/unsubscribe.rb +0 -14
  35. data/spec/integration/TestService/Service/AnonymousResourceService.cs +0 -9
  36. data/spec/integration/TestService/Service/App.config +0 -32
  37. data/spec/integration/TestService/Service/PlainTextService.cs +0 -37
  38. data/spec/integration/TestService/Service/Program.cs +0 -49
  39. data/spec/integration/TestService/Service/Properties/AssemblyInfo.cs +0 -33
  40. data/spec/integration/TestService/Service/ResourceContract.cs +0 -17
  41. data/spec/integration/TestService/Service/ResourceService.cs +0 -58
  42. data/spec/integration/TestService/Service/Service.csproj +0 -71
  43. data/spec/integration/TestService/TestService.sln +0 -33
  44. data/spec/integration/end_to_end_spec.rb +0 -84
  45. data/spec/integration/vmb_spec.rb +0 -30
  46. data/spec/spec_helper.rb +0 -23
  47. data/spec/unit/dot_net_services/authentication_spec.rb +0 -289
  48. data/spec/unit/dot_net_services/message_buffer_spec.rb +0 -161
  49. data/spec/unit/dot_net_services/session_spec.rb +0 -247
@@ -1,283 +0,0 @@
1
- require 'date'
2
-
3
- module DotNetServices
4
-
5
- # The MessageBuffer class is used for creating Volatile Message Buffer (VMB) endpoints on the .NET Services bus, and
6
- # retrieving messages from them.
7
- #
8
- # A VMB is a temporary message buffer that can be used for asynchronous communications between senders and receivers
9
- # of messages. A process may request creation of a VMB on any URL within a solution namespace. Any HTTP requests
10
- # (other than GETs) to that URL are stored in the buffer, until some process retrieves them by sending an HTTP
11
- # X-RETRIEVE request to the management endpoint.
12
- #
13
- # VMB can exist by itself, not tied to the lifecycle of a process that originally created it. Further information
14
- # about VMBs can be found in .NET Services portal [http://go.microsoft.com/fwlink/?LinkID=129428].
15
- #
16
- # == Usage examples
17
- #
18
- # MessageBuffer instance represents a VMB endpoint. Typical usage looks as follows:
19
- #
20
- # error_handler = lambda { |error| logger.error(error) }
21
- #
22
- # buffer = DotNetServices::MessageBuffer.open_and_poll(
23
- # "MySolution/MyVMB",
24
- # {:username => 'MySolution', :password => 'my_password'},
25
- # error_handler) do
26
- # |message|
27
- # ... process the message
28
- # end
29
- #
30
- # This invocation does all of the following:
31
- #
32
- # * Creates a MessageBuffer instance associated with a specified endpoint (/MySolution/MyVMB)
33
- # * obains a security token from trhe Identity service (see Session for details on that).
34
- # * Creates a VMB on the .NET Services bus if it doesn't exist yet
35
- # * immediately starts polling it
36
- # * if it retrieves a message, it passes it to the block. The message is an instance of Net::HTTP::Request that
37
- # looks exactly the same as what the sender originally sent to the bus.
38
- # * if an error occurs while polling, the error is passed to the error_handler block. Polling then continues.
39
- #
40
- # == Guidelines
41
- #
42
- # In cases where an application (which in this case means a process) needs to process multiple types of messages,
43
- # Microsoft recommends to create a single VMB per application, route all message types through the same VMB, and
44
- # route messages to appropriate processors within the application itself.
45
- #
46
- # In the current version of the API, we provide no explicit support for clustering message processors. If you use
47
- # MessageBuffer#open_and_poll(), it's recommended that you only run one cipy of a message processor. If clustering
48
- # is required (for high availability reasons), you can use lower-level MessageBuffer methods to do it.
49
- #
50
- # .NET Services VMBs provide pub-sub and multicast functionality which can be used even over plain HTTP. Which is
51
- # amazing. However, we don't support this functionality in the current version of our library.
52
- class MessageBuffer
53
-
54
- attr_reader :session
55
-
56
- class << self
57
-
58
- # Creates a MessageBuffer instance, acquires a security token, registers a VMB if necessary.
59
- # Unlike Session#open, +auth_data+ is mandatory here.
60
- # If given a block, passes the MessageBuffer instance to the block, and closes it at the end of the block
61
- # returns the result of the block (if called with a block), or the buffer instance opened
62
- def open(name, auth_data, &block)
63
- buffer = MessageBuffer.new(name, auth_data).open
64
- if block_given?
65
- begin
66
- return yield(buffer)
67
- ensure
68
- # TODO gracefully close the buffer
69
- end
70
- else
71
- return buffer
72
- end
73
- end
74
-
75
- # Invoke MessageBuffer#open to create a MessageBuffer instance, subscribe the buffer to receive messages
76
- # posted to the +subscription_endpoint+, then poll it until the containing thread or process is terminated.
77
- #
78
- # Whenever a message is retrieved from the buffer, this method passes it to the block. When an error occurs
79
- # (while polling, or raised by the block), it is passed to +error_handler+, which should be a lambda, or an
80
- # object with handle(error) public method. If no +error_handler+ is provided, the error is printed out
81
- # to STDERR and then ignored.
82
- def open_and_poll(name, subscription_endpoint, auth_data, error_handler=nil, &block)
83
- MessageBuffer.new(name, auth_data).open_and_poll(subscription_endpoint, error_handler, &block)
84
- end
85
- end
86
-
87
- # Initializes a new MessageBuffer instance.
88
- # Does not create a VMB on the .NET Services bus (use #open for that)
89
- def initialize(name, auth_data)
90
- @name = name
91
- @session = Session.new(name, auth_data)
92
- end
93
-
94
- # Register the message buffer (by sending X-CREATEMB to the management endpoint).
95
- #
96
- # Returns the buffer. Raises an exception if the creation is not successful.
97
- def register
98
- createmb_response = @session.createmb
99
-
100
- unless createmb_response.is_a?(Net::HTTPCreated)
101
- # the buffer may already be there
102
- unless @session.get_from_relay.is_a?(Net::HTTPSuccess)
103
- raise "Creating VMB failed. Service responded with #{createmb_response.class.name}"
104
- end
105
- end
106
- self
107
- end
108
-
109
- # Initiates a VMB session by:
110
- # * acquiring a security token
111
- # * checks if there is already a VMB at the endpoint
112
- # * creating a VMB if necessary
113
- def open
114
- register unless @session.get_from_relay.is_a?(Net::HTTPSuccess)
115
- self
116
- end
117
-
118
- # Open the buffer (see #open), subscribe the buffer to receive messages
119
- # posted to the +subscription_endpoint+, then poll it until the containing thread or
120
- # process is terminated.
121
- #
122
- # Whenever a message is retrieved from the buffer, this method passes it to the block. When an error occurs
123
- # (while polling, or raised by the block), it is passed to +error_handler+, which should be a lambda, or an
124
- # object with handle(error) public method. If no +error_handler+ is provided, the error is printed out
125
- # to STDERR and then ignored.
126
- def open_and_poll(subscription_endpoint, error_handler=nil, &block)
127
- raise "MessageBuffer#open_and_poll requires a block" unless block_given?
128
-
129
- @subscription_endpoint = subscription_endpoint
130
-
131
- open
132
- subscribe(@subscription_endpoint)
133
-
134
- begin
135
- loop do
136
- begin
137
- message = poll
138
- block.call(message) if message
139
- rescue Object => error
140
- if error_handler
141
- if error_handler.is_a?(Proc)
142
- error_handler.call(error)
143
- else
144
- error_handler.handle(error)
145
- end
146
- else
147
- STDERR.puts
148
- STDERR.puts "Message Buffer Error"
149
- STDERR.puts error.message
150
- STDERR.puts error.backtrace.map { |line| " #{line}"}
151
- STDERR.puts
152
- end
153
- end
154
- end
155
- ensure
156
- @subscription_endpoint = nil
157
- end
158
- end
159
-
160
- # Poll VMB endpoint for new messages; return the message if one was retrieved, or nil if it wasn't.
161
- #
162
- # Raises an exception if the response from the bus contains an error code (which usually means that the VMB is
163
- # not registered, but may mean other things, for example if the bus itself is not accessible for some reason).
164
- #
165
- # +timeout+ parameter regulates how long a polling request will be held by the bus if there are no messages.
166
- #
167
- # An HTTP server that holds HTTP connections because it has nothing to respond with is somewhat uncommon, so a
168
- # more detailed explanation is due.
169
- #
170
- # Normally, any HTTP interaction begins by opening of a TCP socket from the client to the server. The client
171
- # then writes the HTTP request into that socket and waits until the server responds back and closes the socket.
172
- # If the server doesn't respond for a long time (a minute, usually), the client drops the socket
173
- # and declares timeout.
174
- #
175
- # Many times, when you poll a VMB endpoint, it will have no messages. If the bus simply came back immediately with
176
- # "No Content" response, this would cause a VMB subscriber needs to constantly poll the buffer, abusing the bus
177
- # infrastructure.
178
- #
179
- # .NET Services gets around this problem by making the client connection hang for some time, either until there
180
- # is a message, or a certain number of seconds has passed, and there is still no message. That number of seconds is
181
- # what the +timeout+ parameter specifies. Microsoft suggested that 10-20 seconds is reasonable for
182
- # production purposes. Default value is 15 seconds.
183
- def poll(timeout=15)
184
- response = @session.retrieve(:encoding => 'asreply', :timeout => timeout)
185
- case response
186
- when Net::HTTPNoContent
187
- return nil
188
- when Net::HTTPNotFound
189
- register
190
- subscribe(@subscription_endpoint) if @subscription_endpoint
191
- return nil
192
- when Net::HTTPSuccess
193
- return response
194
- else
195
- raise "Retrieving messages failed. Response was #{response.class.name}" unless response.is_a?(Net::HTTPSuccess)
196
- end
197
- end
198
-
199
- # Delete the message buffer. This removes the buffer entirely
200
- # from the bus, not just the local reference to it.
201
- def delete
202
- response = @session.delete
203
-
204
- unless response.is_a?(Net::HTTPNoContent)
205
- raise "Deleting VMB failed. Response was #{response.class.name}"
206
- end
207
- self
208
- end
209
-
210
- # Queries the VMB management endpoint for the VMB expiry time. With every #poll (HTTP X-RETRIEVE to the VMB management
211
- # endpoint) the bus sets the expiry time of this VMB to 30 minutes later. If 30 minutes pass and there are no
212
- # further polls, the bus automatically delets the buffer.
213
- def expires
214
- response = @session.get_from_relay
215
-
216
- unless response.is_a?(Net::HTTPOK)
217
- raise "Querying expiry status of VMB failed. Response was #{response.class}"
218
- end
219
-
220
- expires_header = response["expires"]
221
- raise "Querying expiry status of VMB failed. Response doesn't have expires: header" unless expires_header
222
- DateTime.parse(expires_header)
223
- end
224
-
225
- # Performs an empty POST to the VMB management endpoint, which extends the VMB expiry time without retrieving any
226
- # messages.
227
- def keep_alive
228
- # if we don't pass a linefeed as a body to the VMB management endpoint, it responds with HTTP 411 Length Required
229
- response = @session.post_to_relay "\n"
230
- case response
231
- when Net::HTTPSuccess
232
- self
233
- else
234
- raise "POST to the VMB management endpoint failed. Response was #{response.class}"
235
- end
236
- end
237
-
238
- # Subscribe to an endpoint.
239
- #
240
- # HTTP messages sent to the +endpoint+ will be routed to this message buffer
241
- def subscribe(target_path)
242
- # Changes for .Net Services March 2009 CTP release (M5)
243
- tmpurl = @session.authenticator.username + "." + DotNetServices.root_url + "/" + target_path
244
-
245
- # Replace unwanted slashes
246
- tmpurl = tmpurl.gsub("\/\/\/", "\/")
247
- tmpurl = tmpurl.gsub("\/\/", "\/")
248
- subscription_endpoint_url = "http://" + tmpurl
249
-
250
- subscribe_response = @session.subscribe(:target => subscription_endpoint_url)
251
- case subscribe_response
252
- when Net::HTTPSuccess
253
- return self
254
- when Net::HTTPConflict
255
- unsubscribe(target_path)
256
- resubscribe_response = @session.subscribe(:target => subscription_endpoint_url)
257
- unless resubscribe_response.is_a?(Net::HTTPSuccess)
258
- raise "Second X-SUBSCRIBE to VMB management endpoint failed. Response was #{resubscribe_response.class}"
259
- end
260
- else
261
- raise "X-SUBSCRIBE to VMB management endpoint failed. Response was #{subscribe_response.class}"
262
- end
263
- end
264
-
265
- # Unsubscribe from an endpoint.
266
- def unsubscribe(target_path)
267
- # Changes for .Net Services March 2009 CTP release (M5)
268
- tmpurl = @session.authenticator.username + "." + DotNetServices.root_url + "/" + target_path
269
-
270
- # Replace unwanted slashes
271
- tmpurl = tmpurl.gsub("\/\/\/", "\/")
272
- tmpurl = tmpurl.gsub("\/\/", "\/")
273
- subscription_endpoint_url = "http://" + tmpurl
274
-
275
- unsubscribe_response = @session.unsubscribe(:target => subscription_endpoint_url)
276
- unless unsubscribe_response.is_a?(Net::HTTPSuccess)
277
- raise "X-UNSUBSCRIBE to VMB management endpoint failed. Response was #{subscribe_response.class}"
278
- end
279
- self
280
- end
281
-
282
- end
283
- end
@@ -1,308 +0,0 @@
1
- require 'uri'
2
- require 'cgi'
3
- require 'net/http'
4
- require 'net/http/unsubscribe'
5
-
6
- module DotNetServices
7
-
8
- # The Session class is used for communicating with endpoints of .NET Services bus.
9
- #
10
- # == Usage examples
11
- #
12
- # A Session instance represents a .NET Services bus endpoint. Typically, you create it by calling Session#open
13
- # and then exchange HTTP messages using methods like #get, #post, etc. It looks like this:
14
- #
15
- # Send a GET with no parameters:
16
- #
17
- # session = Session.open('/MySolution/MyService', :username => 'MySolution', :password => 'my_password')
18
- # get_response = session.get
19
- # # ... process response, which is a Net::HTTP::Response instance
20
- #
21
- # Send a GET with ?age=21&sex=Male query string:
22
- #
23
- # get_with_query_response = session.get :age => 21, :sex => "Male"
24
- #
25
- # Send a POST with name=Joe&email=joe@the_plumber.com (URL-encoded form) as a body:
26
- #
27
- # post_response = session.post :name => 'Joe', :email => 'joe@the_plumber.com'
28
- #
29
- # So far, Session API is similar to Net::HTTP::Session. Which is the whole point of the REST style
30
- # communication - it is all just HTTP! However, there is one small twist. HTTP::Session represents a server
31
- # (host and port). DotNetServices::Session represents a service endpoint. Which is a <b>URL</b>, not a server. In
32
- # fact, all .NET Services endpoints have the same server, servicebus.windows.net. So an endpoint address is really
33
- # just a path on that server.
34
- #
35
- # And sometimes you need to send requests to a path under the endpoint. For example, to update the name of customer
36
- # #12345, you would do a POST to /MySolution/Customer/12345 with &name=Dave body. Creating a new Session for that is
37
- # both counterintuitive and expensive (see the Details section below). For this reason, DotNetServices::Session has
38
- # methods like post_to_url:
39
- #
40
- # result = session.post_to_url(12345, :name => 'Dave')
41
- #
42
- # == Details
43
- #
44
- # When a session is created, it's given the URL of an endpoint (that looks like /SolutionName/path/to/service), and
45
- # username / password. These are <b>solution's</b> username and password, needed to prove to the bus that
46
- # your consumer is a part of this solution. If the solution allows anonymous access, username / password are not
47
- # necessary.
48
- #
49
- # When a session is opened (or is asked to send a first request to the endpoint), the session authenticates itself
50
- # to the .NET Services using Identity Service [http://accesscontrol.windows.net], and obtains a security token from it.
51
- #
52
- # Security token is a Base64-encoded string. Unless an endpoint allows unauthenticated access, any request that comes
53
- # to the endpoint must have this security token attached to it (as X-MS-Identity-Token HTTP header).
54
- # DotNetServices::Session takes care of this responsibility, as well as renewing stale tokens.
55
- #
56
- # Session also has methods get_from_relay and post_to_relay, that are used for communicating to the .NET Services
57
- # bus management endpoint. These methods (createmb, retrieve, query) are used by MessageBuffer, an application normally
58
- # shouldn't need to use them directly.
59
- #
60
- # == Guidelines
61
- #
62
- # Obtaining a security token is an expensive operation, so it is <b>not</b> recommended to create a new instance of
63
- # a Session for every outgoing request to the endpoint. It's better to use one Session instance per endpoint.
64
- # Session takes care of expiring security tokens autoimatically, so Session instances don't go stale even after long
65
- # periods of inactivity.
66
- class Session
67
-
68
- attr_reader :authenticator
69
-
70
- class << self
71
- # Open a .Net Services session at the +endpoint+.
72
- #
73
- # If +auth_data+ is provided, authenticates the session with
74
- # the identity service using it. In this version, +auth_data+ should be a hash containing +:username+ and
75
- # +:password+ keys. Other authentication mechanisms (InformationCard, X.509 certificates etc) that the Identity
76
- # service provides are not exposed via a REST interface, therefore are not available to this library.
77
- #
78
- # If #open is called with a block, it passes the session instance as an argument to the block and returns the
79
- # result of the block. If there is no block, session instance is returned instead.
80
- def open(endpoint, auth_data = nil, &block)
81
- Session.new(endpoint, auth_data).open(&block)
82
- end
83
- end
84
-
85
- # Initialize a new .NET Session at the +endpoint+.
86
- #
87
- # If +auth_data+ is provided, remember it. Acquiring
88
- # authentication token is postponed until it's needed.
89
- def initialize(endpoint, auth_data=nil)
90
- @endpoint_uri = setup_endpoint(endpoint)
91
- @authenticator = Authentication.setup(auth_data)
92
- end
93
-
94
- def initialize(endpoint, auth_data=nil)
95
- # Changes for .Net Services March 2009 CTP release (M5)
96
- username = String.new
97
- if auth_data.nil?
98
- elsif !auth_data.is_a? Hash
99
- else
100
- auth_data_copy = auth_data.dup
101
- username = auth_data_copy.delete(:username)
102
- end
103
-
104
- @endpoint_uri = setup_endpoint(endpoint, username)
105
- @authenticator = Authentication.setup(auth_data)
106
- end
107
-
108
- # See DotNetServices::Session.open.
109
- def open
110
- authenticate
111
- block_given? ? yield(self) : self
112
- end
113
-
114
- # Acquire a security token from the Identity Service.
115
- #
116
- # This method will do nothing if:
117
- # * this session already holds a security token and the token has not expired yet, or
118
- # * the session was created without auth_data (anonymous session)
119
- def authenticate
120
- @authenticator.authenticate
121
- end
122
-
123
- # Send a GET request to the .NET Services endpoint.
124
- #
125
- # If query options are provided, they should be a hash, and they are converted to a query string and attached to
126
- # the GET request target URL.
127
- # Thus, session.get(:foo => 'bar') sends a GET to #{endpoint}?foo=bar
128
- def get(query_options=nil)
129
- get_from_url(nil, query_options)
130
- end
131
-
132
-
133
- def get_from_url(url, query_options=nil)
134
- uri = setup_query_string(url, query_options)
135
- get_request = Net::HTTP::Get.new(uri.request_uri)
136
- enhance_and_execute(get_request)
137
- end
138
-
139
- # Sends a GET to the service management endpoint.
140
- #
141
- # This is used by MessageBuffer for VMB management. Applications shouldn't need to use this method.
142
- def get_from_relay(query_options=nil)
143
- uri = setup_query_string(nil, query_options)
144
- get_request = Net::HTTP::Get.new(uri.request_uri)
145
- route_to_relay(get_request)
146
- enhance_and_execute(get_request)
147
- end
148
-
149
- # Send a POST request to the .NET Services endpoint.
150
- #
151
- # If +data+ is a Hash it is converted to a URL-encoded form, otherwise it is placed in the post body without any
152
- # conversion.
153
- #
154
- # +content_type+ by default is set to +application/x-www-form-urlencoded+, which is appropriate when +data+ is a
155
- # Hash. In any other case, you should specify +content_type+ explicitly.
156
- def post(data=nil, content_type='application/x-www-form-urlencoded')
157
- post_to_url("", data, content_type)
158
- end
159
-
160
- # Sends a POST request to a path below .NET Services endpoint.
161
- #
162
- # If an application neeeds to send a POST to a service that uses URL to receive data, it should use this method
163
- # instead of creating a new session for every new request. For example, if a service endpoint is called
164
- # /Solution/Maps, and it's URL template is /Solution/Maps/*country*/*province*/*city*, a way to create a map of
165
- # Calgary would be:
166
- #
167
- # session.post_to_url('/Canada/Calgary', map_data, content_type=...)
168
- def post_to_url(url, data=nil, content_type='application/x-www-form-urlencoded')
169
- post_request = Net::HTTP::Post.new(@endpoint_uri.path + url.to_s)
170
- if data
171
- post_request.content_type = content_type
172
- if content_type == 'application/x-www-form-urlencoded'
173
- post_request.form_data = data
174
- else
175
- post_request.body = data
176
- end
177
- end
178
- enhance_and_execute(post_request)
179
- end
180
-
181
-
182
- # Sends a POST to the service management endpoint.
183
- #
184
- # This is used by MessageBuffer for VMB management. Applications should use MessageBuffer#keep_alive.
185
- def post_to_relay(data=nil, content_type='application/x-www-form-urlencoded')
186
- post_request = Net::HTTP::Post.new(@endpoint_uri.path)
187
-
188
- if data
189
- post_request.content_type = content_type
190
- if content_type == 'application/x-www-form-urlencoded'
191
- post_request.form_data = data
192
- else
193
- post_request.body = data
194
- end
195
- end
196
- route_to_relay(post_request)
197
- enhance_and_execute(post_request)
198
- end
199
-
200
- # Create a new message buffer (sends an X-CREATEMB to the service management endpoint).
201
- #
202
- # This is used by MessageBuffer for VMB management. Applications should use MessageBuffer#open.
203
- def createmb
204
- request = Net::HTTP::CreateMB.new(@endpoint_uri.path)
205
- route_to_relay(request)
206
- enhance_and_execute(request)
207
- end
208
-
209
- # Subscribe a message buffer to a virtual endpoint (sends an X-SUBSCRIBE to the VMB management endpoint).
210
- #
211
- # This is used by MessageBuffer for VMB management. Applications should use MessageBuffer#open.
212
- def subscribe(request_options)
213
- uri = setup_query_string(nil, request_options)
214
- request = Net::HTTP::Subscribe.new(uri.request_uri)
215
- route_to_relay(request)
216
- enhance_and_execute(request)
217
- end
218
-
219
- # Unsubscribe a message buffer from a virtual endpoint (sends an X-UNSUBSCRIBE to the VMB management endpoint).
220
- #
221
- # This is used by MessageBuffer for VMB management. Applications should use MessageBuffer#open.
222
- def unsubscribe(request_options)
223
- uri = setup_query_string(nil, request_options)
224
- request = Net::HTTP::Unsubscribe.new(uri.request_uri)
225
- route_to_relay(request)
226
- enhance_and_execute(request)
227
- end
228
-
229
- # Retrieve the next message from the message buffer (sends an X-RETRIEVE to the service management endpoint).
230
- #
231
- # This is used by MessageBuffer for VMB management. Applications should use MessageBuffer#poll.
232
- def retrieve(query_options={})
233
- query_options = stringify_and_downcase_keys(query_options)
234
- query_options['timeout'] ||= 15
235
- uri = setup_query_string(nil, query_options)
236
- request = Net::HTTP::Retrieve.new(uri.request_uri)
237
- route_to_relay(request)
238
- enhance_and_execute(request)
239
- end
240
-
241
-
242
- # Delete an endpoint (sends a DELETE to the service management endpoint).
243
- #
244
- # This is used by MessageBuffer for VMB management. Applications should use MessageBuffer#delete.
245
- def delete
246
- request = Net::HTTP::Delete.new(@endpoint_uri.path)
247
- route_to_relay(request)
248
- enhance_and_execute(request)
249
- end
250
-
251
- # The URL of a .NET services endpoint this Session is connected to.
252
- def endpoint
253
- @endpoint_uri.to_s
254
- end
255
-
256
- private
257
-
258
- def enhance_and_execute(request)
259
- @authenticator.enhance(request)
260
- DotNetServices.proxy.start(@endpoint_uri.host, @endpoint_uri.port) { |http| http.request(request) }
261
- end
262
-
263
- def route_to_relay(request)
264
- request['X-Process-At'] = 'http://schemas.microsoft.com/netservices/2009/05/servicebus/connect/roles/relay'
265
- end
266
-
267
- def setup_endpoint(endpoint, username)
268
- if endpoint !~ /^http(s?):\/\//
269
- endpoint = '/' + endpoint unless endpoint[0] == ?/
270
-
271
- # Changes for .Net Services March 2009 CTP release (M5)
272
- if !username.empty?
273
- tmpurl = username + "." + DotNetServices.root_url + "/" + endpoint
274
-
275
- # Replace unnecessary slashes
276
- tmpurl = tmpurl.gsub("\/\/\/", "\/")
277
- tmpurl = tmpurl.gsub("\/\/", "\/")
278
- endpoint = "http://" + tmpurl
279
- else
280
- raise "username must be provided to form the service bus endpoint."
281
- end
282
- end
283
- endpoint += '/' unless endpoint[-1] == ?/
284
-
285
- URI.parse(endpoint)
286
- end
287
- def setup_query_string(url, query_options)
288
- if url && !url.empty?
289
- uri = @endpoint_uri + url.to_s
290
- else
291
- uri = @endpoint_uri.dup
292
- end
293
-
294
- if query_options
295
- query = query_options.map { |k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join('&')
296
- uri.query = query
297
- end
298
- uri
299
- end
300
-
301
- def stringify_and_downcase_keys(options)
302
- new_options = {}
303
- options.each { |key, value| new_options[key.to_s.downcase] = value unless value.nil? }
304
- new_options
305
- end
306
-
307
- end
308
- end
@@ -1,14 +0,0 @@
1
- module Net # :nodoc:
2
- class HTTP # :nodoc:
3
- # Custom request type X-CREATEMB for creating message buffers on
4
- # the .NET Service Bus.
5
- #
6
- # This request should not be used directly. Use
7
- # DotNetServices::Session#createmb instead.
8
- class CreateMB < HTTPRequest
9
- METHOD = "X-CREATEMB"
10
- REQUEST_HAS_BODY = false
11
- RESPONSE_HAS_BODY = true
12
- end
13
- end
14
- end
@@ -1,14 +0,0 @@
1
- module Net # :nodoc:
2
- class HTTP # :nodoc:
3
- # Custom X-RETRIEVE for retrieving messages from the .NET Services
4
- # message buffer.
5
- #
6
- # This request should not be used directly. Use
7
- # DotNetServices::Session#retrieve instead.
8
- class Retrieve < HTTPRequest
9
- METHOD = "X-RETRIEVE"
10
- REQUEST_HAS_BODY = false
11
- RESPONSE_HAS_BODY = true
12
- end
13
- end
14
- end
@@ -1,14 +0,0 @@
1
- module Net # :nodoc:
2
- class HTTP # :nodoc:
3
- # Custom request type X-CREATEMB for creating message buffers on
4
- # the .NET Service Bus.
5
- #
6
- # This request should not be used directly. Use
7
- # DotNetServices::Session#createmb instead.
8
- class Subscribe < HTTPRequest
9
- METHOD = "X-SUBSCRIBE"
10
- REQUEST_HAS_BODY = false
11
- RESPONSE_HAS_BODY = true
12
- end
13
- end
14
- end
@@ -1,14 +0,0 @@
1
- module Net # :nodoc:
2
- class HTTP # :nodoc:
3
- # Custom request type X-CREATEMB for creating message buffers on
4
- # the .NET Service Bus.
5
- #
6
- # This request should not be used directly. Use
7
- # DotNetServices::Session#createmb instead.
8
- class Unsubscribe < HTTPRequest
9
- METHOD = "X-UNSUBSCRIBE"
10
- REQUEST_HAS_BODY = false
11
- RESPONSE_HAS_BODY = true
12
- end
13
- end
14
- end
@@ -1,9 +0,0 @@
1
- namespace DotNetServicesRuby
2
- {
3
- using System.ServiceModel;
4
-
5
- [ServiceBehavior(Name = "SyndicationService", Namespace = "http://samples.microsoft.com/ServiceModel/Relay/")]
6
- class AnonymousResourceService : ResourceService
7
- {
8
- }
9
- }