Skip to content

Instantly share code, notes, and snippets.

@alexdesousa
Last active July 19, 2023 16:48
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexdesousa/4d592fe206cca17393affaefa4c8fd33 to your computer and use it in GitHub Desktop.
Save alexdesousa/4d592fe206cca17393affaefa4c8fd33 to your computer and use it in GitHub Desktop.
Small pubsub implementation using pg2
defmodule PubSub do
@moduledoc """
This module defines the basic pub-sub functions.
"""
@typedoc """
Channel name.
"""
@type channel :: term()
@typedoc """
Message.
"""
@type message :: term()
@doc """
Subscribes to a `channel`.
"""
@spec subscribe(channel()) :: :ok | {:error, {:no_such_group, channel()}}
def subscribe(channel) do
pid = self()
case :pg2.get_members(channel) do
members when is_list(members) ->
if pid in members, do: :ok, else: :pg2.join(channel, pid)
{:error, {:no_such_group, ^channel}} ->
:pg2.create(channel)
:pg2.join(channel, pid)
end
end
@doc """
Unsubscribe from a `channel`.
"""
@spec unsubscribe(channel()) :: :ok
def unsubscribe(channel) do
pid = self()
case :pg2.get_members(channel) do
[^pid] ->
:pg2.leave(channel, pid)
:pg2.delete(channel)
members when is_list(members) ->
if pid in members, do: :pg2.leave(channel, pid), else: :ok
_ ->
:ok
end
end
@doc """
Publishes a `message` in a `channel`.
"""
@spec publish(channel(), message()) :: :ok
def publish(channel, message) do
case :pg2.get_members(channel) do
[_ | _] = members ->
for member <- members, do: send(member, message)
:ok
_ ->
:ok
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment