Product Promotion
0x5a.live
for different kinds of informations and explorations.
GitHub - MyMedsAndMe/spell: Spell is a Web Application Messaging Protocol (WAMP) client implementation in Elixir. WAMP is an open standard WebSocket subprotocol that provides two application messaging patterns in one unified protocol: Remote Procedure Calls + Publish & Subscribe: http://wamp.ws/
Spell is a Web Application Messaging Protocol (WAMP) client implementation in Elixir. WAMP is an open standard WebSocket subprotocol that provides two application messaging patterns in one unified ...
Visit SiteGitHub - MyMedsAndMe/spell: Spell is a Web Application Messaging Protocol (WAMP) client implementation in Elixir. WAMP is an open standard WebSocket subprotocol that provides two application messaging patterns in one unified protocol: Remote Procedure Calls + Publish & Subscribe: http://wamp.ws/
Spell is a Web Application Messaging Protocol (WAMP) client implementation in Elixir. WAMP is an open standard WebSocket subprotocol that provides two application messaging patterns in one unified ...
Powered by 0x5a.live 💗
spell [DEPRECATED]
Spell is an Elixir WAMP client implementing the basic profile specification.
Reason for fork
For spellchecking old symposium
Oficial readme
Why WAMP?
WAMP is the Web Application Message Protocol supported by Tavendo. It's an open standard WebSocket subprotocol that provides two application messaging patterns in one unified protocol: Remote Procedure Calls + Publish & Subscribe.
Why Spell?
- Flexible interface: one line blocking calls or raw message handling -- use whichever tool works best.
- Robust peers: peer processes are supervised, and will restart or retry when appropriate.
- Easy to extend: add new roles, transports, or serializers without changing the core library:
Getting Help
Spell uses GitHub issues and pull requests for development.
Spell has a mailing list at [email protected]; general questions or ideas are welcome there. See librelist for how to sign up.
Using Spell with your Elixir Project
To use Spell from within your Elixir library add, add it to your mix.exs
deps,
along with the required transport and serialization libraries:
defp deps do
[
...
# Required:
{:spell, "~> 0.1"},
# Required if using the websocket transport:
{:websocket_client, github: "jeremyong/websocket_client", tag: "v0.7"},
# Required if using the JSON serializer:
{:poison, "~> 1.4"},
# Required if using the msgpack serializer:
{:msgpax, "~> 0.7"}
]
end
Fetch the dependencies by running:
$ mix deps.get
How it Works
You can run the examples you're about to run into, though first you'll need crossbar.io. You might install it via pip:
$ pip install crossbar
If you are going to use MessagePack you will need to install the optional crossbar package.
$ pip install crossbar[msgpack]
Start an Elixir shell:
$ iex -S mix
Start up Crossbar.io:
iex> Crossbar.start()
To stop Crossbar.io from IEx:
iex> Crossbar.stop()
You can find more detailed documentation at any time by checking
the source code documentation. Spell
provides an entry point:
iex> h Spell
You can hit C-c C-c to exit the shell. Be sure to stop Crossbar.io first.
Peers
In WAMP, messages are exchanged between peers. Peers are assigned a set of roles which define how they handle messages. A client peer (Spell!) may have any choice of client roles, and a server peer may have any choice of server roles.
There are two functional groupings of roles:
- PubSub
- Publisher
- Subscriber
- Broker [Server]
- RPC
- Caller
- Callee
- Dealer [Server]
By default a client peer is started with the above four client roles:
Spell.connect("ws://example.org", realm: "realm1")
See Spell.Peer
and Spell.Role
.
Authentication
Spell supports WAMP Challenge Response Authentication (CRA). This is flexible, and can be used to back a variety of authentication schemes.
To setup a Spell peer with authentication:
alias Spell.Authentication.CRA
authentication = [id: "harry", schemes: [{CRA, [secret: "alohamora"]}]]
Spell.connect("ws://example.org", realm: "realm1",
authentication: authentication)
See Spell.Authentication
.
PubSub
Once subscribed to a topic, the subscriber will receive all messages published to that topic.
# Events must be published to a topic.
topic = "com.spell.example.pubsub.topic"
# Create a peer with the subscriber role.
subscriber = Spell.connect(Crossbar.uri,
realm: Crossbar.get_realm(),
roles: [Spell.Role.Subscriber])
# `call_subscribe/2,3` synchronously subscribes to the topic.
{:ok, subscription} = Spell.call_subscribe(subscriber, topic)
# Create a peer with the publisher role.
publisher = Spell.connect(Crossbar.uri,
realm: Crossbar.get_realm(),
roles: [Spell.Role.Publisher])
# `call_publish/2,3` synchronously publishes a message to the topic.
{:ok, publication} = Spell.call_publish(publisher, topic)
# `receive_event/2,3` blocks to receive the event.
case Spell.receive_event(publisher, subscription) do
{:ok, event} -> handle_event(event)
{:error, reason} -> {:error, reason}
end
# Cleanup.
for peer <- [subscriber, publisher], do: Spell.close(peer)
See Spell.Role.Publisher
and Spell.Role.Subscriber
for more information.
Pattern-based subscriptions
By default, peers subscribe to topics using an exact matching policy. Using pattern-based subscriptions a peer can receive messages that match certain criteria.
# assuming we have a subscriber peer connected
# exact match
{:ok, subscription} = Spell.call_subscribe(subscriber, "com.spell.my_topic")
# subscriber will receive messages published in the "com.spell.my_topic" topic
# prefix match
{:ok, subscription} = Spell.call_subscribe(subscriber, "com.spell.my_topic_prefix", options: %{match: :prefix})
# subscriber will receive messages published in topics:
# "com.spell.my_topic_prefix.foo", "com.spell.my_topic_prefix.bar", ...
# wildcard match
{:ok, subscription} = Spell.call_subscribe(subscriber, "com.spell..my_topic", options: %{match: :wildcard})
# subscriber will receive messages published in topics:
# "com.spell.foo.my_topic", "com.spell.bar.my_topic", ...
RPC
RPC allows a caller to call a procedure using a remote callee.
Let's start with the caller's half:
# Calls are sent to a particular procedure.
procedure = "com.spell.example.rpc.procedure"
# Create a peer with the callee role.
caller = Spell.connect(Crossbar.uri,
realm: Crossbar.get_realm(),
roles: [Spell.Role.Callee])
# `call_register/2,3` synchronously calls the procedure with the arguments.
{:ok, registration} = Spell.call(subscriber, procedure,
arguments: ["args"],
arguments_kw: %{})
Spell.close(caller)
In addition to the synchronous Spell.call_...
type functions described so far,
Spell includes asynchronous Spell.cast_...
functions. To handle the result of
these messages you can use a Spell.receive_...
helper, or, most flexibly,
use a receive
clause.
Next is a contrived example showing the RPC caller and the callee being used from a single process. Note how asynchronous casts and receive functions are used to avoid a deadlock.
Note: I omitted the arguments
and arguments_kw
options for brevity's sake.
# Calls are sent to a particular procedure.
procedure = "com.spell.example.rpc.procedure"
# Create a peer with the callee role.
callee = Spell.connect(Crossbar.uri,
realm: Crossbar.get_realm(),
roles: [Spell.Role.Callee])
# `call_register/2,3` synchronously registers the procedure.
{:ok, registration} = Spell.call_register(callee, procedure)
# Create a peer with the caller role.
caller = Spell.connect(Crossbar.uri,
realm: Crossbar.get_realm(),
roles: [Spell.Role.Caller])
# `cast_call/2,3` asynchronously calls the procedure.
{:ok, call} = Spell.cast_call(caller, procedure)
# `receive_invocation/2,3` blocks until it receives the call invocation.
{:ok, invocation} = Spell.receive_invocation(callee, call)
# `cast_yield/2,3` asynchronously yields the result back to the caller
:ok = Spell.cast_yield(callee, invocation.id, handle_invocation(invocation))
# `receive_event/2,3` blocks until timeout to receive the result.
case Spell.receive_result(publisher, call) do
{:ok, result} -> handle_result(result)
{:error, reason} -> {:error, reason}
end
# Cleanup.
for peer <- [callee, caller], do: Spell.close(peer)
See Spell.Role.Caller
and Spell.Role.Callee
for more information.
Adding New Roles
In Spell, Roles are middleware for handling messages. Technically they're most
similar to GenEvent handlers: callbacks which are hooked into a manager. In this
case, the manager is a Spell.Peer
process.
It's easy to get started:
defmodule Broker do
use Spell.Role
def get_features(_options), do: {:broker, %{}}
def handle_message(%Message{type: :publish} = message, peer, state) do
publish(message, peer, state)
end
... shamelessly skipping the real work.
end
Spell.Peer.connect(Crossbar.uri, realm: Crossbar.get_realm(), roles: [Broker])
See Spell.Role
for descriptions of the Role callbacks.
Examples
Look in examples/
for the scripts.
There are shortcuts to run the examples -- run the following from Spell's root:
$ mix spell.example.pubsub
Testing
To run Spell's integration tests, you must have crossbar installed.
To run the tests:
# run unit and integration tests with default configuration
$ mix test
# run only unit tests
$ mix test.unit
# run integration tests using a specific serializer
$ SERIALIZER=json mix test.integration
$ SERIALIZER=msgpack mix test.integration
# run integration tests with all possible serializers
$ SERIALIZER=all mix test.integration
$ mix test.integration
# run unit and integration tests with all possible configurations
$ mix test.all
The Crossbar.io test server can be configured to listen on a different port by running:
$ CROSSBAR_PORT=8000 mix ...
Creating the Documentation
To generate HTML from the source code documentation you can run:
$ mix docs
Elixir Resources
are all listed below.
Made with ❤️
to provide different kinds of informations and resources.