Packages
ace
0.16.8
0.19.0
0.18.10
0.18.9
0.18.8
0.18.7
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.1
0.17.0
0.16.8
0.16.7
0.16.6
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.11
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
retired
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
0.13.0
0.12.1
0.12.0
retired
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.1
0.8.0
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
HTTP web server and client, supports http1 and http2
Current section
Files
Jump to
Current section
Files
lib/ace/http/worker.ex
defmodule Ace.HTTP.Worker do
@moduledoc """
Run a Raxx application in isolation to handle a single HTTP exchange.
- The application consists of a behaviour module and initial state.
- An HTTP exchange is a single response to a single request.
See `Raxx.Server` for details on implementing a valid module.
A worker must be started for each message sent.
Even if messages are sent on a single connection,
e.g. HTTP pipelining or HTTP/2 streams.
"""
@typep application :: {module, any}
use GenServer
@enforce_keys [
:app_module,
:app_state,
:channel,
:channel_monitor
]
defstruct @enforce_keys
@doc """
Start a new worker linked to the calling process.
"""
@spec start_link(application, Ace.HTTP.Channel.t()) :: GenServer.on_start()
def start_link({module, config}, channel) do
GenServer.start_link(__MODULE__, {module, config, channel}, [])
end
@doc false
def child_spec(app) do
# NOTE child spec is called only once so possibly expensive call to `Code.ensure_compiled?` is not repeated
# `start_link` in this module could be protected by dialyzer
case Raxx.verify_application(app) do
{:ok, app} ->
%{
id: __MODULE__,
start: {__MODULE__, :start_link, [app]},
type: :worker,
restart: :temporary,
shutdown: 500
}
{:error, message} ->
raise message
end
end
## Server Callbacks
@impl GenServer
def init({module, config, channel}) do
channel_monitor = Ace.HTTP.Channel.monitor_endpoint(channel)
nil = Process.put(Ace.HTTP.Channel, channel)
{:ok,
%__MODULE__{
app_module: module,
app_state: config,
channel: channel,
channel_monitor: channel_monitor
}}
end
@impl GenServer
def handle_info({channel, part}, state = %{channel: channel}) do
Ace.HTTP.Channel.ack(channel)
Raxx.Server.handle({state.app_module, state.app_state}, part)
|> do_send(state)
end
def handle_info({:DOWN, ref, :process, _pid, reason}, state = %{channel_monitor: ref}) do
{:stop, reason, state}
end
def handle_info(other, state) do
Raxx.Server.handle({state.app_module, state.app_state}, other)
|> do_send(state)
end
defp do_send({parts, new_app_state}, state) do
new_state = %{state | app_state: new_app_state}
case Ace.HTTP.Channel.send(state.channel, parts) do
{:ok, _channel} ->
case List.last(parts) do
%{body: false} ->
{:stop, :normal, new_state}
%Raxx.Tail{} ->
{:stop, :normal, new_state}
%{body: body} when is_binary(body) ->
{:stop, :normal, new_state}
_ ->
{:noreply, new_state}
end
{:error, :connection_closed} ->
{:stop, :normal, new_state}
end
end
end