Current section
Files
Jump to
Current section
Files
src/lustre_dev_tools/server/proxy.gleam
import filepath
import gleam/bool
import gleam/bytes_builder
import gleam/http/request.{type Request, Request}
import gleam/http/response.{type Response}
import gleam/httpc
import gleam/option.{type Option, None, Some}
import gleam/result
import gleam/string
import gleam/uri.{type Uri}
import glint
import lustre_dev_tools/cli.{type Cli, do}
import lustre_dev_tools/cli/flag
import lustre_dev_tools/error.{IncompleteProxy, InvalidProxyTarget}
import mist
import tom
// TYPES -----------------------------------------------------------------------
pub type Proxy {
Proxy(from: String, to: Uri)
}
//
pub fn middleware(
req: Request(mist.Connection),
proxy: Option(Proxy),
k: fn() -> Response(mist.ResponseData),
) -> Response(mist.ResponseData) {
case proxy {
None -> k()
Some(Proxy(from, to)) -> {
use <- bool.lazy_guard(!string.starts_with(req.path, from), k)
let internal_error =
response.new(500)
|> response.set_body(mist.Bytes(bytes_builder.new()))
let assert Some(host) = to.host
let path =
req.path
|> string.replace(from, "")
|> filepath.join(to.path, _)
let assert Ok(req) = mist.read_body(req, 100 * 1024 * 1024)
Request(..req, host: host, port: to.port, path: path)
|> httpc.send_bits
|> result.map(response.map(_, bytes_builder.from_bit_array))
|> result.map(response.map(_, mist.Bytes))
|> result.unwrap(internal_error)
}
}
}
pub fn get() -> Cli(Option(Proxy)) {
use from <- do(get_proxy_from())
use to <- do(get_proxy_to())
case from, to {
Some(from), Some(to) -> cli.return(Some(Proxy(from, to)))
Some(_), None -> cli.throw(IncompleteProxy(["proxy-to"]))
None, Some(_) -> cli.throw(IncompleteProxy(["proxy-from"]))
None, None -> cli.return(None)
}
}
fn get_proxy_from() -> Cli(Option(String)) {
use flags <- do(cli.get_flags())
use config <- do(cli.get_config())
let flag = result.nil_error(glint.get_flag(flags, flag.proxy_from()))
let toml =
result.nil_error(
tom.get_string(config.toml, ["lustre-dev", "start", "proxy", "from"]),
)
result.or(flag, toml)
|> option.from_result
|> cli.return
}
fn get_proxy_to() -> Cli(Option(Uri)) {
use flags <- do(cli.get_flags())
use config <- do(cli.get_config())
let flag = result.nil_error(glint.get_flag(flags, flag.proxy_to()))
let toml =
result.nil_error(
tom.get_string(config.toml, ["lustre-dev", "start", "proxy", "to"]),
)
let from = result.or(flag, toml)
use <- bool.guard(from == Error(Nil), cli.return(None))
let assert Ok(from) = from
case uri.parse(from) {
Ok(from) -> cli.return(Some(from))
Error(_) -> cli.throw(InvalidProxyTarget(from))
}
}