mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 10:29:58 +02:00
feat(diagnostics): harden ingestion and delivery
This commit is contained in:
@@ -13,8 +13,16 @@ private class JvmPendingCrashStore(
|
||||
|
||||
@Synchronized
|
||||
override fun write(report: CrashReport) {
|
||||
if (!isValidDiagnosticId(report.id)) return
|
||||
directory.mkdirs()
|
||||
File(directory, "${report.id}.crash").writeText(CrashReportCodec.encode(report), StandardCharsets.UTF_8)
|
||||
val target = File(directory, "${report.id}.crash")
|
||||
val temporary = File(directory, ".${report.id}.tmp")
|
||||
val payload = CrashReportCodec.encode(report)
|
||||
temporary.writeText(payload, StandardCharsets.UTF_8)
|
||||
if (!temporary.renameTo(target)) {
|
||||
target.writeText(payload, StandardCharsets.UTF_8)
|
||||
temporary.delete()
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
@@ -31,6 +39,34 @@ private class JvmPendingCrashStore(
|
||||
|
||||
@Synchronized
|
||||
override fun delete(id: String) {
|
||||
if (!isValidDiagnosticId(id)) return
|
||||
File(directory, "$id.crash").delete()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun prune(olderThanTimestampMillis: Long, maxCount: Int) {
|
||||
require(maxCount > 0) { "maxCount must be positive" }
|
||||
if (!directory.isDirectory) return
|
||||
directory.listFiles { file -> file.isFile && file.name.endsWith(".tmp") }
|
||||
.orEmpty()
|
||||
.forEach(File::delete)
|
||||
val reports = directory
|
||||
.listFiles { file -> file.isFile && file.name.endsWith(".crash") }
|
||||
.orEmpty()
|
||||
.mapNotNull { file ->
|
||||
val report = runCatching {
|
||||
CrashReportCodec.decode(file.readText(StandardCharsets.UTF_8))
|
||||
}.getOrNull()
|
||||
if (report == null) {
|
||||
file.delete()
|
||||
null
|
||||
} else {
|
||||
file to report
|
||||
}
|
||||
}
|
||||
.sortedByDescending { (_, report) -> report.timestampMillis }
|
||||
reports.forEachIndexed { index, (file, report) ->
|
||||
if (index >= maxCount || report.timestampMillis < olderThanTimestampMillis) file.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.vnidrop.app.diagnostics
|
||||
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStreamReader
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URI
|
||||
import java.nio.charset.StandardCharsets
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
actual suspend fun platformHttpPost(
|
||||
url: String,
|
||||
headers: Map<String, String>,
|
||||
bodyUtf8: String,
|
||||
): PlatformHttpResponse = withContext(Dispatchers.IO) {
|
||||
val connection = (URI(url).toURL().openConnection() as HttpURLConnection).apply {
|
||||
requestMethod = "POST"
|
||||
doOutput = true
|
||||
connectTimeout = 15_000
|
||||
readTimeout = 30_000
|
||||
setRequestProperty("Content-Type", "application/json; charset=utf-8")
|
||||
headers.forEach { (key, value) -> setRequestProperty(key, value) }
|
||||
}
|
||||
try {
|
||||
connection.outputStream.use { output ->
|
||||
output.write(bodyUtf8.toByteArray(StandardCharsets.UTF_8))
|
||||
}
|
||||
val code = connection.responseCode
|
||||
val stream = if (code in 200..299) connection.inputStream else connection.errorStream
|
||||
val body = stream?.use { input ->
|
||||
BufferedReader(InputStreamReader(input, StandardCharsets.UTF_8)).readText()
|
||||
}.orEmpty()
|
||||
PlatformHttpResponse(code, body)
|
||||
} finally {
|
||||
connection.disconnect()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user