aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/program/aedifex/repository.lux
blob: e5dc55d2c905f3fc43bff6ffcdc315f3061de601 (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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
(.module:
  [lux #*
   ["." host (#+ import:)]
   [abstract
    [monad (#+ do)]]
   [control
    ["." io (#+ IO)]
    ["." try (#+ Try)]
    ["." exception (#+ exception:)]
    [concurrency
     ["." promise (#+ Promise)]
     ["." stm]]]
   [data
    ["." binary (#+ Binary)]
    ["." text
     ["%" format (#+ format)]
     ["." encoding]]
    [number
     ["n" nat]]]
   [world
    [net (#+ URL)
     ["." uri]]]]
  ["." // #_
   ["#." artifact (#+ Artifact)
    ["#/." extension (#+ Extension)]]])

(type: #export Address
  URL)

(type: #export User
  Text)

(type: #export Password
  Text)

(type: #export Identity
  {#user User
   #password Password})

(signature: #export (Repository !)
  (: (-> Artifact Extension (! (Try Binary)))
     download)
  (: (-> Identity Artifact Extension Binary (! (Try Any)))
     upload))

(def: #export (async repository)
  (-> (Repository IO) (Repository Promise))
  (structure
   (def: (download artifact extension)
     (promise.future (:: repository download artifact extension)))

   (def: (upload identity artifact extension content)
     (promise.future (:: repository upload identity artifact extension content)))
   ))

(signature: #export (Simulation s)
  (: (-> Artifact Extension s
         (Try [s Binary]))
     on-download)
  (: (-> Identity Artifact Extension Binary s
         (Try s))
     on-upload))

(def: #export (mock simulation init)
  (All [s] (-> (Simulation s) s (Repository Promise)))
  (let [state (stm.var init)]
    (structure
     (def: (download artifact extension)
       (stm.commit
        (do {! stm.monad}
          [|state| (stm.read state)]
          (case (:: simulation on-download artifact extension |state|)
            (#try.Success [|state| output])
            (do !
              [_ (stm.write |state| state)]
              (wrap (#try.Success output)))
            
            (#try.Failure error)
            (wrap (#try.Failure error))))))

     (def: (upload identity artifact extension content)
       (stm.commit
        (do {! stm.monad}
          [|state| (stm.read state)]
          (case (:: simulation on-upload identity artifact extension content |state|)
            (#try.Success |state|)
            (do !
              [_ (stm.write |state| state)]
              (wrap (#try.Success [])))
            
            (#try.Failure error)
            (wrap (#try.Failure error))))))
     )))

(import: java/lang/String)

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

(import: java/io/OutputStream
  ["#::."
   (flush [] #io #try void)
   (write [[byte]] #io #try void)])

(import: java/net/URLConnection
  ["#::."
   (setDoOutput [boolean] #io #try void)
   (setRequestProperty [java/lang/String java/lang/String] #io #try void)
   (getOutputStream [] #io #try java/io/OutputStream)])

(import: java/net/HttpURLConnection
  ["#::."
   (setRequestMethod [java/lang/String] #io #try void)
   (getResponseCode [] #io #try int)])

(import: java/net/URL
  ["#::."
   (new [java/lang/String])
   (openConnection [] #io #try java/net/URLConnection)
   (openStream [] #io #try java/io/InputStream)])

(import: java/util/Base64$Encoder
  ["#::."
   (encodeToString [[byte]] java/lang/String)])

(import: java/util/Base64
  ["#::."
   (#static getEncoder [] java/util/Base64$Encoder)])

(import: java/io/InputStream)

(import: java/io/BufferedInputStream
  ["#::."
   (new [java/io/InputStream])
   (read [[byte] int int] #io #try int)])

(exception: #export (deployment-failure {code Int})
  (exception.report
   ["Code" (%.int code)]))

(def: (basic-auth user password)
  (-> User Password Text)
  (format "Basic " (java/util/Base64$Encoder::encodeToString (encoding.to-utf8 (format user ":" password))
                                                             (java/util/Base64::getEncoder))))

(def: (url address artifact extension)
  (-> Address Artifact Extension URL)
  (format address uri.separator (//artifact.uri artifact) extension))

(def: buffer-size
  (n.* 512 1,024))

(structure: #export (remote address)
  (All [s] (-> Address (Repository IO)))

  (def: (download artifact extension)
    (let [url (..url address artifact extension)]
      (do {! (try.with io.monad)}
        [input (|> (java/net/URL::new url)
                   java/net/URL::openStream
                   (:: ! map (|>> java/io/BufferedInputStream::new)))
         #let [buffer (binary.create ..buffer-size)]]
        (loop [output (:: binary.monoid identity)]
          (do !
            [bytes-read (java/io/BufferedInputStream::read buffer +0 (.int ..buffer-size) input)]
            (case bytes-read
              -1 (do !
                   [_ (java/lang/AutoCloseable::close input)]
                   (wrap output))
              _ (if (n.= ..buffer-size bytes-read)
                  (recur (:: binary.monoid compose output buffer))
                  (do !
                    [chunk (:: io.monad wrap (binary.slice 0 (.nat bytes-read) buffer))]
                    (recur (:: binary.monoid compose output chunk))))))))))

  (def: (upload [user password] artifact extension content)
    (do (try.with io.monad)
      [connection (|> (..url address artifact extension)
                      java/net/URL::new
                      java/net/URL::openConnection)
       #let [connection (:coerce java/net/HttpURLConnection connection)]
       _ (java/net/HttpURLConnection::setRequestMethod "PUT" connection)
       _ (java/net/URLConnection::setDoOutput true connection)
       _ (java/net/URLConnection::setRequestProperty "Authorization" (..basic-auth user password) connection)
       stream (java/net/URLConnection::getOutputStream connection)
       _ (java/io/OutputStream::write content stream)
       _ (java/io/OutputStream::flush stream)
       _ (java/lang/AutoCloseable::close stream)
       code (java/net/HttpURLConnection::getResponseCode connection)]
      (case code
        +200 (wrap [])
        _ (:: io.monad wrap (exception.throw ..deployment-failure [code])))))
  )