Group proxy endpoints under a shared prefix (#2666)

This commit is contained in:
Jonatan Kłosko 2024-06-21 14:06:18 +02:00 committed by GitHub
parent e299cc9aba
commit 29c2877272
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 46 additions and 38 deletions

View file

@ -17,7 +17,7 @@ defmodule LivebookWeb.AppAuthLive do
{:ok, push_navigate(socket, to: authenticated_path(params))}
end
defp authenticated_path(%{"slug" => slug, "id" => id}), do: ~p"/apps/#{slug}/#{id}"
defp authenticated_path(%{"slug" => slug, "id" => id}), do: ~p"/apps/#{slug}/sessions/#{id}"
defp authenticated_path(%{"slug" => slug}), do: ~p"/apps/#{slug}"
@impl true

View file

@ -16,7 +16,7 @@ defmodule LivebookWeb.AppLive do
else
{:ok, pid} = Livebook.Apps.fetch_pid(slug)
session_id = Livebook.App.get_session_id(pid, user: socket.assigns.current_user)
{:ok, push_navigate(socket, to: ~p"/apps/#{slug}/#{session_id}")}
{:ok, push_navigate(socket, to: ~p"/apps/#{slug}/sessions/#{session_id}")}
end
end
@ -70,7 +70,7 @@ defmodule LivebookWeb.AppLive do
<div :if={@app_settings.show_existing_sessions} class="w-full flex flex-col space-y-4">
<.link
:for={app_session <- active_sessions(@app.sessions)}
navigate={~p"/apps/#{@app.slug}/#{app_session.id}"}
navigate={~p"/apps/#{@app.slug}/sessions/#{app_session.id}"}
class="px-4 py-3 border border-gray-200 rounded-xl text-gray-800 pointer hover:bg-gray-50 flex justify-between"
>
<span>
@ -98,7 +98,8 @@ defmodule LivebookWeb.AppLive do
session_id =
Livebook.App.get_session_id(socket.assigns.app.pid, user: socket.assigns.current_user)
{:noreply, push_navigate(socket, to: ~p"/apps/#{socket.assigns.app.slug}/#{session_id}")}
{:noreply,
push_navigate(socket, to: ~p"/apps/#{socket.assigns.app.slug}/sessions/#{session_id}")}
end
def handle_params(_params, _url, socket), do: {:noreply, socket}

View file

@ -126,7 +126,10 @@ defmodule LivebookWeb.AppSessionLive do
</.link>
</.menu_item>
<.menu_item :if={@data_view.show_source}>
<.link patch={~p"/apps/#{@data_view.slug}/#{@session.id}/source"} role="menuitem">
<.link
patch={~p"/apps/#{@data_view.slug}/sessions/#{@session.id}/source"}
role="menuitem"
>
<.remix_icon icon="code-line" />
<span>View source</span>
</.link>
@ -211,7 +214,7 @@ defmodule LivebookWeb.AppSessionLive do
id="source-modal"
show
width={:big}
patch={~p"/apps/#{@data_view.slug}/#{@session.id}"}
patch={~p"/apps/#{@data_view.slug}/sessions/#{@session.id}"}
>
<.live_component
module={LivebookWeb.AppSessionLive.SourceComponent}

View file

@ -157,7 +157,7 @@ defmodule LivebookWeb.AppsDashboardLive do
<.icon_button
disabled={app_session.app_status.lifecycle != :active}
aria-label="open app"
href={~p"/apps/#{app.slug}/#{app_session.id}"}
href={~p"/apps/#{app.slug}/sessions/#{app_session.id}"}
>
<.remix_icon icon="link" />
</.icon_button>

View file

@ -171,7 +171,7 @@ defmodule LivebookWeb.SessionLive.AppInfoComponent do
<.icon_button
disabled={app_session.app_status.lifecycle != :active}
aria-label="open app"
href={~p"/apps/#{@app.slug}/#{app_session.id}"}
href={~p"/apps/#{@app.slug}/sessions/#{app_session.id}"}
>
<.remix_icon icon="link" />
</.icon_button>

View file

@ -8,16 +8,20 @@ defmodule LivebookWeb.ProxyPlug do
@impl true
def init(opts), do: opts
# We group all routes under the /proxy namespace, so that it's easy
# to expose them when Livebook runs behind an authentication proxy.
# The users may want to expose them, for example, to use as webhooks
@impl true
def call(%{path_info: ["sessions", id, "proxy" | path_info]} = conn, _opts) do
def call(%{path_info: ["proxy", "sessions", id | path_info]} = conn, _opts) do
session = fetch_session!(id)
Livebook.Session.reset_auto_shutdown(session.pid)
proxy_handler_spec = fetch_proxy_handler_spec!(session)
conn = prepare_conn(conn, path_info, ["sessions", id, "proxy"])
conn = prepare_conn(conn, path_info, ["proxy", "sessions", id])
call_proxy_handler(proxy_handler_spec, conn)
end
def call(%{path_info: ["apps", slug, id, "proxy" | path_info]} = conn, _opts) do
def call(%{path_info: ["proxy", "apps", slug, "sessions", id | path_info]} = conn, _opts) do
app = fetch_app!(slug)
unless Enum.any?(app.sessions, &(&1.id == id)) do
@ -28,11 +32,11 @@ defmodule LivebookWeb.ProxyPlug do
Livebook.Session.reset_auto_shutdown(session.pid)
await_app_session_ready(app, session.id)
proxy_handler_spec = fetch_proxy_handler_spec!(session)
conn = prepare_conn(conn, path_info, ["apps", slug, id, "proxy"])
conn = prepare_conn(conn, path_info, ["proxy", "apps", slug, "sessions", id])
call_proxy_handler(proxy_handler_spec, conn)
end
def call(%{path_info: ["apps", slug, "proxy" | path_info]} = conn, _opts) do
def call(%{path_info: ["proxy", "apps", slug | path_info]} = conn, _opts) do
app = fetch_app!(slug)
if app.multi_session do
@ -46,7 +50,7 @@ defmodule LivebookWeb.ProxyPlug do
Livebook.Session.reset_auto_shutdown(session.pid)
await_app_session_ready(app, session.id)
proxy_handler_spec = fetch_proxy_handler_spec!(session)
conn = prepare_conn(conn, path_info, ["apps", slug, "proxy"])
conn = prepare_conn(conn, path_info, ["proxy", "apps", slug])
call_proxy_handler(proxy_handler_spec, conn)
end

View file

@ -146,8 +146,8 @@ defmodule LivebookWeb.Router do
live "/apps/:slug/new", AppLive, :new_session
live "/apps/:slug/authenticate", AppAuthLive, :page
live "/apps/:slug/:id", AppSessionLive, :page
live "/apps/:slug/:id/source", AppSessionLive, :source
live "/apps/:slug/sessions/:id", AppSessionLive, :page
live "/apps/:slug/sessions/:id/source", AppSessionLive, :source
live "/apps", AppsLive, :page
end

View file

@ -108,7 +108,7 @@ defmodule LivebookWeb.AppAuthLiveTest do
{:ok, view, _} =
conn
|> live(~p"/apps/#{slug}/#{session_id}")
|> live(~p"/apps/#{slug}/sessions/#{session_id}")
|> follow_redirect(conn)
view
@ -118,7 +118,7 @@ defmodule LivebookWeb.AppAuthLiveTest do
assert_push_event(view, "persist_app_auth", %{"slug" => ^slug, "token" => _token})
assert {:error, {:live_redirect, %{to: to}}} = render_hook(view, "app_auth_persisted")
assert to == ~p"/apps/#{slug}/#{session_id}"
assert to == ~p"/apps/#{slug}/sessions/#{session_id}"
end
test "redirects to the app page when authenticating in Livebook", %{conn: conn, slug: slug} do

View file

@ -19,7 +19,7 @@ defmodule LivebookWeb.AppLiveTest do
assert_receive {:app_updated, %{pid: ^app_pid, sessions: [%{id: session_id}]}}
{:error, {:live_redirect, %{to: to}}} = live(conn, ~p"/apps/#{slug}")
assert to == ~p"/apps/#{slug}/#{session_id}"
assert to == ~p"/apps/#{slug}/sessions/#{session_id}"
App.close(app_pid)
end
@ -59,8 +59,8 @@ defmodule LivebookWeb.AppLiveTest do
{:ok, view, _} = live(conn, ~p"/apps/#{slug}")
assert render(view) =~ ~p"/apps/#{slug}/#{session_id1}"
refute render(view) =~ ~p"/apps/#{slug}/#{session_id2}"
assert render(view) =~ ~p"/apps/#{slug}/sessions/#{session_id1}"
refute render(view) =~ ~p"/apps/#{slug}/sessions/#{session_id2}"
# Create a new app session
session_id3 = App.get_session_id(app_pid)
@ -68,7 +68,7 @@ defmodule LivebookWeb.AppLiveTest do
assert_receive {:app_updated,
%{pid: ^app_pid, sessions: [%{id: ^session_id3, pid: session_pid3}, _, _]}}
assert render(view) =~ ~p"/apps/#{slug}/#{session_id3}"
assert render(view) =~ ~p"/apps/#{slug}/sessions/#{session_id3}"
# Deactivate the app session
Livebook.Session.app_deactivate(session_pid3)
@ -79,8 +79,8 @@ defmodule LivebookWeb.AppLiveTest do
sessions: [%{app_status: %{lifecycle: :deactivated}}, _, _]
}}
assert render(view) =~ ~p"/apps/#{slug}/#{session_id1}"
refute render(view) =~ ~p"/apps/#{slug}/#{session_id3}"
assert render(view) =~ ~p"/apps/#{slug}/sessions/#{session_id1}"
refute render(view) =~ ~p"/apps/#{slug}/sessions/#{session_id3}"
App.close(app_pid)
end
@ -104,7 +104,7 @@ defmodule LivebookWeb.AppLiveTest do
assert_receive {:app_updated, %{pid: ^app_pid, sessions: [%{id: session_id}]}}
assert to == ~p"/apps/#{slug}/#{session_id}"
assert to == ~p"/apps/#{slug}/sessions/#{session_id}"
App.close(app_pid)
end

