8

In the channel, I need the IP address of the client, and the hostname.

I know it can be send signed as a payload, but if the endpoint should be available from cross domain hosts, or even mobile apps, so I can't pass this information signed.

I've read that an option is to create my own transport based on Phoenix.Transport.WebSocket, injecting the relevant information into the socket, but I don't know how to do that.

Adrian Ribao
  • 1,409
  • 3
  • 11
  • 9
  • Possible duplicate of [how to get remote\_ip from socket in phoenix-framework?](http://stackoverflow.com/questions/33276202/how-to-get-remote-ip-from-socket-in-phoenix-framework) – PatNowak Feb 09 '17 at 07:27

2 Answers2

1

I think at this point the best way would be to send those values as params when connecting. That would probably mean getting the info from the Plug.Conn and passing it to your JS somehow, or somehow doing it all client-side.

Anyway, to get it into the socket from there, you'd do either of these two things.

on the JS side at the socket level:

var socket = new Socket("/socket", {ip: "127.0.0.1", host: "localhost"})

on the JS side at the channel level:

var channel = socket.channel("topic:subtopic", {ip: "127.0.0.1", host: "localhost"})

in your socket module:

def connect(_params = %{"ip" => ip, "host" => host}, socket) do
  socket =
    socket
    |> assign(:ip, ip)
    |> assign(:host, host)

  {:ok, socket}
end

or in your channel module:

def join("topic:subtopic", _params = %{ip: ip, host: host}, socket) do
  socket =
    socket
    |> assign(:ip, ip)
    |> assign(:host, host)

  {:noreply, socket}
end

If you needed that information for all your channels, it would make sense to do it at the socket level. I'm pretty sure either way it ends up in the socket object, so if you're using the same socket for multiple channels, you'd see the same assigns.

Erik
  • 302
  • 2
  • 12
1

To get the client's IP address and hostname in a Phoenix channel, you can use the socket.remote_ip and socket.remote_host functions.

If you want to include them in the payload, you can add them to the assigns map in the join function of your channel. For example:

def join("room:lobby", _params, socket, _assigns) do
  {:ok, assign(socket, :client_ip, socket.remote_ip), assign(socket, :client_host, socket.remote_host)}
end

Then, you can include the client_ip and client_host keys in the payload that is sent to the client when a message is broadcasted. For example:

def handle_in("new_message", %{"message" => message}, socket) do
  broadcast! socket, "new_message", %{
  message: message,
  client_ip: socket.assigns.client_ip,
  client_host: socket.assigns.client_host
}

{:noreply, socket}
end
Kociamber
  • 1,048
  • 8
  • 16