82 lines
2.1 KiB
Gleam
82 lines
2.1 KiB
Gleam
import gleam/erlang/process.{type Subject}
|
|
import gleam/io
|
|
import gleam/otp/actor
|
|
import gleam/result
|
|
import gleam/string
|
|
|
|
import musicplayer/tcp/reason.{type Reason}
|
|
import musicplayer/tcp/tcp
|
|
|
|
pub type Message {
|
|
Shutdown
|
|
ReadyToAccept(subject: Subject(Message), listen_socket: tcp.Socket)
|
|
}
|
|
|
|
pub fn new(socket_path: String) -> Result(tcp.Socket, String) {
|
|
let server = actor.new(Nil) |> actor.on_message(handle_message) |> actor.start
|
|
|
|
case tcp.listen(socket_path), server {
|
|
Error(r), _ -> Error(reason.to_string(r))
|
|
_, Error(start_error) ->
|
|
case start_error {
|
|
actor.InitExited(_) -> Error("InitExited")
|
|
actor.InitFailed(_) -> Error("InitFailed")
|
|
actor.InitTimeout -> Error("InitTimeout")
|
|
}
|
|
Ok(listen_socket), Ok(b) -> {
|
|
let subject = b.data
|
|
actor.send(subject, ReadyToAccept(subject, listen_socket))
|
|
Ok(listen_socket)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn handle_message(_: Nil, message: Message) -> actor.Next(Nil, Message) {
|
|
case message {
|
|
Shutdown -> actor.stop()
|
|
|
|
ReadyToAccept(subject, listen_socket) -> {
|
|
case tcp.accept(listen_socket) {
|
|
Error(r) ->
|
|
actor.stop_abnormal(
|
|
"Could not accept connection :" <> reason.to_string(r),
|
|
)
|
|
Ok(socket) -> {
|
|
case receive_from_connection(socket) {
|
|
Error(r) ->
|
|
io.println_error(
|
|
"Failed to receive from connection :" <> reason.to_string(r),
|
|
)
|
|
Ok(_) -> Nil
|
|
}
|
|
|
|
actor.send(subject, ReadyToAccept(subject, listen_socket))
|
|
actor.continue(Nil)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn receive_from_connection(socket: tcp.Socket) -> Result(Nil, Reason) {
|
|
result.try(receive_until_closed(socket, ""), fn(data) {
|
|
let _ = tcp.send(socket, data)
|
|
tcp.close(socket)
|
|
Ok(Nil)
|
|
})
|
|
}
|
|
|
|
fn receive_until_closed(
|
|
socket: tcp.Socket,
|
|
result: String,
|
|
) -> Result(String, Reason) {
|
|
case tcp.receive(socket, 10_000) {
|
|
Error(reason.Closed) -> Ok(result)
|
|
Error(err) -> Error(err)
|
|
Ok(data) -> {
|
|
let result = data |> string.append(result, _)
|
|
receive_until_closed(socket, result)
|
|
}
|
|
}
|
|
}
|