View file

@ -14,7 +14,7 @@ defmodule LivebookWeb.AppSessionLiveTest do
app_pid = deploy_notebook_sync(notebook)
{:ok, view, _} = live(conn, ~p"/apps/#{slug}/nonexistent")
{:ok, view, _} = live(conn, ~p"/apps/#{slug}/sessions/nonexistent")
assert render(view) =~ "This app session does not exist"
assert render(view) =~ ~p"/apps/#{slug}"
@ -39,7 +39,7 @@ defmodule LivebookWeb.AppSessionLiveTest do
assert_receive {:app_updated,
%{pid: ^app_pid, sessions: [%{app_status: %{lifecycle: :deactivated}}]}}
{:ok, view, _} = live(conn, ~p"/apps/#{slug}/#{session_id}")
{:ok, view, _} = live(conn, ~p"/apps/#{slug}/sessions/#{session_id}")
assert render(view) =~ "This app session does not exist"
assert render(view) =~ ~p"/apps/#{slug}"
@ -59,7 +59,7 @@ defmodule LivebookWeb.AppSessionLiveTest do
assert_receive {:app_updated,
%{pid: ^app_pid, sessions: [%{id: session_id, pid: session_pid}]}}
{:ok, view, _} = live(conn, ~p"/apps/#{slug}/#{session_id}")
{:ok, view, _} = live(conn, ~p"/apps/#{slug}/sessions/#{session_id}")
Livebook.Session.app_deactivate(session_pid)

