Current section

Files

Jump to
wisp src wisp wisp_mist.gleam
Raw

src/wisp/wisp_mist.gleam

import exception
import gleam/bytes_tree
import gleam/http/request.{type Request as HttpRequest}
import gleam/http/response.{type Response as HttpResponse}
import gleam/option
import gleam/result
import gleam/string
import mist
import wisp
import wisp/internal
//
// Running the server
//
/// Convert a Wisp request handler into a function that can be run with the Mist
/// web server.
///
/// # Examples
///
/// ```gleam
/// pub fn main() {
/// let secret_key_base = "..."
/// let assert Ok(_) =
/// handle_request
/// |> wisp_mist.handler(secret_key_base)
/// |> mist.new
/// |> mist.port(8000)
/// |> mist.start_http
/// process.sleep_forever()
/// }
/// ```
pub fn handler(
handler: fn(wisp.Request) -> wisp.Response,
secret_key_base: String,
) -> fn(HttpRequest(mist.Connection)) -> HttpResponse(mist.ResponseData) {
fn(request: HttpRequest(_)) {
let connection =
internal.make_connection(mist_body_reader(request), secret_key_base)
let request = request.set_body(request, connection)
use <- exception.defer(fn() {
let assert Ok(_) = wisp.delete_temporary_files(request)
})
let response =
request
|> handler
|> mist_response
response
}
}
fn mist_body_reader(request: HttpRequest(mist.Connection)) -> internal.Reader {
case mist.stream(request) {
Error(_) -> fn(_) { Ok(internal.ReadingFinished) }
Ok(stream) -> fn(size) { wrap_mist_chunk(stream(size)) }
}
}
fn wrap_mist_chunk(
chunk: Result(mist.Chunk, mist.ReadError),
) -> Result(internal.Read, Nil) {
chunk
|> result.replace_error(Nil)
|> result.map(fn(chunk) {
case chunk {
mist.Done -> internal.ReadingFinished
mist.Chunk(data, consume) ->
internal.Chunk(data, fn(size) { wrap_mist_chunk(consume(size)) })
}
})
}
fn mist_response(response: wisp.Response) -> HttpResponse(mist.ResponseData) {
let body = case response.body {
wisp.Empty -> mist.Bytes(bytes_tree.new())
wisp.Text(text) -> mist.Bytes(bytes_tree.from_string_tree(text))
wisp.Bytes(bytes) -> mist.Bytes(bytes)
wisp.File(path) -> mist_send_file(path)
}
response
|> response.set_body(body)
}
fn mist_send_file(path: String) -> mist.ResponseData {
case mist.send_file(path, offset: 0, limit: option.None) {
Ok(body) -> body
Error(error) -> {
wisp.log_error(string.inspect(error))
// TODO: return 500
mist.Bytes(bytes_tree.new())
}
}
}