{"id":25909639,"url":"https://github.com/wise-home/hub","last_synced_at":"2025-10-10T16:01:53.304Z","repository":{"id":19895779,"uuid":"88209148","full_name":"wise-home/hub","owner":"wise-home","description":"Pub-sub hub with pattern subscription","archived":false,"fork":false,"pushed_at":"2024-07-08T08:10:09.000Z","size":309,"stargazers_count":50,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-09T02:35:11.908Z","etag":null,"topics":["elixir","pubsub"],"latest_commit_sha":null,"homepage":"https://github.com/wise-home/hub","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wise-home.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-04-13T21:47:18.000Z","updated_at":"2024-07-08T08:10:14.000Z","dependencies_parsed_at":"2024-07-05T14:17:15.477Z","dependency_job_id":null,"html_url":"https://github.com/wise-home/hub","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wise-home%2Fhub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wise-home%2Fhub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wise-home%2Fhub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wise-home%2Fhub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wise-home","download_url":"https://codeload.github.com/wise-home/hub/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241629714,"owners_count":19993711,"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":["elixir","pubsub"],"created_at":"2025-03-03T08:18:08.810Z","updated_at":"2025-10-10T16:01:53.227Z","avatar_url":"https://github.com/wise-home.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hub\n\nA single_node pub-sub hub with pattern matching subscriptions.\n\nIt has no dependencies.\n\nExample:\n\n```elixir\n# In one process:\nHub.subscribe(\"some_channel\", %{name: _, age: age} when age \u003e 42)\nreceive do\n  %{name: name} -\u003e IO.puts(\"#{name} is older than 42\")\nend\n\n# In another process:\nHub.publish(\"some_channel\", %{name: \"John\", age: 48})\n```\n\n## Installation\n\nAdd `hub` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [{:hub, \"~\u003e 0.6\"}]\nend\n```\n\n## Status\n\n[![CircleCI](https://circleci.com/gh/wise-home/hub.svg?style=svg)](https://circleci.com/gh/wise-home/hub)\n\n## How it works and what you should know.\n\nBehind the scenes the pattern is \"decompiled\" into an Elixir AST and saved with the subscription. When a message is\npublished to a channel, the pattern of each subscription is checked against the message and the subscriptions that\nmatch receives the message.\n\nIf you have lots of messages and lots of subscribers in the same channel, this is probably not for you, since the\nperformance cost of pattern matching each message against each subscriber could be a problem.\n\nHowever, many applications with many published messages can easily split messages into multiple channels based on\napplication specific criteria. If performance is a concern, having different channels should be used as much as\npossible.\n\n## Usage\n\nA subscription is made with a quoted pattern:\n\n```elixir\nHub.subscribe_quoted(\"My channel\", quote(do: {:some, pattern}))\n```\n\nA convenience macro, `subscribe`, can be used to avoid the `quote`. Given the default value of the options, the\nfollowing is equivalent to the above:\n\n```elixir\nrequire Hub\nHub.subscribe(\"My channel\", {:some, pattern})\n```\n\nTo publish a message in a channel, call `Hub.publish/2`:\n\n```elixir\nHub.publish(\"My channel\", {:any, \"valid\", %{elixir: \"term\"}})\n```\n\nWhen a message is published to the pid of a subscription, it is send directly and unmodified to that process' mailbox.\nThe subscriber should `receive` the message:\n\n```elixir\nHub.subscribe(\"Channel\", {:hello, name})\nHub.subscribe(\"Channel\", {:goodbye, name})\n\nreceive do\n  {:hello, name} -\u003e IO.puts(\"Hello #{name}\")\n  {:goodbye, name} -\u003e IO.puts(\"Goodbye #{name}\")\nend\n```\n\nIf the receiver is a GenServer, and you don't want a blocking `receive`, use `handle_info` instead:\n\n```elixir\ndef handle_info({:hello, name}, state) do\n  IO.puts(\"Hello #{name}\")\n  {:noreply, state}\nend\n```\n\n### Subscribe options\n\n`subscribe` and `subscribe_quoted` accepts these options:\n\n* `pid` (default `self()`) is the process that should receive published messages.\n* `count` (default `:infinity`) is how many times a subscription can be triggered before it is auto-unsubscribed.\n* `multi` (default `false`). When `true`, the `pattern` argument must be a list of multiple patterns. This is handy if\n  combined with `count`.\n\n### Using local variables\n\nSometimes one wish to subscribe using a pattern involving local variables.\nThe `subscribe` macro accepts a `bind_quoted` argument, that will replace pinned variables with the given values.\n\nE.g.\n\n```elixir\nsize = 42\nHub.subscribe(\"my channel\", %{size: ^size}, bind_quoted: [size: size])\n```\n\nis equivalent to\n\n```elixir\nHub.subscribe(\"my channel\", %{size: 42})\n```\n\n### Unsubscribe\n\nTo unsubscribe, use the returned reference given when subscribing:\n\n```elixir\n{:ok, subscription} = Hub.subscribe(\"my channel\", {:hello, name})\nHub.unsubscribe(subscription)\n```\n\nTo avoid race conditions, it can be useful to also flush matched messages, so they don't leak. Example:\n\n```elixir\n{:ok, subscription} = Hub.subscribe(\"my channel\", {:hello, name})\n\nreceive do\n  {:hello, name} -\u003e IO.puts(\"Hello #{name}\")\nafter\n  5_000 -\u003e\n    Hub.unsubscribe_and_flush(subscription)\nend\n```\n\n## Examples\n\nSubscribe only once to a message:\n\n```elixir\nHub.subscribe(\"My channel\", {:hello, name}, count: 1)\n```\n\n`when` is perfectly legal to use in the pattern:\n\n```elixir\nHub.subscribe(\"My channel\", %User{age: age} when age \u003e 42)\n```\n\nSubscribe another process:\n\n```elixir\nHub.subscribe(\"My channel\", {:hello, name}, pid: child_pid)\n```\n\nSubscribe to all messages in a channel:\n\n```elixir\nHub.subscribe(\"My channel\", _)\n```\n\nSubscribe to the first message that matches one of the patterns:\n\n```elixir\nHub.subscribe(\"My channel\", [{:hello, name}, {:goodbye, name}], multi: true, count: 1)\n```\n\n## Contributing\n\nTests are run with `mix test`. When submitting new code, make sure `mix credo` also passes.\n\n## Versions of Elixir and Erlang\n\nHub will usually be tested against the two latest minor versions of Elixir and the three latest minor versions of\nErlang.\nIn all cases the latest patch version is used.\n\nE.g. if the latest Elixir is 1.7.2 and the latest Erlang is 21.0.5, we test against:\n\n* Elixir: 1.7.2 and 1.6.6\n* Erlang: 21.0.5, 20.3.8.6 and 20.2.4\n\nSee in the github actions script, which versions are officially supported.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwise-home%2Fhub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwise-home%2Fhub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwise-home%2Fhub/lists"}