Generate SSD client log transport from typed Jerboa

ober

30ca0ca248b4cd84b2c0ad812387a3b0b305ff92

diff --git a/.build.yml b/.build.yml
index 5a95d86..114accd 100644
--- a/.build.yml
+++ b/.build.yml
@@ -5,7 +5,7 @@ packages:
   - make=4.4.1-r4
 sources:
   # Build dependency: full immutable commit, mirrored in dependencies.lock.json.
-  - "https://git.sr.ht/~lisp/jerboa#df9e55ab7994ee0de757edccf560f4349cc9381d"
+  - "https://git.sr.ht/~lisp/jerboa#344119da5afd49cc97ed78676474b98d0da8fc97"
   # The second source is the build subject selected by the SourceHut submitter.
   - https://git.sr.ht/~lisp/jerboa-android
 tasks:
@@ -14,6 +14,6 @@ tasks:
       test "$(apk info -v chez-scheme)" = chez-scheme-10.3.0-r2
       test "$(apk info -v git)" = git-2.54.0-r0
       test "$(apk info -v make)" = make-4.4.1-r4
-      test "$(git -C ../jerboa rev-parse HEAD)" = df9e55ab7994ee0de757edccf560f4349cc9381d
-      test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = 0061ea8bdc7e8f8f8aef13dee95cfc2489d85ca8
+      test "$(git -C ../jerboa rev-parse HEAD)" = 344119da5afd49cc97ed78676474b98d0da8fc97
+      test "$(git -C ../jerboa rev-parse 'HEAD^{tree}')" = 7869f8316b49971e0846fa995dd2f08f8940aee6
       JERBOA="chez --libdirs .:../jerboa/lib --script" make test
diff --git a/dependencies.lock.json b/dependencies.lock.json
index 7a6780c..8e622d1 100644
--- a/dependencies.lock.json
+++ b/dependencies.lock.json
@@ -11,8 +11,8 @@
   "generator_runtime": {
     "name": "jerboa",
     "repository": "https://git.sr.ht/~lisp/jerboa",
-    "commit": "df9e55ab7994ee0de757edccf560f4349cc9381d",
-    "tree": "0061ea8bdc7e8f8f8aef13dee95cfc2489d85ca8"
+    "commit": "344119da5afd49cc97ed78676474b98d0da8fc97",
+    "tree": "7869f8316b49971e0846fa995dd2f08f8940aee6"
   },
   "assurance_tools": {
     "osv_scanner": {
diff --git a/scripts/verify-supply-chain.sh b/scripts/verify-supply-chain.sh
index f05c7a5..696b73b 100755
--- a/scripts/verify-supply-chain.sh
+++ b/scripts/verify-supply-chain.sh
@@ -3,8 +3,8 @@ set -eu
 
 repo=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd -P)
 lock="$repo/dependencies.lock.json"
-jerboa_commit=df9e55ab7994ee0de757edccf560f4349cc9381d # gitsafe:ignore
-jerboa_tree=0061ea8bdc7e8f8f8aef13dee95cfc2489d85ca8 # gitsafe:ignore
+jerboa_commit=344119da5afd49cc97ed78676474b98d0da8fc97 # gitsafe:ignore
+jerboa_tree=7869f8316b49971e0846fa995dd2f08f8940aee6 # gitsafe:ignore
 gradle_sha=20f1b1176237254a6fc204d8434196fa11a4cfb387567519c61556e8710aed78
 jdk_macos_sha=8fa1eff40bb637a33613b2ccb8b12c70dc3661cc22cf8e784943715769a05336
 jdk_linux_sha=d8afc263758141a66e0e3aafc321e783f7016696f4eaea067d340a269037d331
diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index def03f1..0b35dfb 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -5993,11 +5993,10 @@
                   (activity : MainActivity)
                   (uri : Uri)) : (List SsdPdfChoice)
           (kotlin-member-call findSsdPdfsFromTree))
-        (extern (mainActivitySendClientLogRaw
-                  (activity : MainActivity)
+        (extern (sendClientLogBlockingRaw
                   (payload : JSONObject)
                   (readTimeoutMillis : Int32)) : Unit
-          (kotlin-member-call sendClientLog))
+          (kotlin-call sendClientLogBlocking))
         (extern (throwableLogJsonForExceptionRaw
                   (error : Exception)) : JSONObject
           (kotlin-call throwableLogJsonForThrowable))
@@ -7988,6 +7987,11 @@
                (activity : MainActivity)
                (error : Exception)) : JSONObject
           (throwableLogJsonForExceptionRaw error))
