Packages
glisten
0.7.0
9.0.1
9.0.0
9.0.0-rc1
8.0.3
8.0.2
8.0.1
8.0.0
8.0.0-rc1
7.0.1
7.0.0
6.0.0
5.0.0
4.0.0
3.0.0
2.0.0
1.0.0
0.11.0
0.10.2
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.1
0.5.0
0.4.0
0.3.2
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
a shiny Gleam TCP/TLS server
Current section
Files
Jump to
Current section
Files
src/glisten.gleam
import gleam/dynamic.{Dynamic}
import gleam/erlang/process
import gleam/result
import glisten/acceptor.{Pool, over_ssl}
import glisten/socket.{Closed, ListenSocket, SocketReason, Timeout}
import glisten/tcp
import glisten/ssl
import gleam/otp/actor
import glisten/socket/options.{Certfile, Keyfile}
/// Reasons that `serve` might fail
pub type StartError {
ListenerClosed
ListenerTimeout
AcceptorTimeout
AcceptorFailed(process.ExitReason)
AcceptorCrashed(Dynamic)
SystemError(SocketReason)
}
/// Sets up a TCP listener with the given acceptor pool. The second argument
/// can be obtained from the `glisten/acceptor.{acceptor_pool}` function.
pub fn serve(
port: Int,
with_pool: fn(ListenSocket) -> Pool(data),
) -> Result(Nil, StartError) {
port
|> tcp.listen([])
|> result.map_error(fn(err) {
case err {
Closed -> ListenerClosed
Timeout -> ListenerTimeout
err -> SystemError(err)
}
})
|> result.then(fn(socket) {
socket
|> with_pool
|> acceptor.start_pool
|> result.map_error(fn(err) {
case err {
actor.InitTimeout -> AcceptorTimeout
actor.InitFailed(reason) -> AcceptorFailed(reason)
actor.InitCrashed(reason) -> AcceptorCrashed(reason)
}
})
})
|> result.replace(Nil)
}
external fn start_ssl() -> Result(Nil, Dynamic) =
"ssl_ffi" "start_ssl"
/// Sets up a SSL listener with the given acceptor pool. The second argument
/// can be obtained from the `glisten/acceptor.{acceptor_pool}` function.
pub fn serve_ssl(
port port: Int,
certfile certfile: String,
keyfile keyfile: String,
with_pool with_pool: fn(ListenSocket) -> Pool(data),
) -> Result(Nil, StartError) {
let assert Ok(_nil) = start_ssl()
port
|> ssl.listen([Certfile(certfile), Keyfile(keyfile)])
|> result.map_error(fn(err) {
case err {
Closed -> ListenerClosed
Timeout -> ListenerTimeout
err -> SystemError(err)
}
})
|> result.then(fn(socket) {
socket
|> over_ssl(with_pool)
|> acceptor.start_pool
|> result.map_error(fn(err) {
case err {
actor.InitTimeout -> AcceptorTimeout
actor.InitFailed(reason) -> AcceptorFailed(reason)
actor.InitCrashed(reason) -> AcceptorCrashed(reason)
}
})
})
|> result.replace(Nil)
}