From d668cb818f59c832b447f31702864659e0d6aa39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20K=C5=82osko?= Date: Mon, 27 May 2024 15:19:40 +0700 Subject: [PATCH] Up --- lib/kino/proxy.ex | 42 ++++++++++++++++++++++++++++-------------- mix.exs | 1 + mix.lock | 4 ++++ 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/lib/kino/proxy.ex b/lib/kino/proxy.ex index 274e6185..69e99524 100644 --- a/lib/kino/proxy.ex +++ b/lib/kino/proxy.ex @@ -2,19 +2,24 @@ defmodule Kino.Proxy do @moduledoc """ Functionality for handling proxy requests forwarded from Livebook. - This functionality will make the requests forwarded from Livebook - through a proxy handler and send the response to the incoming connection - according to user definition. + Livebook proxies requests at the following paths: - The proxy handler supports the routes below to perform this proxy - between the `Livebook` and current runtime: + * `/sessions/:id/proxy/*path` - a notebook sessions - * `/sessions/:id/proxy/*path` - for notebook sessions. + * `/apps/:slug/:session_id/proxy/*path` - a specific app session - * `/apps/:slug/:session_id/proxy/*path` - for app sessions. + * `/apps/:slug/proxy/*path` - generic app path, only supported for + single-session apps - Only certain fields will be forwarded through the proxy handler, which - builds a new `%Plug.Conn{}` and sends to the listener function. + You can define a custom listener to handle requests at these paths. + The listener receives a `Plug.Conn` and should use the `Plug` API + to send the response, for example: + + Kino.Proxy.listen(fn conn -> + Plug.Conn.send_resp(conn, 200, "hello") + end + + The following `Plug.Conn` fields are set: * `:host` * `:method` @@ -27,8 +32,14 @@ defmodule Kino.Proxy do * `:script_name` * `:req_headers` - It is possible to create notebooks and apps as APIs, allowing the user to fetch the - request data and send a proper response. + > #### Plug {: .info} + > + > In order to use this feature, you need to add `:plug` as a dependency. + + ## Examples + + Using the proxy feature, you can use Livebook apps to build APIs. + For example, we could provide a data export endpoint: data = <<...>> token = "auth-token" @@ -47,12 +58,15 @@ defmodule Kino.Proxy do |> Plug.Conn.send_resp(200, "use /export/data to get extract the report data") end) - So you would need to access the `/sessions/:id/proxy/export/data` to extract the data from - your session and return as a body response. + Once deployed as an app, the user would be able to export the data + by sending a request to `/apps/:slug/proxy/export/data`. """ @doc """ - Persists the function to be listened by the proxy handler. + Registers a request listener. + + Expects the listener to be a function that handles a request + `Plug.Conn`. """ @spec listen((Plug.Conn.t() -> Plug.Conn.t())) :: DynamicSupervisor.on_start_child() def listen(fun) when is_function(fun, 1) do diff --git a/mix.exs b/mix.exs index 322f5eec..53e6bcf3 100644 --- a/mix.exs +++ b/mix.exs @@ -35,6 +35,7 @@ defmodule Kino.MixProject do {:table, "~> 0.1.2"}, {:fss, "~> 0.1.0"}, {:nx, "~> 0.1", optional: true}, + {:plug, "~> 1.0", optional: true}, {:ex_doc, "~> 0.28", only: :dev, runtime: false} ] end diff --git a/mix.lock b/mix.lock index 429d0058..d032afb6 100644 --- a/mix.lock +++ b/mix.lock @@ -6,7 +6,11 @@ "makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.5", "e0ff5a7c708dda34311f7522a8758e23bfcd7d8d8068dc312b5eb41c6fd76eba", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "94d2e986428585a21516d7d7149781480013c56e30c6a233534bedf38867a59a"}, + "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "nx": {:hex, :nx, "0.4.0", "2ec2cebec6a9ac8a3d5ae8ef79345cf92f37f9018d50817684e51e97b86f3d36", [:mix], [{:complex, "~> 0.4.2", [hex: :complex, repo: "hexpm", optional: false]}], "hexpm", "bab955768dadfe2208723fbffc9255341b023291f2aabcbd25bf98167dd3399e"}, + "plug": {:hex, :plug, "1.16.0", "1d07d50cb9bb05097fdf187b31cf087c7297aafc3fed8299aac79c128a707e47", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cbf53aa1f5c4d758a7559c0bd6d59e286c2be0c6a1fac8cc3eee2f638243b93e"}, + "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, "table": {:hex, :table, "0.1.2", "87ad1125f5b70c5dea0307aa633194083eb5182ec537efc94e96af08937e14a8", [:mix], [], "hexpm", "7e99bc7efef806315c7e65640724bf165c3061cdc5d854060f74468367065029"}, + "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, }