defmodule ToweropsWeb.MobileSocket do @moduledoc """ WebSocket endpoint for mobile app communication. Mobile clients connect to: ws://server/mobile/socket/websocket Authentication happens at connect time using a bearer token from the mobile session system (QR code login flow). The token is passed as a `"token"` parameter during the WebSocket handshake. It is validated against the `mobile_sessions` table, and expired sessions are rejected. """ use Phoenix.Socket alias Towerops.MobileSessions channel "mobile:org:*", ToweropsWeb.MobileChannel channel "mobile:device:*", ToweropsWeb.MobileChannel @impl true @spec connect(map(), Phoenix.Socket.t(), map()) :: {:ok, Phoenix.Socket.t()} | :error def connect(%{"token" => token}, socket, _connect_info) when is_binary(token) do case MobileSessions.get_session_by_token(token) do nil -> :error session -> session = Towerops.Repo.preload(session, :user) Task.start(fn -> MobileSessions.touch_session(session) end) socket = socket |> assign(:user_id, session.user_id) |> assign(:mobile_session_id, session.id) {:ok, socket} end end def connect(_params, _socket, _connect_info), do: :error @impl true @spec id(Phoenix.Socket.t()) :: String.t() def id(socket) do "mobile_socket:#{socket.assigns.user_id}" end end