Compare commits
2 Commits
c76d1aaa53
...
738798da3b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
738798da3b | ||
|
|
0fa2ce4d0e |
@@ -1,7 +1,5 @@
|
|||||||
import gleam/bytes_tree
|
import gleam/bytes_tree
|
||||||
|
|
||||||
import tcp/reason.{type Reason}
|
|
||||||
|
|
||||||
pub type Socket
|
pub type Socket
|
||||||
|
|
||||||
// https://www.erlang.org/doc/apps/kernel/inet#t:address_family/0
|
// https://www.erlang.org/doc/apps/kernel/inet#t:address_family/0
|
||||||
@@ -14,12 +12,16 @@ type ModeValue {
|
|||||||
Binary
|
Binary
|
||||||
}
|
}
|
||||||
|
|
||||||
type TCPOption {
|
type IPCOption {
|
||||||
Active(Bool)
|
Active(Bool)
|
||||||
Mode(ModeValue)
|
Mode(ModeValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect(socket_path: String) -> Result(Socket, Reason) {
|
pub type IPCError {
|
||||||
|
IPCError(reason: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connect(socket_path: String) -> Result(Socket, IPCError) {
|
||||||
let options = [Mode(Binary), Active(False)]
|
let options = [Mode(Binary), Active(False)]
|
||||||
|
|
||||||
// timeout in ms
|
// timeout in ms
|
||||||
@@ -28,7 +30,7 @@ pub fn connect(socket_path: String) -> Result(Socket, Reason) {
|
|||||||
gen_tcp_connect(Local(socket_path), 0, options, timeout)
|
gen_tcp_connect(Local(socket_path), 0, options, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(socket: Socket, message: String) -> Result(Nil, Reason) {
|
pub fn send(socket: Socket, message: String) -> Result(Nil, IPCError) {
|
||||||
gen_tcp_send(socket, bytes_tree.from_string(message))
|
gen_tcp_send(socket, bytes_tree.from_string(message))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,16 +43,16 @@ pub fn close(socket: Socket) -> Nil {
|
|||||||
fn gen_tcp_connect(
|
fn gen_tcp_connect(
|
||||||
address: Local,
|
address: Local,
|
||||||
port: Int,
|
port: Int,
|
||||||
options: List(TCPOption),
|
options: List(IPCOption),
|
||||||
timeout: Int,
|
timeout: Int,
|
||||||
) -> Result(Socket, Reason)
|
) -> Result(Socket, IPCError)
|
||||||
|
|
||||||
// https://www.erlang.org/doc/apps/kernel/gen_tcp.html#send/2
|
// https://www.erlang.org/doc/apps/kernel/gen_tcp.html#send/2
|
||||||
@external(erlang, "ipc_ffi", "send")
|
@external(erlang, "ipc_ffi", "send")
|
||||||
fn gen_tcp_send(
|
fn gen_tcp_send(
|
||||||
socket: Socket,
|
socket: Socket,
|
||||||
packet: bytes_tree.BytesTree,
|
packet: bytes_tree.BytesTree,
|
||||||
) -> Result(Nil, Reason)
|
) -> Result(Nil, IPCError)
|
||||||
|
|
||||||
// https://www.erlang.org/doc/apps/kernel/gen_tcp.html#close/1
|
// https://www.erlang.org/doc/apps/kernel/gen_tcp.html#close/1
|
||||||
@external(erlang, "gen_tcp", "close")
|
@external(erlang, "gen_tcp", "close")
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
-module(tcp_ffi).
|
-module(ipc_ffi).
|
||||||
-export([send/2]).
|
-export([send/2]).
|
||||||
|
|
||||||
send(Socket, Packet) ->
|
send(Socket, Packet) ->
|
||||||
@@ -1,14 +1,11 @@
|
|||||||
import gleam/io
|
import gleam/io
|
||||||
|
import ipc
|
||||||
import tcp/reason
|
|
||||||
import tcp/tcp
|
|
||||||
|
|
||||||
pub fn main() -> Nil {
|
pub fn main() -> Nil {
|
||||||
let socket_path = "/tmp/musicplayer.sock"
|
let socket_path = "/tmp/musicplayer.sock"
|
||||||
|
|
||||||
case tcp.connect(socket_path) {
|
case ipc.connect(socket_path) {
|
||||||
Error(r) ->
|
Error(err) -> io.println("Failed to connect to socket: " <> err.reason)
|
||||||
io.println("Failed to connect to socket: " <> reason.to_string(r))
|
|
||||||
Ok(socket) -> {
|
Ok(socket) -> {
|
||||||
io.println("connected")
|
io.println("connected")
|
||||||
|
|
||||||
@@ -17,12 +14,12 @@ pub fn main() -> Nil {
|
|||||||
messages |> send_messages(socket, _)
|
messages |> send_messages(socket, _)
|
||||||
|
|
||||||
io.println("closing")
|
io.println("closing")
|
||||||
tcp.close(socket)
|
ipc.close(socket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_messages(socket: tcp.Socket, messages: List(String)) -> Nil {
|
fn send_messages(socket: ipc.Socket, messages: List(String)) -> Nil {
|
||||||
case messages {
|
case messages {
|
||||||
[] -> Nil
|
[] -> Nil
|
||||||
[message, ..rest] -> {
|
[message, ..rest] -> {
|
||||||
@@ -32,10 +29,9 @@ fn send_messages(socket: tcp.Socket, messages: List(String)) -> Nil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_message(socket: tcp.Socket, message: String) -> Nil {
|
fn send_message(socket: ipc.Socket, message: String) -> Nil {
|
||||||
case tcp.send(socket, message) {
|
case ipc.send(socket, message) {
|
||||||
Error(r) ->
|
Error(err) -> io.println("Failed to send message to socket: " <> err.reason)
|
||||||
io.println("Failed to send message to socket: " <> reason.to_string(r))
|
|
||||||
Ok(_) -> io.println("Sent message to socket")
|
Ok(_) -> io.println("Sent message to socket")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,240 +0,0 @@
|
|||||||
pub type Reason {
|
|
||||||
/// from `connect`
|
|
||||||
Timeout
|
|
||||||
/// from `send`
|
|
||||||
Closed
|
|
||||||
|
|
||||||
/// Address already in use
|
|
||||||
Eaddrinuse
|
|
||||||
/// Cannot assign requested address
|
|
||||||
Eaddrnotavail
|
|
||||||
/// Address family not supported by protocol family
|
|
||||||
Eafnosupport
|
|
||||||
/// Operation already in progress
|
|
||||||
Ealready
|
|
||||||
/// Software caused connection abort
|
|
||||||
Econnaborted
|
|
||||||
/// Connection refused
|
|
||||||
Econnrefused
|
|
||||||
/// Connection reset by peer
|
|
||||||
Econnreset
|
|
||||||
/// Destination address required
|
|
||||||
Edestaddrreq
|
|
||||||
/// Host is down
|
|
||||||
Ehostdown
|
|
||||||
/// Host is unreachable
|
|
||||||
Ehostunreach
|
|
||||||
/// Operation now in progress
|
|
||||||
Einprogress
|
|
||||||
/// Socket is already connected
|
|
||||||
Eisconn
|
|
||||||
/// Message too long
|
|
||||||
Emsgsize
|
|
||||||
/// Network is down
|
|
||||||
Enetdown
|
|
||||||
/// Network is unreachable
|
|
||||||
Enetunreach
|
|
||||||
/// Package not installed
|
|
||||||
Enopkg
|
|
||||||
/// Bad protocol option
|
|
||||||
Enoprotoopt
|
|
||||||
/// Socket is not connected
|
|
||||||
Enotconn
|
|
||||||
/// Inappropriate device for ioctl
|
|
||||||
Enotty
|
|
||||||
/// Socket operation on non-socket
|
|
||||||
Enotsock
|
|
||||||
/// Protocol error
|
|
||||||
Eproto
|
|
||||||
/// Protocol not supported
|
|
||||||
Eprotonosupport
|
|
||||||
/// Wrong protocol type for socket
|
|
||||||
Eprototype
|
|
||||||
/// Socket type not supported
|
|
||||||
Esocktnosupport
|
|
||||||
/// Connection timed out
|
|
||||||
Etimedout
|
|
||||||
/// Operation would block
|
|
||||||
Ewouldblock
|
|
||||||
/// Invalid exchange
|
|
||||||
Exbadport
|
|
||||||
/// Invalid sequence number
|
|
||||||
Exbadseq
|
|
||||||
/// Permission denied
|
|
||||||
Eacces
|
|
||||||
/// Resource temporarily unavailable
|
|
||||||
Eagain
|
|
||||||
/// Bad file number
|
|
||||||
Ebadf
|
|
||||||
/// Not a data message
|
|
||||||
Ebadmsg
|
|
||||||
/// File busy
|
|
||||||
Ebusy
|
|
||||||
/// Resource deadlock avoided
|
|
||||||
Edeadlk
|
|
||||||
/// Resource deadlock avoided
|
|
||||||
Edeadlock
|
|
||||||
/// Disk quota exceeded
|
|
||||||
Edquot
|
|
||||||
/// File already exists
|
|
||||||
Eexist
|
|
||||||
/// Bad address in system call argument
|
|
||||||
Efault
|
|
||||||
/// File too large
|
|
||||||
Efbig
|
|
||||||
/// Inappropriate file type or format
|
|
||||||
Eftype
|
|
||||||
/// Interrupted system call
|
|
||||||
Eintr
|
|
||||||
/// Invalid argument
|
|
||||||
Einval
|
|
||||||
/// I/O error
|
|
||||||
Eio
|
|
||||||
/// Illegal operation on a directory
|
|
||||||
Eisdir
|
|
||||||
/// Too many levels of symbolic links
|
|
||||||
Eloop
|
|
||||||
/// Too many open files
|
|
||||||
Emfile
|
|
||||||
/// Too many links
|
|
||||||
Emlink
|
|
||||||
/// Multihop attempted
|
|
||||||
Emultihop
|
|
||||||
/// Filename too long
|
|
||||||
Enametoolong
|
|
||||||
/// File table overflow
|
|
||||||
Enfile
|
|
||||||
/// No buffer space available
|
|
||||||
Enobufs
|
|
||||||
/// No such device
|
|
||||||
Enodev
|
|
||||||
/// No locks available
|
|
||||||
Enolck
|
|
||||||
/// Link has been severed
|
|
||||||
Enolink
|
|
||||||
/// No such file or directory
|
|
||||||
Enoent
|
|
||||||
/// Not enough memory
|
|
||||||
Enomem
|
|
||||||
/// No space left on device
|
|
||||||
Enospc
|
|
||||||
/// Out of stream resources or not a stream device
|
|
||||||
Enosr
|
|
||||||
/// Not a stream device
|
|
||||||
Enostr
|
|
||||||
/// Function not implemented
|
|
||||||
Enosys
|
|
||||||
/// Block device required
|
|
||||||
Enotblk
|
|
||||||
/// Not a directory
|
|
||||||
Enotdir
|
|
||||||
/// Operation not supported
|
|
||||||
Enotsup
|
|
||||||
/// No such device or address
|
|
||||||
Enxio
|
|
||||||
/// Operation not supported on socket
|
|
||||||
Eopnotsupp
|
|
||||||
/// Value too large for defined data type
|
|
||||||
Eoverflow
|
|
||||||
/// Not owner
|
|
||||||
Eperm
|
|
||||||
/// Broken pipe
|
|
||||||
Epipe
|
|
||||||
/// Math result unrepresentable
|
|
||||||
Erange
|
|
||||||
/// Read-only filesystem
|
|
||||||
Erofs
|
|
||||||
/// Invalid seek
|
|
||||||
Espipe
|
|
||||||
/// No such process
|
|
||||||
Esrch
|
|
||||||
/// Stale remote file handle
|
|
||||||
Estale
|
|
||||||
/// Text file or pseudo-device busy
|
|
||||||
Etxtbsy
|
|
||||||
/// Cross-device link
|
|
||||||
Exdev
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_string(reason: Reason) -> String {
|
|
||||||
case reason {
|
|
||||||
Closed -> "Connection closed (closed)"
|
|
||||||
Eacces -> "Permission denied (eacces)"
|
|
||||||
Eaddrinuse -> "Address already in use (eaddrinuse)"
|
|
||||||
Eaddrnotavail -> "Cannot assign requested address (eaddrnotavail)"
|
|
||||||
Eafnosupport ->
|
|
||||||
"Address family not supported by protocol family (eafnosupport)"
|
|
||||||
Eagain -> "Resource temporarily unavailable (eagain)"
|
|
||||||
Ealready -> "Operation already in progress (ealready)"
|
|
||||||
Ebadf -> "Bad file number (ebadf)"
|
|
||||||
Ebadmsg -> "Not a data message (ebadmsg)"
|
|
||||||
Ebusy -> "File busy (ebusy)"
|
|
||||||
Econnaborted -> "Software caused connection abort (econnaborted)"
|
|
||||||
Econnrefused -> "Connection refused (econnrefused)"
|
|
||||||
Econnreset -> "Connection reset by peer (econnreset)"
|
|
||||||
Edeadlk -> "Resource deadlock avoided (edeadlk)"
|
|
||||||
Edeadlock -> "Resource deadlock avoided (edeadlock)"
|
|
||||||
Edestaddrreq -> "Destination address required (edestaddrreq)"
|
|
||||||
Edquot -> "Disk quota exceeded (edquot)"
|
|
||||||
Eexist -> "File already exists (eexist)"
|
|
||||||
Efault -> "Bad address in system call argument (efault)"
|
|
||||||
Efbig -> "File too large (efbig)"
|
|
||||||
Eftype -> "Inappropriate file type or format (eftype)"
|
|
||||||
Ehostdown -> "Host is down (ehostdown)"
|
|
||||||
Ehostunreach -> "Host is unreachable (ehostunreach)"
|
|
||||||
Einprogress -> "Operation now in progress (einprogress)"
|
|
||||||
Eintr -> "Interrupted system call (eintr)"
|
|
||||||
Einval -> "Invalid argument (einval)"
|
|
||||||
Eio -> "I/O error (eio)"
|
|
||||||
Eisconn -> "Socket is already connected (eisconn)"
|
|
||||||
Eisdir -> "Illegal operation on a directory (eisdir)"
|
|
||||||
Eloop -> "Too many levels of symbolic links (eloop)"
|
|
||||||
Emfile -> "Too many open files (emfile)"
|
|
||||||
Emlink -> "Too many links (emlink)"
|
|
||||||
Emsgsize -> "Message too long (emsgsize)"
|
|
||||||
Emultihop -> "Multihop attempted (emultihop)"
|
|
||||||
Enametoolong -> "Filename too long (enametoolong)"
|
|
||||||
Enetdown -> "Network is down (enetdown)"
|
|
||||||
Enetunreach -> "Network is unreachable (enetunreach)"
|
|
||||||
Enfile -> "File table overflow (enfile)"
|
|
||||||
Enobufs -> "No buffer space available (enobufs)"
|
|
||||||
Enodev -> "No such device (enodev)"
|
|
||||||
Enoent -> "No such file or directory (enoent)"
|
|
||||||
Enolck -> "No locks available (enolck)"
|
|
||||||
Enolink -> "Link has been severed (enolink)"
|
|
||||||
Enomem -> "Not enough memory (enomem)"
|
|
||||||
Enopkg -> "Package not installed (enopkg)"
|
|
||||||
Enoprotoopt -> "Bad protocol option (enoprotoopt)"
|
|
||||||
Enospc -> "No space left on device (enospc)"
|
|
||||||
Enosr -> "Out of stream resources or not a stream device (enosr)"
|
|
||||||
Enostr -> "Not a stream device (enostr)"
|
|
||||||
Enosys -> "Function not implemented (enosys)"
|
|
||||||
Enotblk -> "Block device required (enotblk)"
|
|
||||||
Enotconn -> "Socket is not connected (enotconn)"
|
|
||||||
Enotdir -> "Not a directory (enotdir)"
|
|
||||||
Enotsock -> "Socket operation on non-socket (enotsock)"
|
|
||||||
Enotsup -> "Operation not supported (enotsup)"
|
|
||||||
Enotty -> "Inappropriate device for ioctl (enotty)"
|
|
||||||
Enxio -> "No such device or address (enxio)"
|
|
||||||
Eopnotsupp -> "Operation not supported on socket (eopnotsupp)"
|
|
||||||
Eoverflow -> "Value too large for defined data type (eoverflow)"
|
|
||||||
Eperm -> "Not owner (eperm)"
|
|
||||||
Epipe -> "Broken pipe (epipe)"
|
|
||||||
Eproto -> "Protocol error (eproto)"
|
|
||||||
Eprotonosupport -> "Protocol not supported (eprotonosupport)"
|
|
||||||
Eprototype -> "Wrong protocol type for socket (eprototype)"
|
|
||||||
Erange -> "Math result unrepresentable (erange)"
|
|
||||||
Erofs -> "Read-only filesystem (erofs)"
|
|
||||||
Esocktnosupport -> "Socket type not supported (esocktnosupport)"
|
|
||||||
Espipe -> "Invalid seek (espipe)"
|
|
||||||
Esrch -> "No such process (esrch)"
|
|
||||||
Estale -> "Stale remote file handle (estale)"
|
|
||||||
Etimedout -> "Connection timed out (etimedout)"
|
|
||||||
Etxtbsy -> "Text file or pseudo-device busy (etxtbsy)"
|
|
||||||
Ewouldblock -> "Operation would block (ewouldblock)"
|
|
||||||
Exbadport -> "Invalid exchange (exbadport)"
|
|
||||||
Exbadseq -> "Invalid sequence number (exbadseq)"
|
|
||||||
Exdev -> "Cross-device link (exdev)"
|
|
||||||
Timeout -> "Operation timed out (timeout)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user