-
-
Notifications
You must be signed in to change notification settings - Fork 468
Expand file tree
/
Copy pathDistributionHttpClient.kt
More file actions
114 lines (98 loc) · 3.79 KB
/
DistributionHttpClient.kt
File metadata and controls
114 lines (98 loc) · 3.79 KB
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
package io.sentry.android.distribution
import io.sentry.SentryLevel
import io.sentry.SentryOptions
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL
import java.net.URLEncoder
import javax.net.ssl.HttpsURLConnection
/** HTTP client for making requests to Sentry's distribution API. */
internal class DistributionHttpClient(private val options: SentryOptions) {
/** Represents the result of an HTTP request. */
data class HttpResponse(
val statusCode: Int,
val body: String,
val isSuccessful: Boolean = statusCode in 200..299,
)
/** Parameters for checking updates. */
data class UpdateCheckParams(
val appId: String,
val platform: String = "android",
val versionCode: Long,
val versionName: String,
)
/**
* Makes a GET request to the distribution API to check for updates.
*
* @param params Update check parameters
* @return HttpResponse containing the response details
*/
fun checkForUpdates(params: UpdateCheckParams): HttpResponse {
val distributionOptions = options.distribution
val orgSlug = distributionOptions.orgSlug
val projectSlug = distributionOptions.projectSlug
val authToken = distributionOptions.orgAuthToken
val baseUrl = distributionOptions.sentryBaseUrl
if (orgSlug.isNullOrEmpty() || projectSlug.isNullOrEmpty() || authToken.isNullOrEmpty()) {
throw IllegalStateException(
"Missing required distribution configuration: orgSlug, projectSlug, or orgAuthToken"
)
}
val urlString = buildString {
append(baseUrl.trimEnd('/'))
append(
"/api/0/projects/${URLEncoder.encode(orgSlug, "UTF-8")}/${URLEncoder.encode(projectSlug, "UTF-8")}/preprodartifacts/check-for-updates/"
)
append("?app_id=${URLEncoder.encode(params.appId, "UTF-8")}")
append("&platform=${URLEncoder.encode(params.platform, "UTF-8")}")
append("&build_number=${URLEncoder.encode(params.versionCode.toString(), "UTF-8")}")
append("&build_version=${URLEncoder.encode(params.versionName, "UTF-8")}")
}
val url = URL(urlString)
return try {
makeRequest(url, authToken)
} catch (e: IOException) {
options.logger.log(SentryLevel.ERROR, e, "Network error while checking for updates")
throw e
}
}
private fun makeRequest(url: URL, authToken: String): HttpResponse {
val connection = url.openConnection() as HttpURLConnection
try {
connection.requestMethod = "GET"
connection.setRequestProperty("Authorization", "Bearer $authToken")
connection.setRequestProperty("Accept", "application/json")
connection.setRequestProperty(
"User-Agent",
options.sentryClientName ?: throw IllegalStateException("sentryClientName must be set"),
)
connection.connectTimeout = options.connectionTimeoutMillis
connection.readTimeout = options.readTimeoutMillis
if (connection is HttpsURLConnection && options.sslSocketFactory != null) {
connection.sslSocketFactory = options.sslSocketFactory
}
val responseCode = connection.responseCode
val responseBody = readResponse(connection)
options.logger.log(
SentryLevel.DEBUG,
"Distribution API request completed with status: $responseCode",
)
return HttpResponse(responseCode, responseBody)
} finally {
connection.disconnect()
}
}
private fun readResponse(connection: HttpURLConnection): String {
val inputStream =
if (connection.responseCode in 200..299) {
connection.inputStream
} else {
connection.errorStream ?: connection.inputStream
}
return inputStream?.use { stream ->
BufferedReader(InputStreamReader(stream, "UTF-8")).use { reader -> reader.readText() }
} ?: ""
}
}