+        (def (mainActivitySendClientLogRaw
+               (activity : MainActivity)
+               (payload : JSONObject)
+               (readTimeoutMillis : Int32)) : Unit
+          (sendClientLogBlockingRaw payload readTimeoutMillis))
         (def (mainActivityLogDetectResultRaw
                (activity : MainActivity)
                (stage : String)
@@ -11379,6 +11383,146 @@
               (json-object-put-string! out "status" text)
               out)))))
 
+    (typed-kotlin-file "com/sfb/ssdreview/ClientLogTransport.kt"
+      (kotlin-imports (java io InputStream)
+                      (java io OutputStream)
+                      (java net URL)
+                      (java net URLConnection)
+                      (javax net ssl HttpsURLConnection)
+                      (org json JSONObject))
+      (typed-library (com sfb ssdreview)
+        (export sendClientLogBlocking)
+        (type Exception)
+        (type HttpsURLConnection)
+        (type InputStream)
+        (type Int)
+        (type Int32)
+        (type JSONObject)
+        (type OutputStream)
+        (type URL)
+        (type URLConnection)
+        (extern (clientLogEndpointValue) : String
+          (kotlin-value CLIENT_LOG_ENDPOINT))
+        (extern (clientLogConnectTimeoutMillisValue) : Int32
+          (kotlin-value CLIENT_LOG_CONNECT_TIMEOUT_MS))
+        (extern (clientLogUrl (value : String)) : URL
+          (kotlin-call URL))
+        (extern (clientLogOpenConnection
+                  (url : URL)) : URLConnection
+          (kotlin-member-call openConnection))
+        (extern (clientLogHttpsConnection
+                  (connection : URLConnection)) : HttpsURLConnection
+          (kotlin-cast HttpsURLConnection))
+        (extern (clientLogJsonToString
+                  (payload : JSONObject)) : String
+          (kotlin-member-call toString))
+        (extern (clientLogConnectionRequestMethodSet
+                  (connection : HttpsURLConnection)
+                  (method : String)) : Unit
+          (kotlin-member-set requestMethod))
+        (extern (clientLogConnectionConnectTimeoutSet
+                  (connection : HttpsURLConnection)
+                  (timeoutMillis : Int32)) : Unit
+          (kotlin-member-set connectTimeout))
+        (extern (clientLogConnectionReadTimeoutSet
+                  (connection : HttpsURLConnection)
+                  (timeoutMillis : Int32)) : Unit
+          (kotlin-member-set readTimeout))
+        (extern (clientLogConnectionDoOutputSet
+                  (connection : HttpsURLConnection)
+                  (enabled : Bool)) : Unit
+          (kotlin-member-set doOutput))
+        (extern (clientLogConnectionSetRequestProperty
+                  (connection : HttpsURLConnection)
+                  (name : String)
+                  (value : String)) : Unit
+          (kotlin-member-call setRequestProperty))
+        (extern (clientLogConnectionSetFixedLengthStreamingMode
+                  (connection : HttpsURLConnection)
+                  (length : Int)) : Unit
+          (kotlin-member-call setFixedLengthStreamingMode))
+        (extern (clientLogConnectionOutputStream
+                  (connection : HttpsURLConnection)) : OutputStream
+          (kotlin-member-get outputStream))
+        (extern (clientLogOutputStreamWrite
+                  (output : OutputStream)
+                  (bytes : Bytes)) : Unit
+          (kotlin-member-call write))
+        (extern (clientLogOutputStreamClose
+                  (output : OutputStream)) : Unit
+          (kotlin-member-call close))
+        (extern (clientLogConnectionResponseCode
+                  (connection : HttpsURLConnection)) : Int32
+          (kotlin-member-get responseCode))
+        (extern (clientLogConnectionInputStream
+                  (connection : HttpsURLConnection)) : InputStream
+          (kotlin-member-get inputStream))
+        (extern (clientLogInputStreamClose
+                  (input : InputStream)) : Unit
+          (kotlin-member-call close))
+        (extern (clientLogConnectionDisconnect
+                  (connection : HttpsURLConnection)) : Unit
+          (kotlin-member-call disconnect))
+        (extern (clientLogIllegalStateException
+                  (message : String)) : Exception
+          (kotlin-call IllegalStateException))
+        (def (sendClientLogBytes
+               (connection : HttpsURLConnection)
+               (bytes : Bytes)) : Unit
+          (let ((output (clientLogConnectionOutputStream connection)))
+            (try-finally
+              (clientLogOutputStreamWrite output bytes)
+              (clientLogOutputStreamClose output))))
+        (def (closeClientLogResponse
+               (connection : HttpsURLConnection)) : Unit
+          (clientLogInputStreamClose
+            (clientLogConnectionInputStream connection)))
+        (def (checkClientLogResponse
+               (connection : HttpsURLConnection)) : Unit
+          (let ((code (clientLogConnectionResponseCode connection)))
+            (if (httpStatusFailed code)
+              (throw
+                (clientLogIllegalStateException
+                  (clientLogHttpStatusMessage code))
+                Unit)
+              (begin))))
+        (def (configureClientLogConnection
+               (connection : HttpsURLConnection)
+               (bytes : Bytes)
+               (readTimeoutMillis : Int32)) : Unit
+          (begin
+            (clientLogConnectionRequestMethodSet connection "POST")
+            (clientLogConnectionConnectTimeoutSet
+              connection
+              (clientLogConnectTimeoutMillisValue))
+            (clientLogConnectionReadTimeoutSet connection readTimeoutMillis)
+            (clientLogConnectionDoOutputSet connection #t)
+            (clientLogConnectionSetRequestProperty
+              connection
+              "Content-Type"
+              "application/json; charset=utf-8")
+            (clientLogConnectionSetFixedLengthStreamingMode
+              connection
+              (byteArraySizeBytes bytes))))
+        (def (sendClientLogBlocking
+               (payload : JSONObject)
+               (readTimeoutMillis : Int32)) : Unit
+          (let ((bytes (textUtf8Bytes (clientLogJsonToString payload))))
+            (let ((connection
+                    (clientLogHttpsConnection
+                      (clientLogOpenConnection
+                        (clientLogUrl (clientLogEndpointValue))))))
+              (try-finally
+                (begin
+                  (configureClientLogConnection
+                    connection
+                    bytes
+                    readTimeoutMillis)
+                  (sendClientLogBytes connection bytes)
+                  (checkClientLogResponse connection)
+                  (closeClientLogResponse connection))
+                (clientLogConnectionDisconnect connection)))))))
+
     (typed-kotlin-file "com/sfb/ssdreview/ClientCrash.kt"
       (kotlin-imports (java lang Thread)
                       (java lang Thread UncaughtExceptionHandler))
@@ -11442,11 +11586,10 @@
                   (event : String)
                   (fields : JSONObject)) : JSONObject
           (kotlin-call mainActivityClientLogPayloadRaw))
