mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-26 05:16:29 +08:00
Attempt to load a flat remote URL as a relative path fallback (#1428)
This commit is contained in:
parent
1799f0a303
commit
b20ac022a8
2 changed files with 61 additions and 6 deletions
|
|
@ -6,7 +6,7 @@ defmodule LivebookWeb.SessionLive do
|
||||||
import Livebook.Utils, only: [format_bytes: 1]
|
import Livebook.Utils, only: [format_bytes: 1]
|
||||||
|
|
||||||
alias Livebook.{Sessions, Session, Delta, Notebook, Runtime, LiveMarkdown}
|
alias Livebook.{Sessions, Session, Delta, Notebook, Runtime, LiveMarkdown}
|
||||||
alias Livebook.Notebook.Cell
|
alias Livebook.Notebook.{Cell, ContentLoader}
|
||||||
alias Livebook.JSInterop
|
alias Livebook.JSInterop
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
|
@ -1242,7 +1242,8 @@ defmodule LivebookWeb.SessionLive do
|
||||||
|> redirect_to_self()
|
|> redirect_to_self()
|
||||||
|
|
||||||
resolution_location ->
|
resolution_location ->
|
||||||
origin = Notebook.ContentLoader.resolve_location(resolution_location, relative_path)
|
origin = ContentLoader.resolve_location(resolution_location, relative_path)
|
||||||
|
fallback_locations = fallback_relative_locations(resolution_location, relative_path)
|
||||||
|
|
||||||
case session_id_by_location(origin) do
|
case session_id_by_location(origin) do
|
||||||
{:ok, session_id} ->
|
{:ok, session_id} ->
|
||||||
|
|
@ -1252,7 +1253,7 @@ defmodule LivebookWeb.SessionLive do
|
||||||
push_redirect(socket, to: redirect_path)
|
push_redirect(socket, to: redirect_path)
|
||||||
|
|
||||||
{:error, :none} ->
|
{:error, :none} ->
|
||||||
open_notebook(socket, origin, requested_url)
|
open_notebook(socket, origin, fallback_locations, requested_url)
|
||||||
|
|
||||||
{:error, :many} ->
|
{:error, :many} ->
|
||||||
origin_str =
|
origin_str =
|
||||||
|
|
@ -1282,12 +1283,12 @@ defmodule LivebookWeb.SessionLive do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp open_notebook(socket, origin, requested_url) do
|
defp open_notebook(socket, origin, fallback_locations, requested_url) do
|
||||||
case Notebook.ContentLoader.fetch_content_from_location(origin) do
|
case fetch_content_with_fallbacks(origin, fallback_locations) do
|
||||||
{:ok, content} ->
|
{:ok, content} ->
|
||||||
{notebook, messages} = Livebook.LiveMarkdown.notebook_from_livemd(content)
|
{notebook, messages} = Livebook.LiveMarkdown.notebook_from_livemd(content)
|
||||||
|
|
||||||
# If the current session has no path, fork the notebook
|
# If the current session has no file, fork the notebook
|
||||||
fork? = socket.private.data.file == nil
|
fork? = socket.private.data.file == nil
|
||||||
{file, notebook} = file_and_notebook(fork?, origin, notebook)
|
{file, notebook} = file_and_notebook(fork?, origin, notebook)
|
||||||
url_hash = get_url_hash(requested_url)
|
url_hash = get_url_hash(requested_url)
|
||||||
|
|
@ -1308,6 +1309,32 @@ defmodule LivebookWeb.SessionLive do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def fallback_relative_locations({:file, _}, _relative_path), do: []
|
||||||
|
|
||||||
|
def fallback_relative_locations(resolution_location, relative_path) do
|
||||||
|
# Other locations to check in case the relative location doesn't
|
||||||
|
# exist. For example, in ExDoc all pages (including notebooks) are
|
||||||
|
# flat, regardless of how they are structured in the file system
|
||||||
|
|
||||||
|
name = relative_path |> String.split("/") |> Enum.at(-1)
|
||||||
|
flat_location = ContentLoader.resolve_location(resolution_location, name)
|
||||||
|
[flat_location]
|
||||||
|
end
|
||||||
|
|
||||||
|
defp fetch_content_with_fallbacks(location, fallbacks) do
|
||||||
|
case ContentLoader.fetch_content_from_location(location) do
|
||||||
|
{:ok, content} ->
|
||||||
|
{:ok, content}
|
||||||
|
|
||||||
|
error ->
|
||||||
|
fallbacks
|
||||||
|
|> Enum.reject(&(&1 == location))
|
||||||
|
|> Enum.find_value(error, fn fallback ->
|
||||||
|
with {:error, _} <- ContentLoader.fetch_content_from_location(fallback), do: nil
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp file_and_notebook(fork?, origin, notebook)
|
defp file_and_notebook(fork?, origin, notebook)
|
||||||
defp file_and_notebook(false, {:file, file}, notebook), do: {file, notebook}
|
defp file_and_notebook(false, {:file, file}, notebook), do: {file, notebook}
|
||||||
defp file_and_notebook(true, {:file, _file}, notebook), do: {nil, Notebook.forked(notebook)}
|
defp file_and_notebook(true, {:file, _file}, notebook), do: {nil, Notebook.forked(notebook)}
|
||||||
|
|
|
||||||
|
|
@ -834,6 +834,34 @@ defmodule LivebookWeb.SessionLiveTest do
|
||||||
close_session_by_id(session_id)
|
close_session_by_id(session_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "when a remote URL cannot be loaded, attempts to resolve a flat URL", %{conn: conn} do
|
||||||
|
bypass = Bypass.open()
|
||||||
|
|
||||||
|
# Multi-level path is not available
|
||||||
|
Bypass.expect_once(bypass, "GET", "/nested/path/to/notebook.livemd", fn conn ->
|
||||||
|
Plug.Conn.resp(conn, 500, "Error")
|
||||||
|
end)
|
||||||
|
|
||||||
|
# A flat path is available
|
||||||
|
Bypass.expect_once(bypass, "GET", "/notebook.livemd", fn conn ->
|
||||||
|
conn
|
||||||
|
|> Plug.Conn.put_resp_content_type("text/plain")
|
||||||
|
|> Plug.Conn.resp(200, "# My notebook")
|
||||||
|
end)
|
||||||
|
|
||||||
|
index_url = url(bypass.port) <> "/index.livemd"
|
||||||
|
{:ok, session} = Sessions.create_session(origin: {:url, index_url})
|
||||||
|
|
||||||
|
assert {:error, {:live_redirect, %{to: "/sessions/" <> session_id}}} =
|
||||||
|
result = live(conn, "/sessions/#{session.id}/nested/path/to/notebook.livemd")
|
||||||
|
|
||||||
|
{:ok, view, _} = follow_redirect(result, conn)
|
||||||
|
assert render(view) =~ "My notebook"
|
||||||
|
|
||||||
|
Session.close(session.pid)
|
||||||
|
close_session_by_id(session_id)
|
||||||
|
end
|
||||||
|
|
||||||
test "renders an error message if relative remote notebook cannot be loaded", %{conn: conn} do
|
test "renders an error message if relative remote notebook cannot be loaded", %{conn: conn} do
|
||||||
bypass = Bypass.open()
|
bypass = Bypass.open()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue