wamp_client 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 72e6d6b94bf4b5f244885438e6c122c952d5d084
4
+ data.tar.gz: 0366993e7d42a1e3673210af8c8b4a05b63206e9
5
+ SHA512:
6
+ metadata.gz: 0de90b5fc4cdf71d2e76b587a232530b47fb8e0ebd961c5a77299f130714c575ac36061a5c0bdeb75de5a535d9711a07523b79360d1d1c777738f0314f70179a
7
+ data.tar.gz: bf65fac58f124abb76d0c4518067f28f2046a29ffcb1d7fb0aede645654ae9d445ffeafded1c3d94aa759e316f9fd2738f38c72f8a2c3b4d2550a6ff21f6a4e8
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ .idea
16
+ *.tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in wamp_client.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 Eric Chapman
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,464 @@
1
+ # WampClient
2
+
3
+ [![Circle CI](https://circleci.com/gh/ericchapman/ruby_wamp_client/tree/master.svg?&style=shield&circle-token=92813c17f9c9510c4c644e41683e7ba2572e0b2a)](https://circleci.com/gh/ericchapman/ruby_wamp_client/tree/master)
4
+ [![Codecov](https://img.shields.io/codecov/c/github/ericchapman/ruby_wamp_client/master.svg)](https://codecov.io/github/ericchapman/ruby_wamp_client)
5
+
6
+ Client for talking to a WAMP Router. This is defined at
7
+
8
+ https://tools.ietf.org/html/draft-oberstet-hybi-tavendo-wamp-02
9
+
10
+ ## Revision History
11
+
12
+ - v0.0.1:
13
+ - Initial Release
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'wamp_client'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install wamp_client
30
+
31
+ ## Usage
32
+
33
+ ### Connection
34
+ The connection object is used to instantiate and maintain a WAMP session as well as the underlying transport. A user
35
+ creates a connection and then operates on the session once the session has been established.
36
+
37
+ Note that once "connection.open" is called, the library will automatically attempt to reconnect if the connection
38
+ closes for any reason. Calling "connection.close" will stop the reconnect logic as well as close the connection if it
39
+ is open
40
+
41
+ #### Creating a connection
42
+ A connection can be created as follows
43
+
44
+ ```ruby
45
+ require 'wamp_client'
46
+
47
+ options = {
48
+ uri: 'ws://127.0.0.1:8080/ws',
49
+ realm: 'realm1'
50
+ }
51
+ connection = WampClient::Connection.new(options)
52
+
53
+ connection.on_join do |session, details|
54
+ puts "Session Open"
55
+
56
+ # Register for something
57
+ def add(args, kwargs, details)
58
+ args[0] + args[1]
59
+ end
60
+ session.register('com.example.procedure', method(:add)) do |registration, error, details|
61
+
62
+ # Call It
63
+ session.call('com.example.procedure', [3,4]) do |result, error, details|
64
+ if result
65
+ puts result.args[0] # => 7
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+
72
+ end
73
+
74
+ connection.open
75
+ ```
76
+
77
+ #### Closing a connection
78
+ A connection is closed by simply calling "close"
79
+
80
+ ```ruby
81
+ connection.close
82
+ ```
83
+
84
+ Note that the connection will still call "on_leave" and "on_disconnect" as it closes the session and the transport
85
+
86
+ #### Callbacks
87
+ A session has the following callbacks
88
+
89
+ **on_connect** - Called when the transport is opened
90
+ ```ruby
91
+ connection.on_connect do
92
+
93
+ end
94
+ ```
95
+
96
+ **on_join** - Called when the session is established
97
+ ```ruby
98
+ connection.on_join do |session, details|
99
+
100
+ end
101
+ ```
102
+
103
+ **on_leave** - Called when the session is terminated
104
+ ```ruby
105
+ connection.on_leave do |reason, details|
106
+
107
+ end
108
+ ```
109
+
110
+ **on_disconnect** - Called when the connection is terminated
111
+ ```ruby
112
+ connection.on_disconnect do |reason|
113
+
114
+ end
115
+ ```
116
+
117
+ **oon_challenge** - Called when an authentication challenge is created
118
+ ```ruby
119
+ connection.on_challenge do |authmethod, extra|
120
+
121
+ end
122
+ ```
123
+
124
+ ### Authentication
125
+ The library supports authentication. Here is how to perform the different methods
126
+
127
+ #### WAMPCRA
128
+ To perform WAMP CRA, do the following
129
+
130
+ ```ruby
131
+ require 'wamp_client'
132
+
133
+ options = {
134
+ uri: 'ws://127.0.0.1:8080/ws',
135
+ realm: 'realm1',
136
+ authid: 'joe',
137
+ authmethods: ['wampcra']
138
+ }
139
+ connection = WampClient::Connection.new(options)
140
+
141
+ connection.on_challenge do |authmethod, extra|
142
+ puts 'Challenge'
143
+ if authmethod == 'wampcra'
144
+ WampClient::Auth::Cra.sign('secret', extra[:challenge])
145
+ else
146
+ raise RuntimeError, "Unsupported auth method #{authmethod}"
147
+ end
148
+ end
149
+
150
+ connection.on_join do |session, details|
151
+ puts "Session Open"
152
+ end
153
+
154
+ connection.open
155
+ ```
156
+
157
+ ### Handlers and Callbacks
158
+ This library makes extensive use of "blocks", "lambdas", "procs", and method pointers for any returned values because
159
+ all communication is performed asynchronously. The library defines two types of methods
160
+
161
+ - handlers - Can be called **AT ANY TIME**. These can be blocks, lambdas, procs, or method pointers
162
+ - callbacks - Only invoked in response to specific call. These are only blocks
163
+
164
+ Note that all callbacks can be set to nil, handlers however cannot since the user is explicitly setting them up.
165
+
166
+ #### Handlers
167
+ All handlers are called with the following parameters
168
+
169
+ - args [Array] - Array of arguments
170
+ - kwargs [Hash] - Hash of key/value arguments
171
+ - details [Hash] - Hash containing some details about the call
172
+
173
+ Some examples of this are shown below
174
+
175
+ **lambda**
176
+
177
+ ```ruby
178
+ handler = lambda do |args, kwargs, details|
179
+ # TODO: Do Something!!
180
+ end
181
+ session.subscribe('com.example.topic', handler)
182
+ ```
183
+
184
+ **method**
185
+
186
+ ```ruby
187
+ def handler(args, kwargs, details)
188
+ # TODO: Do Something!!
189
+ end
190
+ session.subscribe('com.example.topic', method(:handler))
191
+ ```
192
+
193
+ #### Callbacks
194
+ All callbacks are called with the following parameters
195
+
196
+ - result [Object] - Some object with the result information (depends on the call)
197
+ - error [Hash] - Hash containing "error", "args", and "kwargs" if an error occurred
198
+ - details [Hash] - Hash containing some details about the call
199
+
200
+ An example of this is shown below
201
+
202
+ ```ruby
203
+ session.call('com.example.procedure') do |result, error, details|
204
+ # TODO: Do something
205
+ end
206
+ ```
207
+
208
+ ### Topic Subscriptions and Publications
209
+
210
+ #### Subscribe
211
+ This method subscribes to a topic. The prototype for the method is
212
+
213
+ ```ruby
214
+ subscribe(topic, handler, options={}, &callback)
215
+ ```
216
+
217
+ where the parameters are defined as
218
+
219
+ - topic [String] - The topic to subscribe to
220
+ - handler [lambda] - The handler(args, kwargs, details) when an event is received
221
+ - options [Hash] - The options for the subscription
222
+ - callback [block] - The callback(subscription, error, details) called to signal if the subscription was a success or not
223
+
224
+ To subscribe, do the following
225
+
226
+ ```ruby
227
+ handler = lambda do |args, kwargs, details|
228
+ # TODO: Do something
229
+ end
230
+
231
+ session.subscribe('com.example.topic', handler)
232
+ ```
233
+
234
+ If you would like confirmation of the success of the subscription, do the following
235
+
236
+ ```ruby
237
+ handler = lambda do |args, kwargs, details|
238
+ # TODO: Do something
239
+ end
240
+
241
+ session.subscribe('com.example.topic', handler) do |subscription, error, details|
242
+ # TODO: Do something
243
+ end
244
+ ```
245
+
246
+ Options are
247
+
248
+ - match [String] - "exact", "prefix", or "wildcard"
249
+
250
+ #### Unsubscribe
251
+ This method unsubscribes from a topic. The prototype for the method is as follows
252
+
253
+ ```ruby
254
+ def unsubscribe(subscription, &callback)
255
+ ```
256
+
257
+ where the parameters are defined as
258
+
259
+ - subscription [Subscription] - The subscription object from when the subscription was created
260
+ - callback [block] - The callback(subscription, error, details) called to signal if the unsubscription was a success or not
261
+
262
+ To unsubscribe, do the following
263
+
264
+ ```ruby
265
+ handler = lambda do |args, kwargs, details|
266
+ # TODO: Do something
267
+ end
268
+
269
+ session.subscribe('com.example.topic', handler) do |subscription, error, details|
270
+ @subscription = subscription
271
+ end
272
+
273
+ # At some later time...
274
+
275
+ session.unsubscribe(@subscription)
276
+
277
+ # or ...
278
+
279
+ @subscription.unsubscribe
280
+
281
+ ```
282
+
283
+ #### Publish
284
+ This method publishes an event to all of the subscribers. The prototype for the method is
285
+
286
+ ```ruby
287
+ publish(topic, args=nil, kwargs=nil, options={}, &callback)
288
+ ```
289
+
290
+ where the parameters are defined as
291
+
292
+ - topic [String] - The topic to publish the event to
293
+ - args [Array] - The arguments
294
+ - kwargs [Hash] - The keyword arguments
295
+ - options [Hash] - The options for the subscription
296
+ - callback [block] - The callback(publish, error, details) is called to signal if the publish was a success or not
297
+
298
+ To publish, do the following
299
+
300
+ ```ruby
301
+ session.publish('com.example.topic', [15], {param: value})
302
+ ```
303
+
304
+ If you would like confirmation, do the following
305
+
306
+ ```ruby
307
+ session.publish('com.example.topic', [15], {param: value}, {acknowledge: true}, callback) do |publish, error, details|
308
+ # TODO: Do something
309
+ end
310
+ ```
311
+
312
+ Options are
313
+
314
+ - acknowledge [Boolean] - set to "true" if you want the Broker to acknowledge if the Publish was successful or not
315
+ - disclose_me [Boolean] - "true" if the publisher would like the subscribers to know his identity
316
+ - exclude [Array[Integer]] - Array of session IDs to exclude
317
+ - exclude_authid [Array[String]] - Array of auth IDs to exclude
318
+ - exclude_authrole [Array[String]] - Array of auth roles to exclude
319
+ - eligible [Array[Integer]] - Array of session IDs to include
320
+ - eligible_authid [Array[String]] - Array of auth IDs to include
321
+ - eligible_authrole [Array[String]] - Array of auth roles to include
322
+ - exclude_me [Boolean] - set to "false" if you would like yourself to receive an event that you fired
323
+
324
+ ### Procedure Registrations and Calls
325
+
326
+ #### Register
327
+ This method registers to a procedure. The prototype for the method is
328
+
329
+ ```ruby
330
+ register(procedure, handler, options={}, &callback)
331
+ ```
332
+
333
+ where the parameters are defined as
334
+
335
+ - procedure [String] - The procedure to register for
336
+ - handler [lambda] - The handler(args, kwargs, details) when a invocation is received
337
+ - options [Hash] - The options for the registration
338
+ - callback [block] - The callback(registration, error, details) called to signal if the registration was a success or not
339
+
340
+ To register, do the following
341
+
342
+ ```ruby
343
+ handler = lambda do |args, kwargs, details|
344
+ # TODO: Do something
345
+ end
346
+
347
+ session.register('com.example.procedure', handler)
348
+ ```
349
+
350
+ If you would like confirmation of the success of the registration, do the following
351
+
352
+ ```ruby
353
+ handler = lambda do |args, kwargs, details|
354
+ # TODO: Do something
355
+ end
356
+
357
+ session.register('com.example.procedure', handler, {}, callback) do |registration, error, details|
358
+ # TODO: Do something
359
+ end
360
+ ```
361
+
362
+ Options are
363
+
364
+ - match [String] - "exact", "prefix", or "wildcard"
365
+ - invoke [String] - "single", "roundrobin", "random", "first", "last"
366
+
367
+ #### Unregister
368
+ This method unregisters from a procedure. The prototype for the method is as follows
369
+
370
+ ```ruby
371
+ def unregister(registration, &callback)
372
+ ```
373
+
374
+ where the parameters are defined as
375
+
376
+ - registration [Registration] - The registration object from when the registration was created
377
+ - callback [lambda] - The callback(registration, error, details) called to signal if the unregistration was a success
378
+ or not
379
+
380
+ To unregister, do the following
381
+
382
+ ```ruby
383
+ handler = lambda do |args, kwargs, details|
384
+ # TODO: Do something
385
+ end
386
+
387
+ session.register('com.example.procedure', handler, {}) do |registration, error, details|
388
+ @registration = registration
389
+ end
390
+
391
+ # At some later time...
392
+
393
+ session.unregister(@registration)
394
+
395
+ # or ...
396
+
397
+ @registration.unregister
398
+
399
+ ```
400
+
401
+ #### Call
402
+ This method calls a procedure. The prototype for the method is
403
+
404
+ ```ruby
405
+ call(procedure, args=nil, kwargs=nil, options={}, &callback)
406
+ ```
407
+
408
+ where the parameters are defined as
409
+
410
+ - procedure [String] - The procedure to invoke
411
+ - args [Array] - The arguments
412
+ - kwargs [Hash] - The keyword arguments
413
+ - options [Hash] - The options for the call
414
+ - callback [block] - The callback(result, error, details) called to signal if the call was a success or not
415
+
416
+ To call, do the following
417
+
418
+ ```ruby
419
+ session.call('com.example.procedure', [15], {param: value}, {}) do |result, error, details|
420
+ # TODO: Do something
421
+ args = result.args
422
+ kwargs = result.kwargs
423
+ end
424
+ ```
425
+
426
+ Options are
427
+
428
+ - receive_progress [Boolean] - "true" if you support results being able to be sent progressively
429
+ - disclose_me [Boolean] - "true" if the caller would like the callee to know the identity
430
+
431
+ ## Contributing
432
+
433
+ 1. Fork it ( https://github.com/ericchapman/ruby_wamp_client )
434
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
435
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
436
+ 4. Push to the branch (`git push origin my-new-feature`)
437
+ 5. Create a new Pull Request
438
+
439
+ ### TODOs
440
+
441
+ - progressive_call_results (callee)
442
+ - call_timeout
443
+ - call_canceling
444
+
445
+ ### Testing
446
+
447
+ The unit tests are run as follows
448
+
449
+ $ bundle exec rake spec
450
+
451
+ ### Scripts
452
+
453
+ #### Message
454
+
455
+ The *lib/wamp_client/message.rb* file and the *spec/message_spec.rb* file are autogenerated using the script
456
+ *scripts/gen_message.rb*. This is done as follows
457
+
458
+ $ cd scripts
459
+ $ ./gen_message.rb
460
+ $ mv message.rb.tmp ../lib/wamp_client/message.rb
461
+ $ mv message_spec.rb.tmp ../spec/message_spec.rb
462
+
463
+ As I was writing the code for the messages I caught myself cutting and pasting allot and decided these would be
464
+ better suited to be autogenerated.
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ Dir.glob('tasks/**/*.rake').each(&method(:import))
data/circle.yml ADDED
@@ -0,0 +1,3 @@
1
+ test:
2
+ post:
3
+ - bundle exec rake spec
@@ -0,0 +1,18 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+
4
+ module WampClient
5
+ module Auth
6
+ module Cra
7
+
8
+ # Generates the signature from the challenge
9
+ # @param key [String]
10
+ # @param challenge [String]
11
+ def self.sign(key, challenge)
12
+ hash = OpenSSL::HMAC.digest('sha256', key, challenge)
13
+ Base64.encode64(hash).gsub(/\n/,'')
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,57 @@
1
+ module WampClient
2
+ module Check
3
+
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+
10
+ def check_equal(name, expected, value)
11
+ raise ArgumentError, "The '#{name}' argument must have the value '#{expected}'. Instead the value was '#{value}'" unless value == expected
12
+ end
13
+
14
+ def check_gte(name, expected, value)
15
+ raise ArgumentError, "The '#{name}' argument must be greater than or equal to '#{expected}'. Instead the value was '#{value}'" unless value >= expected
16
+ end
17
+
18
+ def check_nil(name, param, nil_allowed)
19
+ raise ArgumentError, "The '#{name}' argument cannot be nil" if param.nil? and not nil_allowed
20
+ end
21
+
22
+ def check_int(name, param, nil_allowed=false)
23
+ check_nil(name, param, nil_allowed)
24
+ raise ArgumentError, "The '#{name}' argument must be an integer" unless param.nil? or param.is_a? Integer
25
+ end
26
+
27
+ def check_string(name, param, nil_allowed=false)
28
+ check_nil(name, param, nil_allowed)
29
+ raise ArgumentError, "The '#{name}' argument must be a string" unless param.nil? or param.is_a? String
30
+ end
31
+
32
+ def check_bool(name, param, nil_allowed=false)
33
+ check_nil(name, param, nil_allowed)
34
+ raise ArgumentError, "The '#{name}' argument must be a boolean" unless param.nil? or !!param == param
35
+ end
36
+
37
+ def check_dict(name, param, nil_allowed=false)
38
+ check_nil(name, param, nil_allowed)
39
+ raise ArgumentError, "The '#{name}' argument must be a hash" unless param.nil? or param.is_a? Hash
40
+ end
41
+
42
+ def check_list(name, param, nil_allowed=false)
43
+ check_nil(name, param, nil_allowed)
44
+ raise ArgumentError, "The '#{name}' argument must be an array" unless param.nil? or param.is_a? Array
45
+ end
46
+
47
+ def check_uri(name, param, nil_allowed=false)
48
+ check_string(name, param, nil_allowed)
49
+ end
50
+
51
+ def check_id(name, param, nil_allowed=false)
52
+ check_int(name, param, nil_allowed)
53
+ end
54
+ end
55
+
56
+ end
57
+ end