{"id":13508336,"url":"https://github.com/MyMedsAndMe/spell","last_synced_at":"2025-03-30T11:31:43.144Z","repository":{"id":30004409,"uuid":"33552000","full_name":"MyMedsAndMe/spell","owner":"MyMedsAndMe","description":"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 \u0026 Subscribe: http://wamp.ws/","archived":true,"fork":false,"pushed_at":"2023-01-20T11:47:45.000Z","size":210,"stargazers_count":67,"open_issues_count":11,"forks_count":25,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-17T01:35:55.756Z","etag":null,"topics":["dev"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MyMedsAndMe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-04-07T15:36:17.000Z","updated_at":"2024-12-10T17:27:52.000Z","dependencies_parsed_at":"2023-02-12T01:47:07.635Z","dependency_job_id":null,"html_url":"https://github.com/MyMedsAndMe/spell","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MyMedsAndMe%2Fspell","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MyMedsAndMe%2Fspell/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MyMedsAndMe%2Fspell/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MyMedsAndMe%2Fspell/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MyMedsAndMe","download_url":"https://codeload.github.com/MyMedsAndMe/spell/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246314011,"owners_count":20757450,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dev"],"created_at":"2024-08-01T02:00:51.629Z","updated_at":"2025-03-30T11:31:42.763Z","avatar_url":"https://github.com/MyMedsAndMe.png","language":"Elixir","funding_links":[],"categories":["HTTP"],"sub_categories":[],"readme":"# spell [DEPRECATED]\n\nSpell is an [Elixir](http://elixir-lang.org/) [WAMP](http://wamp.ws/) client\nimplementing the\n[basic profile](https://github.com/tavendo/WAMP/blob/master/spec/basic.md)\nspecification.\n\n# Reason for fork\n\nFor spellchecking old symposium\n\n# Oficial readme\n\nWhy WAMP?\n\n[WAMP](http://wamp.ws/) is the Web Application Message Protocol supported by\n[Tavendo](http://tavendo.com/). It's an open standard WebSocket subprotocol that\nprovides two application messaging patterns in one unified protocol: Remote\nProcedure Calls + Publish \u0026amp; Subscribe.\n\nWhy Spell?\n\n- Flexible interface: one line blocking calls or raw message handling -- use\nwhichever tool works best.\n- Robust peers: peer processes are supervised, and will restart or retry when\nappropriate.\n- Easy to extend: add new roles, transports, or serializers without changing\nthe core library:\n\n## Getting Help\n\nSpell uses GitHub [issues](https://github.com/MyMedsAndMe/spell/issues) and\n[pull requests](https://github.com/MyMedsAndMe/spell/pulls) for development.\n\nSpell has a mailing list at spell@librelist.com; general questions or ideas are\nwelcome there. See [librelist](http://librelist.com/) for how to sign up.\n\n## Using Spell with your Elixir Project\n\nTo use Spell from within your Elixir library add, add it to your `mix.exs` deps,\nalong with the required transport and serialization libraries:\n\n```elixir\ndefp deps do\n  [\n    ...\n    # Required:\n    {:spell, \"~\u003e 0.1\"},\n    # Required if using the websocket transport:\n    {:websocket_client, github: \"jeremyong/websocket_client\", tag: \"v0.7\"},\n    # Required if using the JSON serializer:\n    {:poison, \"~\u003e 1.4\"},\n    # Required if using the msgpack serializer:\n    {:msgpax, \"~\u003e 0.7\"}\n  ]\nend\n```\n\nFetch the dependencies by running:\n\n```\n$ mix deps.get\n```\n\n## How it Works\n\nYou can run the examples you're about to run into, though first you'll need\n[crossbar.io](http://crossbar.io/). You might install it via pip:\n\n```shell\n$ pip install crossbar\n```\n\nIf you are going to use MessagePack you will need to install the optional\ncrossbar package.\n\n```shell\n$ pip install crossbar[msgpack]\n```\n\nStart an Elixir shell:\n\n```bash\n$ iex -S mix\n```\n\n\u003ca name=\"crossbar-install\"\u003e\u003c/a\u003eStart up Crossbar.io:\n\n```elixir\niex\u003e Crossbar.start()\n```\n\nTo stop Crossbar.io from IEx:\n\n```elixir\niex\u003e Crossbar.stop()\n```\n\nYou can find more detailed documentation at any time by checking\nthe source code documentation. `Spell` provides an entry point:\n\n```elixir\niex\u003e h Spell\n```\n\nYou can hit \u003ckbd\u003eC-c C-c\u003c/kbd\u003e to exit the shell. Be sure to stop Crossbar.io\nfirst.\n\n### Peers\n\nIn WAMP, messages are exchanged between peers. Peers are assigned a set of roles\nwhich define how they handle messages. A client peer (Spell!) may have any\nchoice of client roles, and a server peer may have any choice of server roles.\n\nThere are two functional groupings of roles:\n\n- PubSub\n  - Publisher\n  - Subscriber\n  - Broker _[Server]_\n- RPC\n  - Caller\n  - Callee\n  - Dealer _[Server]_\n\nBy default a client peer is started with the above four client roles:\n\n```elixir\nSpell.connect(\"ws://example.org\", realm: \"realm1\")\n```\n\n\nSee `Spell.Peer` and `Spell.Role`.\n\n#### Authentication\n\nSpell supports\n[WAMP Challenge Response Authentication (CRA)](https://github.com/tavendo/WAMP/blob/master/spec/advanced.md#challenge-response-authentication). This\nis flexible, and can be used to back a variety of authentication schemes.\n\nTo setup a Spell peer with authentication:\n\n```elixir\nalias Spell.Authentication.CRA\nauthentication = [id: \"harry\", schemes: [{CRA, [secret: \"alohamora\"]}]]\nSpell.connect(\"ws://example.org\", realm: \"realm1\",\n              authentication: authentication)\n```\n\nSee `Spell.Authentication`.\n\n### PubSub\n\nOnce subscribed to a topic, the subscriber will receive all messages\npublished to that topic.\n\n```elixir\n# Events must be published to a topic.\ntopic = \"com.spell.example.pubsub.topic\"\n\n# Create a peer with the subscriber role.\nsubscriber = Spell.connect(Crossbar.uri,\n                           realm: Crossbar.get_realm(),\n                           roles: [Spell.Role.Subscriber])\n\n# `call_subscribe/2,3` synchronously subscribes to the topic.\n{:ok, subscription} = Spell.call_subscribe(subscriber, topic)\n\n# Create a peer with the publisher role.\npublisher = Spell.connect(Crossbar.uri,\n                          realm: Crossbar.get_realm(),\n                          roles: [Spell.Role.Publisher])\n\n# `call_publish/2,3` synchronously publishes a message to the topic.\n{:ok, publication} = Spell.call_publish(publisher, topic)\n\n# `receive_event/2,3` blocks to receive the event.\ncase Spell.receive_event(publisher, subscription) do\n  {:ok, event}     -\u003e handle_event(event)\n  {:error, reason} -\u003e {:error, reason}\nend\n\n# Cleanup.\nfor peer \u003c- [subscriber, publisher], do: Spell.close(peer)\n```\n\nSee `Spell.Role.Publisher` and `Spell.Role.Subscriber` for more information.\n\n#### Pattern-based subscriptions\n\nBy default, peers subscribe to topics using an exact matching policy. Using\npattern-based subscriptions a peer can receive messages that match certain\ncriteria.\n\n```elixir\n# assuming we have a subscriber peer connected\n\n# exact match\n{:ok, subscription} = Spell.call_subscribe(subscriber, \"com.spell.my_topic\")\n# subscriber will receive messages published in the \"com.spell.my_topic\" topic\n\n# prefix match\n{:ok, subscription} = Spell.call_subscribe(subscriber, \"com.spell.my_topic_prefix\", options: %{match: :prefix})\n# subscriber will receive messages published in topics:\n# \"com.spell.my_topic_prefix.foo\",  \"com.spell.my_topic_prefix.bar\", ...\n\n# wildcard match\n{:ok, subscription} = Spell.call_subscribe(subscriber, \"com.spell..my_topic\", options: %{match: :wildcard})\n# subscriber will receive messages published in topics:\n# \"com.spell.foo.my_topic\", \"com.spell.bar.my_topic\", ...\n```\n\n### RPC\n\nRPC allows a caller to call a procedure using a remote callee.\n\nLet's start with the caller's half:\n\n```elixir\n# Calls are sent to a particular procedure.\nprocedure = \"com.spell.example.rpc.procedure\"\n\n# Create a peer with the callee role.\ncaller = Spell.connect(Crossbar.uri,\n                       realm: Crossbar.get_realm(),\n                       roles: [Spell.Role.Callee])\n\n# `call_register/2,3` synchronously calls the procedure with the arguments.\n{:ok, registration} = Spell.call(subscriber, procedure,\n                                 arguments: [\"args\"],\n                                 arguments_kw: %{})\n\nSpell.close(caller)\n```\n\nIn addition to the synchronous `Spell.call_...` type functions described so far,\nSpell includes asynchronous `Spell.cast_...` functions. To handle the result of\nthese messages you can use a `Spell.receive_...` helper, or, most flexibly,\nuse a `receive` clause.\n\nNext is a contrived example showing the RPC caller and the callee being used\nfrom a single process. Note how asynchronous casts and receive functions are\nused to avoid a deadlock.\n\nNote: I omitted the `arguments` and `arguments_kw` options for brevity's sake.\n\n```elixir\n# Calls are sent to a particular procedure.\nprocedure = \"com.spell.example.rpc.procedure\"\n\n# Create a peer with the callee role.\ncallee = Spell.connect(Crossbar.uri,\n                       realm: Crossbar.get_realm(),\n                       roles: [Spell.Role.Callee])\n\n# `call_register/2,3` synchronously registers the procedure.\n{:ok, registration} = Spell.call_register(callee, procedure)\n\n# Create a peer with the caller role.\ncaller = Spell.connect(Crossbar.uri,\n                       realm: Crossbar.get_realm(),\n                       roles: [Spell.Role.Caller])\n\n# `cast_call/2,3` asynchronously calls the procedure.\n{:ok, call} = Spell.cast_call(caller, procedure)\n\n# `receive_invocation/2,3` blocks until it receives the call invocation.\n{:ok, invocation} = Spell.receive_invocation(callee, call)\n\n# `cast_yield/2,3` asynchronously yields the result back to the caller\n:ok = Spell.cast_yield(callee, invocation.id, handle_invocation(invocation))\n\n# `receive_event/2,3` blocks until timeout to receive the result.\ncase Spell.receive_result(publisher, call) do\n  {:ok, result}    -\u003e handle_result(result)\n  {:error, reason} -\u003e {:error, reason}\nend\n\n# Cleanup.\nfor peer \u003c- [callee, caller], do: Spell.close(peer)\n```\n\n\nSee `Spell.Role.Caller` and `Spell.Role.Callee` for more information.\n\n### Adding New Roles\n\nIn Spell, Roles are middleware for handling messages. Technically they're most\nsimilar to GenEvent handlers: callbacks which are hooked into a manager. In this\ncase, the manager is a `Spell.Peer` process.\n\nIt's easy to get started:\n\n```elixir\ndefmodule Broker do\n  use Spell.Role\n\n  def get_features(_options), do: {:broker, %{}}\n\n  def handle_message(%Message{type: :publish} = message, peer, state) do\n    publish(message, peer, state)\n  end\n\n  ... shamelessly skipping the real work.\nend\n\nSpell.Peer.connect(Crossbar.uri, realm: Crossbar.get_realm(), roles: [Broker])\n```\n\nSee `Spell.Role` for descriptions of the Role callbacks.\n\n## Examples\n\nLook in `examples/` for the scripts.\n\nThere are shortcuts to run the examples -- run the following from Spell's root:\n\n```shell\n$ mix spell.example.pubsub\n```\n\n## Testing\n\nTo run Spell's integration tests, you must have\n[crossbar installed](#crossbar-install).\n\n\nTo run the tests:\n\n```shell\n# run unit and integration tests with default configuration\n$ mix test\n\n# run only unit tests\n$ mix test.unit\n\n# run integration tests using a specific serializer\n$ SERIALIZER=json mix test.integration\n$ SERIALIZER=msgpack mix test.integration\n\n# run integration tests with all possible serializers\n$ SERIALIZER=all mix test.integration\n$ mix test.integration\n\n# run unit and integration tests with all possible configurations\n$ mix test.all\n```\n\nThe Crossbar.io test server can be configured to listen on a different port\nby running:\n\n```shell\n$ CROSSBAR_PORT=8000 mix ...\n```\n\n## Creating the Documentation\n\nTo generate HTML from the source code documentation you can run:\n\n```shell\n$ mix docs\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMyMedsAndMe%2Fspell","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMyMedsAndMe%2Fspell","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMyMedsAndMe%2Fspell/lists"}