Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Broadcaster] Add viewer count and backend chat stub #12

Merged
merged 4 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion broadcaster/assets/js/app.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// If you want to use Phoenix channels, run `mix help phx.gen.channel`
// to get started and then uncomment the line below.
// import "./user_socket.js"
import "./user_socket.js"

// You can include dependencies in two ways.
//
Expand Down
27 changes: 27 additions & 0 deletions broadcaster/assets/js/user_socket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {Socket, Presence} from "phoenix"

let socket = new Socket("/socket", {params: {token: window.userToken}})

socket.connect()

const channel = socket.channel("stream:chat", {name: "TODO get user name"})
const presence = new Presence(channel)
const viewercount = document.getElementById("viewercount")

presence.onSync(() => {
viewercount.innerText = presence.list().length
})

channel.join()
.receive("ok", resp => { console.log("Joined chat channel successfully", resp) })
.receive("error", resp => { console.log("Unable to join chat channel", resp) })

channel.on("chat_msg", payload => {
// TODO capture message from some kind of input
console.log("RECEIVED CHAT MESSAGE", payload)
})

// TODO when user types message in chat, do this
channel.push("chat_msg", {body: "TODO get chat message"})

export default socket
1 change: 1 addition & 0 deletions broadcaster/lib/broadcaster/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ defmodule Broadcaster.Application do
# {Broadcaster.Worker, arg},
# Start to serve requests, typically the last entry
BroadcasterWeb.Endpoint,
BroadcasterWeb.Presence,
Broadcaster.PeerSupervisor,
Broadcaster.Forwarder,
{Registry, name: Broadcaster.PeerRegistry, keys: :unique}
Expand Down
6 changes: 4 additions & 2 deletions broadcaster/lib/broadcaster/peer_supervisor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,17 @@ defmodule Broadcaster.PeerSupervisor do
pc_id = generate_pc_id()
{:ok, pc} = spawn_peer_connection(pc_id)

Logger.info("Received offer for #{inspect(pc)}, SDP:\n#{offer.sdp}")
Logger.info("Received offer for #{inspect(pc)}")
Logger.debug("Offer SDP for #{inspect(pc)}:\n#{offer.sdp}")

with :ok <- PeerConnection.set_remote_description(pc, offer),
:ok <- setup_transceivers(pc, direction),
{:ok, answer} <- PeerConnection.create_answer(pc),
:ok <- PeerConnection.set_local_description(pc, answer),
:ok <- gather_candidates(pc),
answer <- PeerConnection.get_local_description(pc) do
Logger.info("Sent answer for #{inspect(pc)}, SDP:\n#{answer.sdp}")
Logger.info("Sent answer for #{inspect(pc)}")
Logger.debug("Answer SDP for #{inspect(pc)}:\n#{answer.sdp}")

{:ok, pc, pc_id, answer.sdp}
else
Expand Down
11 changes: 11 additions & 0 deletions broadcaster/lib/broadcaster_web/channels/presence.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
defmodule BroadcasterWeb.Presence do
@moduledoc """
Provides presence tracking to channels and processes.

See the [`Phoenix.Presence`](https://hexdocs.pm/phoenix/Phoenix.Presence.html)
docs for more details.
"""
use Phoenix.Presence,
otp_app: :broadcaster,
pubsub_server: Broadcaster.PubSub
end
24 changes: 24 additions & 0 deletions broadcaster/lib/broadcaster_web/channels/stream_channel.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
defmodule BroadcasterWeb.StreamChannel do
use BroadcasterWeb, :channel

alias BroadcasterWeb.Presence

@impl true
def join("stream:chat", %{"name" => name}, socket) do
send(self(), :after_join)
{:ok, assign(socket, :name, name)}
end

@impl true
def handle_in("chat_msg", %{"body" => body}, socket) do
broadcast!(socket, "chat_msg", %{body: body, name: socket.assigns.name})
{:noreply, socket}
end

@impl true
def handle_info(:after_join, socket) do
{:ok, _} = Presence.track(socket, socket.assigns.user_id, %{})
push(socket, "presence_state", Presence.list(socket))
{:noreply, socket}
end
end
19 changes: 19 additions & 0 deletions broadcaster/lib/broadcaster_web/channels/user_socket.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
defmodule BroadcasterWeb.UserSocket do
use Phoenix.Socket

channel "stream:*", BroadcasterWeb.StreamChannel

@impl true
def connect(_params, socket, _connect_info) do
{:ok, assign(socket, :user_id, generate_id())}
end

@impl true
def id(socket), do: "user_socket:#{socket.assigns.user_id}"

defp generate_id do
10
|> :crypto.strong_rand_bytes()
|> Base.url_encode64()
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
</a>
</div>
<div class="flex items-center gap-4 font-semibold leading-6 text-brand/80">
<div class="flex gap-1 px-4">
<p id="viewercount">0</p>
<.icon name="hero-user-solid" />
</div>
<a href="https://github.com/elixir-webrtc/ex_webrtc" class="hover:text-brand">
GitHub
</a>
Expand Down
4 changes: 4 additions & 0 deletions broadcaster/lib/broadcaster_web/endpoint.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ defmodule BroadcasterWeb.Endpoint do
same_site: "Lax"
]

socket "/socket", BroadcasterWeb.UserSocket,
websocket: true,
longpoll: false

socket "/live", Phoenix.LiveView.Socket,
websocket: [connect_info: [session: @session_options]],
longpoll: [connect_info: [session: @session_options]]
Expand Down

This file was deleted.

34 changes: 34 additions & 0 deletions broadcaster/test/support/channel_case.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
defmodule BroadcasterWeb.ChannelCase do
@moduledoc """
This module defines the test case to be used by
channel tests.

Such tests rely on `Phoenix.ChannelTest` and also
import other functionality to make it easier
to build common data structures and query the data layer.

Finally, if the test case interacts with the database,
we enable the SQL sandbox, so changes done to the database
are reverted at the end of every test. If you are using
PostgreSQL, you can even run database tests asynchronously
by setting `use BroadcasterWeb.ChannelCase, async: true`, although
this option is not recommended for other databases.
"""

use ExUnit.CaseTemplate

using do
quote do
# Import conveniences for testing with channels
import Phoenix.ChannelTest
import BroadcasterWeb.ChannelCase

# The default endpoint for testing
@endpoint BroadcasterWeb.Endpoint
end
end

setup _tags do
:ok
end
end