Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Client for talking to a WAMP Router. This is defined here
Note: wamp_rails has been deprecated in favor of wamp-worker which allows this library to be run in a RAILS worker. It will also allow integration with Sidekiq to support allowing handlers to execute in the background.
Add this line to your application's Gemfile:
gem 'wamp_client'
And then execute:
$ bundle
Or install it yourself as:
$ gem install wamp_client
The connection object is used to instantiate and maintain a WAMP session as well as the underlying transport. A user creates a connection and then operates on the session once the session has been established.
Note that once "connection.open" is called, the library will automatically attempt to reconnect if the connection closes for any reason. Calling "connection.close" will stop the reconnect logic as well as close the connection if it is open
A connection can be created as follows
require 'wamp/client'
connection = Wamp::Client::Connection.new(uri: 'ws://127.0.0.1:8080/ws', realm: 'realm1')
connection.on(:join) do |session, details|
puts "Session Open"
# Register for something
def add(args, kwargs, details)
args[0] + args[1]
end
session.register('com.example.procedure', method(:add)) do |registration, error, details|
# Call It
session.call('com.example.procedure', [3,4]) do |result, error, details|
if result
puts result[:args][0] # => 7
end
end
end
end
connection.open
A connection is closed by simply calling "close"
connection.close
Note that the connection will still call "on(:leave)" and "on(:disconnect)" as it closes the session and the transport
A connection has the following callbacks
on(:connect) - Called when the transport is opened
connection.on(:connect) do
end
on(:join) - Called when the session is established
connection.on(:join) do |session, details|
end
on(:leave) - Called when the session is terminated
connection.on(:leave) do |reason, details|
end
on(:disconnect) - Called when the connection is terminated
connection.on(:disconnect) do |reason|
end
on(:challenge) - Called when an authentication challenge is created
connection.on(:challenge) do |authmethod, extra|
end
You can run a task on every event machine tick by using the transport class method 'add_tick_loop'
require 'wamp/client'
connection = Wamp::Client::Connection.new(uri: 'ws://127.0.0.1:8080/ws', realm: 'realm1')
connection.transport_class.add_tick_loop do
# Do something periodic
end
By default, the library will use the "websocket-eventmachine-client" Gem as the websocket transport. However the library also supports overriding this.
To use this library, do the following
Install the "faye-websocket" Gem:
$ gem install faye-websocket
Override the transport by doing the following:
require 'wamp/client'
options = {
uri: 'ws://127.0.0.1:8080/ws',
realm: 'realm1',
proxy: { # See faye-websocket documentation
:origin => 'http://username:password@proxy.example.com',
:headers => {'User-Agent' => 'ruby'}
},
transport: Wamp::Client::Transport::FayeWebSocket
}
connection = Wamp::Client::Connection.new(options)
# More code
Note that the "faye-wesbsocket" transport supports passing in a "proxy" as shown above.
You can also create your own transports by wrapping them in a "Transport" object and including as shown above. For more details on this, see the files in "lib/wamp_client/transport"
The library supports authentication. Here is how to perform the different methods
To perform WAMP CRA, do the following
require 'wamp/client'
options = {
uri: 'ws://127.0.0.1:8080/ws',
realm: 'realm1',
authid: 'joe',
authmethods: ['wampcra']
}
connection = Wamp::Client::Connection.new(options)
connection.on(:challenge) do |authmethod, extra|
puts 'Challenge'
if authmethod == 'wampcra'
Wamp::Client::Auth::Cra.sign('secret', extra[:challenge])
else
raise RuntimeError, "Unsupported auth method #{authmethod}"
end
end
connection.on(:join) do |session, details|
puts "Session Open"
end
connection.open
This library makes extensive use of "blocks", "lambdas", "procs", and method pointers for any returned values because all communication is performed asynchronously. The library defines two types of methods
Note that all callbacks can be set to nil, handlers however cannot since the user is explicitly setting them up.
All handlers are called with the following parameters
Some examples of this are shown below
lambda
handler = lambda do |args, kwargs, details|
# TODO: Do Something!!
end
session.subscribe('com.example.topic', handler)
method
def handler(args, kwargs, details)
# TODO: Do Something!!
end
session.subscribe('com.example.topic', method(:handler))
All callbacks are called with the following parameters
An example of this is shown below
session.call('com.example.procedure') do |result, error, details|
# TODO: Do something
end
This method subscribes to a topic. The prototype for the method is
def subscribe(topic, handler, options={}, &callback)
where the parameters are defined as
To subscribe, do the following
handler = lambda do |args, kwargs, details|
# TODO: Do something
end
session.subscribe('com.example.topic', handler)
If you would like confirmation of the success of the subscription, do the following
handler = lambda do |args, kwargs, details|
# TODO: Do something
end
session.subscribe('com.example.topic', handler) do |subscription, error, details|
# TODO: Do something
end
Options are
This method unsubscribes from a topic. The prototype for the method is as follows
def unsubscribe(subscription, &callback)
where the parameters are defined as
To unsubscribe, do the following
handler = lambda do |args, kwargs, details|
# TODO: Do something
end
session.subscribe('com.example.topic', handler) do |subscription, error, details|
@subscription = subscription
end
# At some later time...
session.unsubscribe(@subscription)
# or ...
@subscription.unsubscribe
This method publishes an event to all of the subscribers. The prototype for the method is
def publish(topic, args=nil, kwargs=nil, options={}, &callback)
where the parameters are defined as
To publish, do the following
session.publish('com.example.topic', [15], {param: value})
If you would like confirmation, do the following
session.publish('com.example.topic', [15], {param: value}, {acknowledge: true}, callback) do |publish, error, details|
# TODO: Do something
end
Options are
This method registers to a procedure. The prototype for the method is
def register(procedure, handler, options={}, &callback)
where the parameters are defined as
To register, do the following
handler = lambda do |args, kwargs, details|
# TODO: Do something
end
session.register('com.example.procedure', handler)
If you would like confirmation of the success of the registration, do the following
handler = lambda do |args, kwargs, details|
# TODO: Do something
end
session.register('com.example.procedure', handler, {}, callback) do |registration, error, details|
# TODO: Do something
end
Options are
This method unregisters from a procedure. The prototype for the method is as follows
def unregister(registration, &callback)
where the parameters are defined as
To unregister, do the following
handler = lambda do |args, kwargs, details|
# TODO: Do something
end
session.register('com.example.procedure', handler, {}) do |registration, error, details|
@registration = registration
end
# At some later time...
session.unregister(@registration)
# or ...
@registration.unregister
This method calls a procedure. The prototype for the method is
def call(procedure, args=nil, kwargs=nil, options={}, &callback)
where the parameters are defined as
To call, do the following
session.call('com.example.procedure', [15], {param: value}, {}) do |result, error, details|
# TODO: Do something
args = result[:args]
kwargs = result[:kwargs]
end
Options are
Errors can either be raised OR returned as shown below
handler = lambda do |args, kwargs, details|
raise RuntimeError,'error'
# OR
raise Wamp::Client::Response::CallError.new('wamp.error', ['some error'], {details: true})
# OR
Wamp::Client::Response::CallError.new('wamp.error', ['some error'], {details: true})
end
session.register('com.example.procedure', handler)
All 3 of the above examples will return a WAMP Error
A deferred call refers to a call where the response needs to be asynchronously fetched before it can be returned to the caller. This is shown below
def add(args, kwargs, details)
defer = Wamp::Client::Response::CallDefer.new
EM.add_timer(2) { # Something Async
defer.succeed(args[0]+args[1])
}
defer
end
session.register('com.example.procedure', method(:add))
Errors are returned as follows
def add(args, kwargs, details)
defer = Wamp::Client::Response::CallDefer.new
EM.add_timer(2) { # Something Async
defer.fail(Wamp::Client::Response::CallError.new('test.error'))
}
defer
end
session.register('com.example.procedure', method(:add))
Progressive calls are ones that return the result in pieces rather than all at once. They are invoked as follows
Caller
results = []
session.call('com.example.procedure', [], {}, {receive_progress: true}) do |result, error, details|
results = results + result[:args]
unless details[:progress]
puts results # => [1,2,3,4,5,6]
end
end
Callee
def add(args, kwargs, details)
defer = Wamp::Client::Response::ProgressiveCallDefer.new
EM.add_timer(2) { # Something Async
defer.progress(Wamp::Client::Response::CallResult.new([1,2,3]))
}
EM.add_timer(4) { # Something Async
defer.progress(Wamp::Client::Response::CallResult.new([4,5,6]))
}
EM.add_timer(6) { # Something Async
defer.succeed(Wamp::Client::Response::CallResult.new)
}
defer
end
session.register('com.example.procedure', method(:add))
A cancelled call will tell a callee who implements a progressive call to cancel it
Caller
call = session.call('com.example.procedure', [15], {param: value}, {}) do |result, error, details|
# TODO: Do something
args = result[:args]
kwargs = result[:kwargs]
end
# At some later time...
session.cancel(call, 'skip') # Options are 'skip', 'kill', or 'killnowait'
# or ...
call.cancel('skip')
Callee
(There is probably a better way to do this. This is a bad example)
@interrupts = {}
def interrupt_handler(request, mode)
@interrups[request] = mode
# To trigger a custom error, either return something or raise a "CallError"
# else the library will raise a standard error for you
end
def add(args, kwargs, details)
defer = Wamp::Client::Response::ProgressiveCallDefer.new
EM.add_timer(2) { # Something Async
if @interrupts[defer.request].nil?
defer.progress(Wamp::Client::Response::CallResult.new([1,2,3]))
end
}
EM.add_timer(4) { # Something Async
if @interrupts[defer.request].nil?
defer.progress(Wamp::Client::Response::CallResult.new([4,5,6]))
end
}
EM.add_timer(6) { # Something Async
if @interrupts[defer.request].nil?
defer.succeed(Wamp::Client::Response::CallResult.new)
end
@interrupts.delete(request)
}
defer
end
session.register('com.example.procedure', method(:add), nil, method(:interrupt_handler))
Notes:
git checkout -b my-new-feature
)git commit -am 'Add some feature'
)git push origin my-new-feature
)The unit tests are run as follows
$ bundle exec rake spec
The lib/wamp_client/message.rb file and the spec/message_spec.rb file are autogenerated using the script scripts/gen_message.rb. This is done as follows
$ cd scripts
$ ./gen_message.rb
$ mv message.rb.tmp ../lib/wamp/client/message.rb
$ mv message_spec.rb.tmp ../spec/wamp/client/message_spec.rb
As I was writing the code for the messages I caught myself cutting and pasting allot and decided these would be better suited to be autogenerated.
FAQs
Unknown package
We found that wamp_client demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.