aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/world/net/udp.jvm.lux
blob: 9e61e55eb8b994bc9776c9b372db2f35ae212a9a (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
(.module:
  [lux #*
   [control
    monad
    ["ex" exception (#+ exception:)]]
   [concurrency
    ["P" promise]
    ["T" task]]
   [data
    ["e" error]
    [maybe]
    [collection [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 Any))
    (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 Any))
    (let [(^open) (:representation self)]
      (P.future
       (AutoCloseable::close [] socket))))

  (def: #export (client _)
    (-> Any (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))))))
  )