#net
TCP connections and name resolution.
connect opens a connection and listen and accept receive them.
Connection and Listener are distinct handle types, so one cannot be
passed where the other is expected. sendAll and recvAll
loop until every byte is transferred, and sendString, recvString,
sendLine, and recvLine work in UTF-8 text. withConnection,
withListener, and serveLoop close their handle when the body
finishes, on the Ok and Err paths alike.
Every operation returns Result String a, with the host's error message
in Err. Networking works only in a program built for the native
backend: the interpreter does not bind the net primitives, and the
WebAssembly backend rejects a program that imports this module.
#Handles
#Connection
type Connection (h : Authority Net) = Socket hA connected TCP socket, from connect or accept, at the authority of
the host it reaches.
#Listener
type Listener (a : Authority Net) = ListenSocket aA listening TCP socket, from listen, at the authority of its address.
#Shutdown
data Shutdown
= ShutdownRead
| ShutdownWrite
| ShutdownBothWhich direction of a connection shutdown closes.
#Clients
#resolve
resolve : (host : String) -> <Net host> Result String (List String)
resolve hostThe numeric addresses a host name resolves to.
resolve "localhost" gives Ok ["127.0.0.1"] or similar.
#connect
connect : (host : String) -> Int -> <Net host> Result String (Connection host)
connect host portA connection to host on port.
The host name is resolved first. withConnection is the form that
closes the connection for you.
#Servers
#listen
listen : (addr : String) -> Int -> <Net addr> Result String (Listener addr)
listen addr portA listener bound to addr on port.
Port 0 lets the system pick a free port; listenPort reports which.
#listenPort
listenPort : Listener a -> <Net a> Result String Int
listenPort lisThe port a listener is bound to.
#accept
accept : Listener a -> <Net a> Result String (Connection a)
accept lisWaits for the next connection to a listener.
The connection is at the listener's authority: it is reached through the address the listener was granted.
#Transfer
#send
send : Connection h -> Bytes -> <Net h> Result String Int
send conn bsSends bytes in one call. The result is the number of bytes written, which may be fewer than given.
sendAll is the form that sends everything.
#recv
recv : Connection h -> Int -> <Net h> Result String Bytes
recv conn nReceives up to n bytes in one call.
An empty result means the peer has closed the connection. recvAll is
the form that reads to the end.
#sendAll
sendAll : Connection h -> Bytes -> <Net h> Result String Unit
sendAll conn bsSends every byte, looping over send as needed.
Err on the first failed send, or when a send writes nothing, which is
treated as a stalled connection.
#recvAll
recvAll : Connection h -> <Net h> Result String Bytes
recvAll connReceives everything until the peer closes the connection.
Err on the first failed receive; whatever was read before it is
discarded.
#Text
#sendString
sendString : Connection h -> String -> <Net h> Result String Unit
sendString conn sSends a string as UTF-8, every byte of it.
#recvString
recvString : Connection h -> <Net h> Result String String
recvString connReceives everything until the peer closes the connection, decoded as UTF-8.
For a connection that stays open, read a line at a time with recvLine
or a bounded amount with recv.
#sendLine
sendLine : Connection h -> String -> <Net h> Result String Unit
sendLine conn sSends a string as UTF-8 followed by a newline.
#recvLine
recvLine : Connection h -> <Net h> Result String (Option String)
recvLine connReceives one line, without its newline.
None when the peer has closed the connection and nothing was pending.
A final line with no newline is still returned. Reads one byte per call,
so it suits small line-based messages, not bulk transfer.
#Lifecycle
#shutdown
shutdown : Connection h -> Shutdown -> <Net h> Result String Unit
shutdown conn howShuts down one or both directions of a connection without closing it.
#close
close : Connection h -> <Net h> Result String Unit
close connCloses a connection.
Closing twice is not an error. withConnection closes for you.
#closeListener
closeListener : Listener a -> <Net a> Result String Unit
closeListener lisCloses a listener.
#setTimeout
setTimeout : Connection h -> Duration -> <Net h> Result String Unit
setTimeout conn dSets a connection's send and receive timeout.
A zero duration means no timeout. Set one on any long-lived connection so a stalled peer cannot block forever.
#withConnection
withConnection : (host : String) -> Int -> (Connection host -> <Net host | e> Result String a) -> <Net host | e> Result String a
withConnection host port bodyConnects to host on port, runs body on the connection, and closes
it whatever body returns.
The result is body's result, or the connection error when connecting
fails, in which case body does not run.
withConnection "127.0.0.1" 9000 (conn => sendString conn "hi")
#withListener
withListener : (addr : String) -> Int -> (Listener addr -> <Net addr | e> Result String a) -> <Net addr | e> Result String a
withListener addr port bodyListens on addr and port, runs body on the listener, and closes
it whatever body returns.
The result is body's result, or the error when listening fails.
#serveLoop
serveLoop : Listener a -> (Connection a -> <Net a | e> Result String Unit) -> <Net a | e> Result String Unit
serveLoop lis handleAccepts connections forever, running handle on each and closing it
afterwards.
A failure in handle closes that connection and the loop continues. A
failure in accept ends the loop with the error. Pair it with
withListener to close the listener when the loop ends.