aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/world/net/udp.lux
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib/source/lux/world/net/udp.lux')
-rw-r--r--stdlib/source/lux/world/net/udp.lux124
1 files changed, 124 insertions, 0 deletions
diff --git a/stdlib/source/lux/world/net/udp.lux b/stdlib/source/lux/world/net/udp.lux
new file mode 100644
index 000000000..df9244186
--- /dev/null
+++ b/stdlib/source/lux/world/net/udp.lux
@@ -0,0 +1,124 @@
+(.module:
+ [lux #*
+ [host (#+ import:)]
+ ["@" target]
+ [abstract
+ monad]
+ [control
+ ["ex" exception (#+ exception:)]
+ ["." io (#+ IO)]
+ [concurrency
+ ["." promise (#+ Promise)]]
+ [security
+ ["!" capability]]]
+ [data
+ ["." error (#+ Error)]
+ ["." maybe]
+ [collection
+ ["." array]]]
+ [world
+ ["." binary (#+ Binary)]]]
+ ["." // (#+ Location Can-Read Can-Write Can-Close)])
+
+(exception: #export (cannot-resolve-address {address //.Address})
+ (ex.report ["Address" address]))
+
+(exception: #export (multiple-candidate-addresses {address //.Address})
+ (ex.report ["Address" address]))
+
+(signature: #export (UDP !)
+ (: (Can-Read ! [Nat Location Binary])
+ read)
+
+ (: (Can-Write ! [Location Binary])
+ write)
+
+ (: (Can-Close !)
+ close))
+
+(def: #export (async udp)
+ (-> (UDP IO) (UDP Promise))
+ (`` (structure (~~ (template [<name> <forge>]
+ [(def: <name> (<forge> (|>> (!.use (:: udp <name>)) promise.future)))]
+
+ [read //.can-read]
+ [write //.can-write]
+ [close //.can-close])))))
+
+(with-expansions [<for-jvm> (as-is (import: java/lang/AutoCloseable
+ (close [] #io #try void))
+
+ (import: java/io/Flushable
+ (flush [] #io #try void))
+
+ (import: java/net/InetAddress
+ (#static getAllByName [String] #io #try [InetAddress])
+ (getHostAddress [] String))
+
+ (import: java/net/DatagramPacket
+ (new #as new|send [[byte] int int InetAddress int])
+ (new #as new|receive [[byte] int int])
+ (getAddress [] InetAddress)
+ (getPort [] int)
+ (getLength [] int))
+
+ (import: java/net/DatagramSocket
+ (new #as new|client [] #io #try)
+ (new #as new|server [int] #io #try)
+ (receive [DatagramPacket] #io #try void)
+ (send [DatagramPacket] #io #try void))
+
+ (def: (resolve address)
+ (-> //.Address (IO (Error InetAddress)))
+ (do (error.with io.monad)
+ [addresses (InetAddress::getAllByName address)]
+ (: (IO (Error InetAddress))
+ (case (array.size addresses)
+ 0 (io.io (ex.throw cannot-resolve-address address))
+ 1 (wrap (maybe.assume (array.read 0 addresses)))
+ _ (io.io (ex.throw multiple-candidate-addresses address))))))
+
+ (def: (udp socket)
+ (-> DatagramSocket (UDP IO))
+ (structure (def: read
+ (//.can-read
+ (function (read size)
+ (let [data (binary.create size)
+ packet (DatagramPacket::new|receive data +0 (.int size))]
+ (do (error.with io.monad)
+ [_ (DatagramSocket::receive packet socket)
+ #let [bytes-read (.nat (DatagramPacket::getLength packet))]]
+ (wrap [bytes-read
+ {#//.address (|> packet DatagramPacket::getAddress InetAddress::getHostAddress)
+ #//.port (.nat (DatagramPacket::getPort packet))}
+ data]))))))
+
+ (def: write
+ (//.can-write
+ (function (write [location data])
+ (do (error.with io.monad)
+ [address (resolve (get@ #//.address location))]
+ (DatagramSocket::send (DatagramPacket::new|send data +0 (.int (binary.size data)) address (.int (get@ #//.port location)))
+ socket)))))
+
+ (def: close
+ (//.can-close
+ (function (close _)
+ (AutoCloseable::close socket))))))
+
+ (def: #export client
+ (IO (Error (UDP IO)))
+ (|> (DatagramSocket::new|client)
+ (:: (error.with io.monad) map ..udp)))
+
+ (def: #export server
+ (-> //.Port (IO (Error (UDP IO))))
+ (|>> .int
+ DatagramSocket::new|server
+ (:: (error.with io.monad) map ..udp)))
+ )]
+ (`` (for {(~~ (static @.old))
+ (as-is <for-jvm>)
+
+ (~~ (static @.jvm))
+ (as-is <for-jvm>)})))