- add MobileSocket for token-authenticated mobile WebSocket connections - add MobileChannel with org-level and device-level real-time events - add /mobile/socket endpoint for iOS app connections - add "Link Mobile App" to user dropdown menu for discoverability - improve QR code page with numbered steps and clearer instructions - add socket/channel tests (17 total)
48 lines
1.4 KiB
Elixir
48 lines
1.4 KiB
Elixir
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
|