Skip to content

Commit

Permalink
Accept module plugs in Kino.Proxy.listen/1 (#448)
Browse files Browse the repository at this point in the history
  • Loading branch information
wojtekmach committed Jun 20, 2024
1 parent cc87210 commit 4094617
Showing 1 changed file with 37 additions and 4 deletions.
41 changes: 37 additions & 4 deletions lib/kino/proxy.ex
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,47 @@ defmodule Kino.Proxy do
> ```
"""

@type plug() ::
(Plug.Conn.t() -> Plug.Conn.t())
| module()
| {module(), term()}

@doc """
Registers a request listener.
Expects the listener to be a function that handles a request
`Plug.Conn`.
Expects the listener to be a plug, that is, one of:
* a function plug: a `fun(conn)` function that takes a `Plug.Conn` and returns a `Plug.Conn`.

This comment has been minimized.

Copy link
@hugobarauna

hugobarauna Jun 20, 2024

Member

Rigorously, this function does not follow the function plug contract since a function plug is a 2-arity function, right? 🤔

I don't think we need to change the docs, though. I think it's nice that the Kino.Proxy.listen/1 can receive any shape of the plug, a function plug, or a module plug. With that contract, the user can leverage his knowledge about Plugs to understand that API.

This comment has been minimized.

Copy link
@wojtekmach

wojtekmach Jun 20, 2024

Author Contributor

Right, I don't think it's a big deal in practice though because the second argument is always going to be ignored but I'm happy to support it for completeness. We have it in Bandit.start_link(plug: &fun/2), Req.get!(plug: &fun/2), and Req.Test.stub(:foo, &fun/2), for example.

This comment has been minimized.

Copy link
@josevalim

josevalim Jun 20, 2024

Contributor

I would just update the docs to say "a function"

This comment has been minimized.

Copy link
@hugobarauna

hugobarauna Jun 20, 2024

Member

Your call. :)

* a module plug: a `module` atom or a `{module, options}` tuple.
"""
@spec listen((Plug.Conn.t() -> Plug.Conn.t())) :: DynamicSupervisor.on_start_child()
def listen(fun) when is_function(fun, 1) do
@spec listen(plug()) :: DynamicSupervisor.on_start_child()
def listen(plug) do
fun =
case plug do
fun when is_function(fun, 1) ->
fun

mod when is_atom(mod) ->
opts = mod.init([])
&mod.call(&1, opts)

{mod, opts} when is_atom(mod) ->
opts = mod.init(opts)
&mod.call(&1, opts)

other ->
raise """
expected plug to be one of:
* fun(conn)
* module
* {module, options}
got: #{inspect(other)}
"""
end

case Kino.Bridge.get_proxy_handler_child_spec(fun) do
{:ok, child_spec} ->
Kino.start_child(child_spec)
Expand Down

0 comments on commit 4094617

Please sign in to comment.