Current section
Files
Jump to
Current section
Files
src/tcp_client.gleam
// shamelessly copied from glisten tests! Thanks @rawhat!
import gleam/bit_builder.{BitBuilder}
import gleam/dynamic.{Dynamic}
import gleam/erlang/atom
import gleam/erlang/charlist.{Charlist}
import gleam/erlang/process
import gleam/function
import gleam/otp/actor
import gleam/result
import glisten/socket.{Socket}
import glisten/tcp
@external(erlang, "gen_tcp", "connect")
fn tcp_connect(
host host: Charlist,
port port: Int,
options options: List(Dynamic),
) -> Result(Socket, Nil)
fn connect(host: String, port: Int) -> Socket {
let assert Ok(client) =
tcp_connect(
charlist.from_string(host),
port,
[dynamic.from(atom.create_from_string("binary"))],
)
client
}
pub type ClientMessage {
ReceiveMessage(BitString)
SendMessage(BitBuilder)
Close
}
pub fn init(host: String, port: Int) {
let receiver = process.new_subject()
let assert Ok(sender) =
actor.start_spec(actor.Spec(
init: fn() {
let client = connect(host, port)
let subj = process.new_subject()
let client_selector =
process.new_selector()
|> process.selecting_record3(
atom.create_from_string("tcp"),
fn(_port, msg) {
msg
|> dynamic.bit_string
|> result.unwrap(<<>>)
|> ReceiveMessage
},
)
|> process.selecting_record2(
atom.create_from_string("tcp_closed"),
function.constant(Close),
)
|> process.selecting(subj, function.identity)
actor.Ready(client, client_selector)
},
init_timeout: 2000,
loop: fn(msg, client) {
case msg {
ReceiveMessage(msg) -> {
process.send(receiver, ReceiveMessage(msg))
actor.Continue(client)
}
SendMessage(msg) -> {
let assert Ok(_) = tcp.send(client, msg)
actor.Continue(client)
}
Close -> {
let assert Ok(_) = tcp.close(client)
actor.Stop(process.Normal)
}
}
},
))
#(sender, receiver)
}