View file

@ -2246,7 +2246,7 @@ defmodule LivebookWeb.SessionLiveTest do
assert_receive {:app_updated,
%{slug: ^slug, sessions: [%{app_status: %{lifecycle: :deactivated}}]}}
assert render(view) =~ "/apps/#{slug}/#{app_session.id}"
assert render(view) =~ "/apps/#{slug}/sessions/#{app_session.id}"
view
|> element(~s/[data-el-app-info] button[aria-label="terminate app session"]/)
@ -2254,7 +2254,7 @@ defmodule LivebookWeb.SessionLiveTest do
assert_receive {:app_updated, %{slug: ^slug, sessions: []}}
refute render(view) =~ "/apps/#{slug}/#{app_session.id}"
refute render(view) =~ "/apps/#{slug}/sessions/#{app_session.id}"
Livebook.App.close(app.pid)
end

View file

@ -13,7 +13,7 @@ defmodule LivebookWeb.ProxyPlugTest do
session_id = Livebook.Utils.random_long_id()
assert_error_sent 404, fn ->
get(conn, "/sessions/#{session_id}/proxy/foo/bar")
get(conn, "/proxy/sessions/#{session_id}/foo/bar")
end
end
@ -21,7 +21,7 @@ defmodule LivebookWeb.ProxyPlugTest do
{:ok, session} = Sessions.create_session()
assert_error_sent 404, fn ->
get(conn, "/sessions/#{session.id}/proxy/foo/bar")
get(conn, "/proxy/sessions/#{session.id}/foo/bar")
end
end
@ -38,7 +38,7 @@ defmodule LivebookWeb.ProxyPlugTest do
{:add_cell_evaluation_response, _, ^cell_id, _, %{errored: false}}},
4_000
url = "/sessions/#{session.id}/proxy/"
url = "/proxy/sessions/#{session.id}/"
assert text_response(get(conn, url), 200) == "used GET method"
assert text_response(post(conn, url), 200) == "used POST method"
@ -56,7 +56,7 @@ defmodule LivebookWeb.ProxyPlugTest do
session_id = Livebook.Utils.random_long_id()
assert_error_sent 404, fn ->
get(conn, "/apps/#{slug}/#{session_id}/proxy/foo/bar")
get(conn, "/proxy/apps/#{slug}/sessions/#{session_id}/foo/bar")
end
end
@ -73,7 +73,7 @@ defmodule LivebookWeb.ProxyPlugTest do
assert_receive {:app_updated,
%{slug: ^slug, sessions: [%{id: id, app_status: %{execution: :executed}}]}}
url = "/apps/#{slug}/#{id}/proxy/"
url = "/proxy/apps/#{slug}/sessions/#{id}/"
assert text_response(get(conn, url), 200) == "used GET method"
assert text_response(post(conn, url), 200) == "used POST method"
@ -82,7 +82,7 @@ defmodule LivebookWeb.ProxyPlugTest do
assert text_response(delete(conn, url), 200) == "used DELETE method"
# Generic path also works for single-session apps
url = "/apps/#{slug}/proxy/"
url = "/proxy/apps/#{slug}/"
assert text_response(get(conn, url), 200) == "used GET method"
end
@ -107,7 +107,7 @@ defmodule LivebookWeb.ProxyPlugTest do
# The app is configured with auto shutdown, so the session will
# start only once requested. We should wait until it executes
# and then proxy the request as usual
url = "/apps/#{slug}/proxy/"
url = "/proxy/apps/#{slug}/"
assert text_response(get(conn, url), 200) == "used GET method"
end
@ -130,7 +130,7 @@ defmodule LivebookWeb.ProxyPlugTest do
assert_receive {:app_created, %{pid: ^pid, slug: ^slug, sessions: []}}
assert_error_sent 400, fn ->
get(conn, "/apps/#{slug}/proxy/foo/bar")
get(conn, "/proxy/apps/#{slug}/foo/bar")
end
end
end