-        (extern (mainActivityCrashSendClientLogRaw
-                  (activity : MainActivity)
+        (extern (sendClientLogBlockingRawForCrash
                   (payload : JSONObject)
                   (readTimeoutMillis : Int32)) : Unit
-          (kotlin-member-call sendClientLog))
+          (kotlin-call sendClientLogBlocking))
         (extern (mainActivityThrowableLogRaw
                   (error : Throwable)) : JSONObject
           (kotlin-call throwableLogJsonForThrowable))
@@ -11465,6 +11608,11 @@
             (begin
               (threadStartCrashRaw sender)
               sender)))
+        (def (mainActivityCrashSendClientLogRaw
+               (activity : MainActivity)
+               (payload : JSONObject)
+               (readTimeoutMillis : Int32)) : Unit
+          (sendClientLogBlockingRawForCrash payload readTimeoutMillis))
         (def (crashPayloadFor
                (activity : MainActivity)
                (crashingThread : Thread)
@@ -12681,26 +12829,6 @@
        "            }"
        "    }"
 	       ""
-	       "    internal fun sendClientLog(payload: JSONObject, readTimeoutMillis: Int) {"
-       "        val bytes = textUtf8Bytes(payload.toString())"
-       "        val connection = (URL(CLIENT_LOG_ENDPOINT).openConnection() as HttpsURLConnection).apply {"
-       "            requestMethod = \"POST\""
-       "            connectTimeout = CLIENT_LOG_CONNECT_TIMEOUT_MS"
-       "            readTimeout = readTimeoutMillis"
-       "            doOutput = true"
-       "            setRequestProperty(\"Content-Type\", \"application/json; charset=utf-8\")"
-       "            setFixedLengthStreamingMode(bytes.size)"
-       "        }"
-       "        try {"
-       "            connection.outputStream.use { it.write(bytes) }"
-       "            val code = connection.responseCode"
-       "            if (httpStatusFailed(code)) throw IllegalStateException(clientLogHttpStatusMessage(code))"
-       "            connection.inputStream.close()"
-       "        } finally {"
-       "            connection.disconnect()"
-       "        }"
-       "    }"
-	       ""
 	       "}"
        ))
     (typed-kotlin-file "com/sfb/ssdreview/MainActivityConstants.kt"