https://github.com/infinitered/mithril_pubsub
A PubSub layer for Mithril-architected apps
https://github.com/infinitered/mithril_pubsub
Last synced: 6 months ago
JSON representation
A PubSub layer for Mithril-architected apps
- Host: GitHub
- URL: https://github.com/infinitered/mithril_pubsub
- Owner: infinitered
- Created: 2017-11-17T19:01:03.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2019-05-01T16:32:30.000Z (over 6 years ago)
- Last Synced: 2025-05-31T19:23:08.148Z (8 months ago)
- Language: Elixir
- Size: 45.9 KB
- Stars: 6
- Watchers: 9
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Mithril.PubSub
[](https://travis-ci.org/infinitered/mithril_pubsub)
PubSub and Presence implementations that don't create a dependency between your
business logic and your Phoenix web app.
## Why
Phoenix 1.3 and higher encourages us to keep our business logic separate from our
Phoenix web application. PubSub topics, event handling, and presence **are often
core business logic concerns**.
The current architecture of Phoenix forces your business logic to call
`Phoenix.Endpoint` to broadcast events to websockets. Presence information about
a topic is likewise tied up in a web app `Presence` module.
This makes your business logic depend on your Phoenix application, rather
than the other way around.

`Mithril.PubSub` allows you to reverse that dependency, making your
Phoenix app, Endpoint, and Channels depend on your business logic instead.

## Included Modules
Read their documentation for more information.
- `Mithril.PubSub`
- `Mithril.PubSub.Subscriber`
- `Mithril.Presence`
## How It Works
Phoenix has already extracted its PubSub and CRDT-based presence tracking
system to a small package called [phoenix_pubsub][pp]. Sadly,
`Phoenix.Presence` is not in this package, because it relies on
Phoenix-specific data types, such as `Phoenix.Socket.Message` and
`Phoenix.Socket.Broadcast`.
However, `Phoenix.Presence` is only a tiny wrapper around `Phoenix.Tracker`,
which _is_ part of [phoenix_pubsub][pp].
It was therefore very easy to fork `Phoenix.Presence` to remove its reliance
on Phoenix-only data-types, producing `Mithril.Presence`.
Likewise, `Mithril.PubSub` is a lightweight wrapper around `Phoenix.PubSub`.
## Installation
The package can be installed by adding `mithril_pubsub` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:mithril_pubsub, github: "infinitered/mithril_pubsub"}
]
end
```
## Usage
Define a `PubSub` module in your logic application:
```elixir
defmodule MyApp.PubSub do
use Mithril.PubSub, otp_app: :my_app
end
```
Configure that `PubSub` module to use an adapter:
```elixir
# config/config.exs
config :my_app, MyApp.PubSub,
adapter: Phoenix.PubSub.PG2,
pool_size: 5
```
If using Phoenix, replace the `:pubsub` option on your Endpoint configuration
with your new `PubSub` module:
```elixir
config :my_app_web, MyAppWeb.Endpoint,
pubsub: [name: MyApp.PubSub]
```
Update your `lib/my_app_web.ex` or `apps/my_app_web/lib/my_app_web.ex` file to
pull in functions from your new `PubSub` module instead of the defaults from
`Phoenix.Channel`:
```elixir
def channel do
quote do
use Phoenix.Channel
import Phoenix.Channel,
except: [
broadcast: 3,
broadcast!: 3,
broadcast_from: 3,
broadcast_from!: 3
]
import MyApp.PubSub,
only: [
broadcast: 2,
broadcast!: 2,
broadcast_from: 2,
broadcast_from!: 2
]
end
end
```
Then, broadcast regular Elixir tuple messages over your PubSub within your channel:
```elixir
defmodule MyAppWeb.RoomChannel do
use MyAppWeb, :channel
alias MyApp.Presence
def join("room:lobby", payload, socket) do
{:ok, socket}
end
def handle_in("message", message, socket) do
# Broadcasts the event as a simple Erlang term, instead of a
# custom Phoenix one. This allows listeners in the business
# logic app to easily subscribe to them.
broadcast!(socket, {:message, message})
{:noreply, socket}
end
# Channels will receive messages for their topic from the PubSub
# server as regular Erlang process messages.
#
# It's up to each channel to handle these messages and forward
# them on to the websocket using `Phoenix.Channel.push/3`.
def handle_info({:message, message}, socket) do
push(socket, "message", message)
{:noreply, socket}
end
end
```
## Documentation
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc).
[pp]: https://hexdocs.pm/phoenix_pubsub