glyde/transport
What the built-in runtime asks of the outside world: one socket, one HTTP
client, one clock. glyde.with_transport swaps it for a proxy, a
recording double, or a script in a test.
Stdlib and gleam_http only. Writing a transport must not drag in the
Erlang one, which lives in glyde/transport/erlang.
Not glyde/client.Transport, which is the six outputs of the pure state
machine. This is the platform underneath one.
Types
An HTTP answer, or why there was none.
pub type Answer =
Result(response.Response(BitArray), Unreachable)
What a socket says, in order: Opened at most once and before everything,
then messages, then exactly one Closed.
pub type Event {
Opened
TextMessage(text: String)
BinaryMessage(bytes: BitArray)
Closed(code: Int, reason: String)
Failed(reason: String)
Refused(status: Int, reason: String)
}
Constructors
-
OpenedThe socket is open. Nothing can be sent before this arrives.
-
TextMessage(text: String)Discord’s gateway payloads arrive here as JSON.
-
BinaryMessage(bytes: BitArray)What Discord sends once a compressed transport is negotiated.
-
Closed(code: Int, reason: String)1006 means no close frame at all: a dial that never connected, a dead transport, a close of your own. 1005 means the peer named no code.
-
Failed(reason: String)Advisory: a
Closedalways follows and that is what ends the socket. -
Refused(status: Int, reason: String)The upgrade was answered and it was not 101. Discord sends 401 for a dead token and 429 for a bot dialling too often, and the shard reads the number. A transport that cannot see one reports
Failedinstead.
pub type Socket {
Socket(
send: fn(String) -> Bool,
close: fn(Int) -> Nil,
drop: fn() -> Nil,
turn: fn(Int) -> #(Socket, List(Event)),
)
}
Constructors
-
Socket( send: fn(String) -> Bool, close: fn(Int) -> Nil, drop: fn() -> Nil, turn: fn(Int) -> #(Socket, List(Event)), )Arguments
- send
-
Write one text frame.
Falsemeans the socket is dead: the runtime stops writing and reports the close itself. - close
-
Write a close frame with this code, then tear the socket down. Nothing to report: the socket is finished either way.
- drop
-
Abandon the socket with no close frame. Nothing to report, as above.
- turn
-
Block until the socket says something or
in_mspasses, then answer with what it said and the socket to use next.
Everything the built-in runtime asks of the outside world. Every function is synchronous: it answers before it returns.
pub type Transport {
Transport(
open: fn(String) -> Socket,
request: fn(request.Request(BitArray)) -> Result(
response.Response(BitArray),
Unreachable,
),
now: fn() -> Int,
idle: fn(Int) -> Nil,
)
}
Constructors
-
Transport( open: fn(String) -> Socket, request: fn(request.Request(BitArray)) -> Result( response.Response(BitArray), Unreachable, ), now: fn() -> Int, idle: fn(Int) -> Nil, )Arguments
- open
-
Dial a
wssURL. Blocks until TLS and the upgrade are done, and the socket reportsOpenedthrough its ownturnafterwards. - request
-
One HTTP request. Never raises: an unreachable host is
Unreachable, because a dead REST call must not take a live gateway session with it. - now
-
Milliseconds on a clock that only goes forwards. Every deadline is read from it, so a transport that jumps runs a whole session in no time.
- idle
-
Wait
in_ms. Only reached with no socket to wait on, which is the gap between a close and the next dial.
Why an HTTP request came back with nothing. A shape and not a rendering, so a caller can tell a timeout from a name that does not resolve.
pub type Unreachable {
ConnectFailed(detail: String)
TimedOut
Unreadable
Other(detail: String)
}
Constructors
-
ConnectFailed(detail: String)No connection at all: a name that does not resolve, a refused port, a TLS handshake that failed.
-
TimedOutThe request went out and nothing came back in time.
-
UnreadableSomething came back and it was not an HTTP response we could read.
-
Other(detail: String)Anything the other three do not cover, for a transport of your own.
Values
pub fn describe(reason: Unreachable) -> String
One line per reason, for a host that just wants to print it.