Bidirectional Pusher client in Elixir
Pushest is bidirectional Pusher client leveraging Elixir/OTP to combine server and client-side
Pusher features together in one library. Pushest communicates both via WebSockets and REST API.
You can trigger on any channel, subscribe to channels, handle events using callbacks or
keep track of presence.
pusher:error
auth
function to generate a token for client-side libraries.
# Add necessary pusher configuration to your application config:
# simple_client/config/config.exs
config :simple_client, SimpleClient,
pusher_app_id: System.get_env("PUSHER_APP_ID"),
pusher_key: System.get_env("PUSHER_APP_KEY"),
pusher_secret: System.get_env("PUSHER_SECRET"),
pusher_cluster: System.get_env("PUSHER_CLUSTER"),
pusher_encrypted: true
# simple_client/simple_client.ex
defmodule SimpleClient do
use Pushest, otp_app: :simple_client
# Subscribe to these channels right after application startup.
def init_channels do
[
[name: "public-init-channel", user_data: %{}],
[name: "private-init-channel", user_data: %{}],
[name: "presence-init-channel", user_data: %{user_id: 123}],
]
end
# handle_event/2 is user-defined callback which is triggered whenever an event
# occurs on the channel.
def handle_event({:ok, "public-init-channel", "some-event"}, frame) do
# do something with public-init-channel frame
end
def handle_event({:ok, "public-channel", "some-event"}, frame) do
# do something with public-channel frame
end
def handle_event({:ok, "private-channel", "some-other-event"}, frame) do
# do something with private-channel frame
end
# We can also catch errors.
def handle_event({:error, msg}, frame) do
# do something with error
end
end
# Now you can start your application with Pushest as a part of your supervision tree:
# simple_client/lib/simple_client/application.ex
def start(_type, _args) do
children = [
{SimpleClient, []}
]
opts = [strategy: :one_for_one, name: Sup.Supervisor]
Supervisor.start_link(children, opts)
end
config = %{
app_id: System.get_env("PUSHER_APP_ID"),
key: System.get_env("PUSHER_APP_KEY"),
secret: System.get_env("PUSHER_SECRET"),
cluster: System.get_env("PUSHER_CLUSTER"),
encrypted: true
}
{:ok, pid} = SimpleClient.start_link(config)
SimpleClient.channels()
# => %{
"channels" => %{
"presence-init-channel" => %{},
"private-init-channel" => %{},
"public-init-channel" => %{}
}
# ...
SimpleClient.subscribe("public-channel")
:ok
# ...
SimpleClient.subscribe("private-channel")
:ok
# ...
SimpleClient.subscribe("presence-channel", %{user_id: "1", user_info: %{name: "Tomas"}})
:ok
# ...
SimpleClient.presence()
%Pushest.Data.Presence{
count: 2,
hash: %{"1" => %{"name" => "Tomas"}, "2" => %{"name" => "Jose"}},
ids: ["1", "2"],
me: %{user_id: "1", user_info: %{name: "Tomas"}}
}
# ...
SimpleClient.trigger("private-channel", "first-event", %{message: "Ahoj"})
:ok
# ...
SimpleClient.subscribed_channels()
["presence-channel", "private-channel", "public-channel",
"presence-init-channel", "private-init-channel", "public-init-channel"]
# ...
SimpleClient.unsubscribe("public-channel")
:ok
Subscribes to public or private channel
SimpleClient.subscribe("public-channel")
:ok
Subscribes to private or presence channel with user data as second parameter.
User data has to contain user_id
key with unique identifier for current user.
Can optionally contain user_info
field with map of additional informations about user.
user_data = %{user_id: 123, user_info: %{name: "Tomas", email: "secret@secret.com"}}
SimpleClient.subscribe("presence-channel", user_data)
:ok
# ...
SimpleClient.subscribe("private-channel", user_data)
:ok
Triggers on given channel and event with given data payload. Pushest sends data by
default to REST API endpoint of Pusher, however when subscribed to private or presence channel
it sends data to Pusher via WebSockets.
SimpleClient.trigger("public-channel", "event", %{message: "message"})
:ok
# ..
SimpleClient.trigger("private-channel", "event", %{message: "message"})
:ok
Same as trigger/3
but lets you force trigger over the REST API (so it never triggers via WebSockets).
SimpleClient.trigger("private-channel", "event", %{message: "message"}, force_api: true)
Returns map of all the active channels which are being used in your Pusher application.
Can contain informations about subscribed users.
SimpleClient.channels()
%{"channels" => %{"public-channel" => %{}, "private-channel" => %{}}}
Returns list of all the subscribed channels for current instance.
SimpleClient.subscribed_channels()
["private-channel"]
Returns information about all the users subscribed to a presence channel.
SimpleClient.presence()
%Pushest.Data.Presence{
count: 2,
hash: %{"1" => %{"name" => "Tomas"}, "2" => %{"name" => "Jose"}},
ids: ["1", "2"],
me: %{user_id: "2", user_info: %{name: "Jose"}}
}
Unsubscribes from given channel
SimpleClient.unsubscribe("public-channel")
These functions are meant to be overridden in a module using Pushest
Callback being triggered when there is a WebSocket event on a subscribed channel.
defmodule MyApp.MyModule
use Pushest, otp_app: :my_app
def handle_event({:ok, "my-channel", "my-event"}, frame) do
IO.inspect frame
end
end
Subscribes to given list of channels right after application startup.
Each element has to be a keyword list in exact format of: [name: String.t(), user_data: map]
defmodule MyApp.MyModule
use Pushest, otp_app: :my_app
def init_channels do
[
[name: "public-init-channel", user_data: %{}],
[name: "private-init-channel", user_data: %{}],
[name: "presence-init-channel", user_data: %{user_id: 123}],
]
end
end
frame
exampleframe
is a Pushest.Socket.Data.Frame
or Pushest.Api.Data.Frame
struct with data payload as a map.
%Pushest.Data.Frame{
channel: "private-channel",
data: %{"name" => "John", "message" => "Hello"},
event: "second-event"
}
The package can be installed by adding pushest
to your list of dependencies in mix.exs
:
def deps do
[
{:pushest, "~> 0.2.2"}
]
end
Documentation can be be found at https://hexdocs.pm/pushest.