aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/world/net/udp.jvm.lux
blob: da4f8f05d3a66fb2c4290639e580cd3879d9021b (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
(.module:
  lux
  (lux (control monad
                ["ex" exception #+ exception:])
       (concurrency ["P" promise]
                    ["T" task])
       (data ["e" error]
             [maybe]
             (coll [array]))
       (type abstract)
       (world [blob #+ Blob])
       [io]
       [host])
  [//])

(host.import java/lang/AutoCloseable
  (close [] #io #try void))

(host.import java/io/Flushable
  (flush [] #io #try void))

(host.import java/net/InetAddress
  (#static getAllByName [String] #io #try (Array InetAddress))
  (getHostAddress [] String))

(host.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))

(host.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})
  address)

(exception: #export (multiple-candidate-addresses {address //.Address})
  address)

(def: (resolve address)
  (-> //.Address (io.IO (e.Error InetAddress)))
  (do (e.ErrorT io.Monad<IO>)
    [addresses (InetAddress::getAllByName [address])]
    (: (io.IO (e.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))))))

(abstract: #export UDP {}
  {#socket DatagramSocket}
  
  (def: #export (read data offset length self)
    (-> Blob Nat Nat UDP (T.Task [Nat //.Address //.Port]))
    (let [(^open) (@representation self)
          packet (DatagramPacket::new|receive [data (.int offset) (.int length)])]
      (P.future
       (do (e.ErrorT io.Monad<IO>)
         [_ (DatagramSocket::receive [packet] socket)
          #let [bytes-read (.nat (DatagramPacket::getLength [] packet))]]
         (wrap [bytes-read
                (|> packet (DatagramPacket::getAddress []) (InetAddress::getHostAddress []))
                (.nat (DatagramPacket::getPort [] packet))])))))
  
  (def: #export (write address port data offset length self)
    (-> //.Address //.Port Blob Nat Nat UDP (T.Task Top))
    (P.future
     (do (e.ErrorT io.Monad<IO>)
       [address (resolve address)
        #let [(^open) (@representation self)]]
       (DatagramSocket::send (DatagramPacket::new|send [data (.int offset) (.int length) address (.int port)])
                             socket))))

  (def: #export (close self)
    (-> UDP (T.Task Top))
    (let [(^open) (@representation self)]
      (P.future
       (AutoCloseable::close [] socket))))

  (def: #export (client _)
    (-> Top (T.Task UDP))
    (P.future
     (do (e.ErrorT io.Monad<IO>)
       [socket (DatagramSocket::new|client [])]
       (wrap (@abstraction (#socket socket))))))

  (def: #export (server port)
    (-> //.Port (T.Task UDP))
    (P.future
     (do (e.ErrorT io.Monad<IO>)
       [socket (DatagramSocket::new|server [(.int port)])]
       (wrap (@abstraction (#socket socket))))))
  )