EssenceOfChaos

EssenceOfChaos

The Phoenix Chat, websockets

I’m having trouble implementing a general lobby channel in my Phoenix app. Overall, Phoenix makes soft real-time communication very simple. A brief reading off Channels provides all the info to get up and running. However, after reaching that point of joining the channel and broadcasting messages it leaves me with some unanswered questions.

Besides the endpoint, are essentially 3 files in play:

  1. socket.js

  2. player_socket.ex

  3. lobby_channel.ex

I wanted to try the scaffolding so I used the generator mix phx.gen.channel Lobby. This seems to have left me with a “lobby:lobby” topic and subtopic. I tried implementing the presence module several times without any success. How do I implement the presence module so that I can show a list of “online users” and also have a username next to the chat message and the time the message was sent in a readable format, opposed to the Date.new() iso format that the guide provides.

I do have a “current_player” object stored in the session so it should be easy to figure this out but for some reason each time I take one step forward I wind up taking two steps back. I’ve reviewed the docs as well as several tutorials but I can’t figure out what I’m doing wrong.

The whole repo is here.

My player socket:

def connect(%{"token" => token}, socket) do

  case Phoenix.Token.verify(socket, "player socket", token, max_age: @max_age) do
    {:ok, player_id} ->
      {:ok, assign(socket, :player, player_id)}
    {:error, reason} ->
      :error
  end
end

Lobby Channel:

  def join("lobby:lobby", _payload, socket) do
      current_player = socket.assigns.current_player
      players = ChannelMonitor.player_joined("lobby:lobby", current_player)["lobby:lobby"]
      send self, {:after_join, players}
      {:ok, socket}
    end

My Socket.js (which is a mess of failed attempts)

/*jshint esversion: 6 */

// To use Phoenix channels, the first step is to import Socket
// and connect at the socket path in "lib/web/endpoint.ex":
import { Socket } from "phoenix";

var token = $('meta[name=channel_token]').attr('content');
var socket = new Socket('/socket', {params: {token: token}});
socket.connect();

var lobby = socket.channel('lobby:lobby');
lobby.on('lobby_update', function(response) {
  console.log(JSON.stringify(response.players));
});
lobby.join().receive('ok', function() {
  console.log('Connected to lobby!');
});

lobby.on('game_invite', function(response) {
  console.log('You were invited to join a game by', response.username);
});

window.invitePlayer = function(username) {
  lobby.push('game_invite', {username: username});
};



// format timestamp
let formatTimestamp = timestamp => {
    let date = new Date(timestamp);
    return date.toLocaleTimeString();
};

let channel = socket.channel("lobby:lobby", {});
let chatInput = document.querySelector("#chat-input");
let messagesContainer = document.querySelector("#messages");

// listen for "enter" key press
chatInput.addEventListener("keypress", event => {
    if (event.keyCode === 13) {
        channel.push("new_msg", { body: chatInput.value });
        chatInput.value = "";
    }
});

// listen for messages and append to the messagesContainer
channel.on("new_msg", payload => {
    let messageItem = document.createElement("li");
    messageItem.innerText = `[${Date()}] ${payload.body}`;
    messagesContainer.appendChild(messageItem);
});

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

export default socket;

// WORKING WITH PHOENIX PRESENCE MODULE //
// channel.on("presence_state", state => {
//     presences = Presence.syncState(presences, state);
//     renderOnlinePlayers(presences);
// });
//
// channel.on("presence_diff", diff => {
//     presences = Presence.syncDiff(presences, diff);
//     renderOnlinePlayers(presences);
// });
// WORKING WITH PHOENIX PRESENCE MODULE //

First Post!

axelson

axelson

Scenic Core Team

@EssenceOfChaos have you tried using Presence.track/3? The presence docs should be able to get you setup fine on the Elixir side: Phoenix.Presence — Phoenix v1.8.8

Most Liked

EssenceOfChaos

EssenceOfChaos

@axelson thanks for the reply. I implement the Presence tracking in the lobby channel after joining

kokolegorille

kokolegorille

Glad You solved it

EssenceOfChaos

EssenceOfChaos

Any idea why how to solve, “websocket connection failed: Connection closed before receiving a handshake response” ?

Last Post!

OvermindDL1

OvermindDL1

Sounds like a server issue, do you have anything between the client and phoenix, like a proxy or cache?

Where Next?

Popular in Questions Top

jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

Other popular topics Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

We're in Beta

About us Mission Statement