Трансляция на другой канал Феникс 1.1.6
Я пытаюсь транслировать на другой канал в моем приложении, но не могу заставить его работать. Также я пытаюсь написать тест, но я не уверен, как.
Из того, что я могу собрать, я преуспел в трансляции сообщения от messages_channel, но оно не получено в chat_channel.
Уведомление следует отправлять в чат.
notification_channel.ex
def handle_in("new:group:recommendation", msg, socket) do
payload = %{
message: msg["message"],
url: msg["url"],
title: msg["title"],
user_name: get_name_of_user(socket.assigns.user_grapqhl_id),
user_grapqhl_id: socket.assigns.user_grapqhl_id
}
IO.puts "incomming"
IO.inspect msg
Enum.map(msg["groups"], fn(x) ->
App.Endpoint.broadcast_from! self(), "chat:"<>x,
"new:recommendation", payload
end)
{:reply, :ok, socket}
end
chat_channel.ex
def handle_in("new:recommendation", msg, socket) do
IO.puts "i am a recommendation !"
IO.inspect msg
chat_msg = %{
"creator_id" => msg["user_grapqhl_id"],
"text" => msg["message"],
"creator_name" => msg["user_name"]
}
broadcast! socket, "new:msg", create_chat_msg(chat_msg,socket)
{:reply, :ok, socket}
end
тестовое задание
test "do we send a new:recommendation to chat ?", %{guardian_token: guardian_token} do
nils_base_64 = Base.encode64("user:nils")
{:ok, socket} = connect(UserSocket, %{})
{:ok, _, socket1} = subscribe_and_join(socket, "notifications:"<>nils_base_64, %{"guardian_token" => guardian_token})
{:ok, _, socket} = subscribe_and_join(socket1, "chat:Y2hhdDpjaGF0Mw==", %{"guardian_token" => guardian_token})
payload = %{
"message" => "look at this cool thing!",
"url" => "link to stuff",
"title" => "AWESOME EVENT",
"groups" => ["Y2hhdDpjaGF0Mw==", "Y2hhdDpwdWJsaWM="]
}
reply = %{message: "look at this cool thing!", title: "AWESOME EVENT", url: "link to stuff", user_grapqhl_id: nils_base_64, user_name: "Nils Eriksson"}
ref = push socket1, "new:group:recommendation", payload
assert_reply ref, :ok
assert_broadcast "new:recommendation", ^reply
end
Этот тест проходит, и я могу заставить его потерпеть неудачу, изменив reply
или комментируя трансляцию. Я не могу заставить его потерпеть неудачу, изменив handle_in
получить fail:please
в chat_channel
, Это то, на что он будет жаловаться, если я отправлю изменить это ref = push socket1, "new:group:recommendation", payload
в ref = push socket, "new:group:recommendation", payload
не исключая в этом случае.
Это то, что на проводе.
Process mailbox:
%Phoenix.Socket.Message{event: "init:msgs", payload: %{messages: []}, ref: nil, topic: "chat:Y2hhdDpjaGF0Mw=="}
%Phoenix.Socket.Broadcast{event: "new:recommendation", payload: %{message: "look at this cool thing!", title: "AWESOME EVENTs", url: "link to stuff", user_grapqhl_id: "dXNlcjpuaWxz", user_name: "Nils Eriksson"}, topic: "chat:Y2hhdDpjaGF0Mw=="}
%Phoenix.Socket.Message{event: "new:recommendation", payload: %{message: "look at this cool thing!", title: "AWESOME EVENTs", url: "link to stuff", user_grapqhl_id: "dXNlcjpuaWxz", user_name: "Nils Eriksson"}, ref: nil, topic: "chat:Y2hhdDpjaGF0Mw=="}
Я использую аутентификацию канала, поскольку используемый мной пакет elm еще не поддерживает аутентификацию на уровне сокетов. так вот как это выглядит в chat
def join("chat:" <> chat_id, %{"guardian_token" => token}, socket) do
IO.puts chat_id
case sign_in(socket, token) do
{:ok, authed_socket, _guardian_params} ->
Process.flag(:trap_exit, true)
send(self, {:after_join})
[_type, node_chat_id] = Node.from_global_id(chat_id)
{:ok, assign(authed_socket, :chat_id, node_chat_id)}
{:error, reason} ->
IO.puts "Can't join channel cuz: " <> reason
# handle error TODO
end
конец
2 ответа
Так как вы используете broadcast_from/4
от твоего Endpoint
. Вы должны использовать handle_info/2
в вашем chat_channel
:
alias Phoenix.Socket.Broadcast
...
def handle_info(%Broadcast{topic: _, event: ev, payload: payload}, socket) do
IO.puts ev
IO.inspect payload
# do something with ev and payload( push or broadcast)
{:noreply, socket}
end
Или вы можете прослушать это событие от вашего клиента:
chatChannel.on("new:recommendation", resp => {
// doSomething with response
}
Редактировать:
Давайте объясним немного о том, как channel
а также PubSub
системная работа.
Если вы хотите транслировать или отправить событие с полезной нагрузкой. Сначала оно отправит PubSub
система, а затем PubSub
система отправит его всем подписчикам процесса (channel
) с темой channel
зарегистрировался в PubSub
система.
И когда вы используете Endpoint.broadcast_from/4
транслировать событие с вашего сервера. PubSub
Система получит событие с полезной нагрузкой и передаст его в тему, зарегистрированную на канале.
Канал сработает handle_out
перезвонить и отправить сообщение клиенту. Так в вашем chat_channel
тебе не нужно handle_in
Событие "new: рекомендации". Вашему клиенту просто нужно прослушать это событие.
chatChannel.on("new:recommendation", resp => {
// do something with response
}
И позвольте мне переписать ваш тест:
setup do
nils_base_64 = Base.encode64("user:nils")
{:ok, socket} = connect(UserSocket, %{})
{:ok, _, socket} = subscribe_and_join(socket, "notifications:"<>nils_base_64, %{"guardian_token" => guardian_token})
{:ok, socket: socket}
end
test "do we send a new:recommendation to chat ?", %{socket: socket} do
MyApp.Endpoint.subscribe("chat:Y2hhdDpjaGF0Mw==")
payload = %{
"message" => "look at this cool thing!",
"url" => "link to stuff",
"title" => "AWESOME EVENT",
"groups" => ["Y2hhdDpjaGF0Mw==", "Y2hhdDpwdWJsaWM="]
}
reply = %Phoenix.Socket.Broadcast{message: "look at this cool thing!",
title: "AWESOME EVENT",
url: "link to stuff",
user_grapqhl_id: nils_base_64,
user_name: "Nils Eriksson"}
ref = push socket, "new:group:recommendation", payload
assert_reply ref, :ok
assert_receive ^reply
end
От subscribe
к теме, которую вы хотите прослушать, вы можете убедиться, что ваш канал получил сообщение с assert_receive
, Это способ проверить broadcast
на другой канал.
Попробуйте и скажите мне. Тест пройдет.
Использование App.Endpoint.broadcast topic, event, payload
с темой вашего канала чата. Он должен работать.