aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/world/net/udp.jvm.lux
blob: 842f1c969e6f6734ef840c2de21de7342e66ad4c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
(.module:
  [lux #*
   [control
    monad
    ["ex" exception (#+ exception:)]
    [security
     ["." taint (#+ Dirty taint)]]]
   [concurrency
    ["." promise (#+ Promise)]
    [task (#+ Task)]]
   [data
    ["." error (#+ Error)]
    ["." maybe]
    [collection
     ["." array]]]
   [world
    ["." binary (#+ Binary)]]
   ["." io (#+ IO)]
   [host (#+ import:)]
   [platform
    [compiler
     ["." host]]]]
  ["." // (#+ Location)])

(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 (Array InetAddress))
  (getHostAddress [] String))

(import: java/net/DatagramPacket
  (new #as new|send [(Array byte) int int InetAddress int])
  (new #as new|receive [(Array 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))

############################################################
############################################################
############################################################

(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 !)
  (: (-> Nat (! (Error [Nat Location (Dirty Binary)])))
     read)

  (: (-> Location Binary (! (Error Any)))
     write)

  (: (-> Any (! (Error Any)))
     close))

(def: #export (async udp)
  (-> (UDP IO) (UDP Promise))
  (`` (structure (def: read (|>> (:: udp read) promise.future))
                 
                 (def: (write location data)
                   (promise.future (:: udp write location data)))
                 
                 (def: close (|>> (:: udp close) promise.future)))))

(`` (for {(~~ (static host.jvm))
          (as-is (def: (resolve address)
                   (-> //.Address (IO (Error InetAddress)))
                   (do io.Monad<Process>
                     [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 size)
                                (let [data (binary.create size)
                                      packet (DatagramPacket::new|receive data +0 (.int size))]
                                  (do io.Monad<Process>
                                    [_ (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))}
                                           (taint data)]))))

                              (def: (write location data)
                                (do io.Monad<Process>
                                  [address (resolve (get@ #//.address location))]
                                  (DatagramSocket::send (DatagramPacket::new|send data +0 (.int (binary.size data)) address (.int (get@ #//.port location)))
                                                        socket)))

                              (def: (close _)
                                (AutoCloseable::close socket))))

                 (def: #export client
                   (IO (Error (UDP IO)))
                   (|> (DatagramSocket::new|client)
                       (:: io.Monad<Process> map udp)))

                 (def: #export server
                   (-> //.Port (IO (Error (UDP IO))))
                   (|>> .int
                        DatagramSocket::new|server
                        (:: io.Monad<Process> map udp)))
                 )}))