Skip to content

Commit 1f4c593

Browse files
authored
Merge pull request #30 from Automattic/replace-volley-with-httpurlconnection
Replace Volley with HttpURLConnection
2 parents d7fc023 + c57ff74 commit 1f4c593

File tree

7 files changed

+237
-124
lines changed

7 files changed

+237
-124
lines changed

encryptedlogging/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,11 @@ dependencies {
7272
ksp(libs.androidx.room.compiler)
7373
implementation(libs.kotlinx.coroutines.android)
7474
implementation(libs.kotlinx.coroutines.core)
75-
implementation(libs.volley)
7675
testImplementation(libs.androidx.test.core.ktx)
7776
testImplementation(libs.assertj.core)
7877
testImplementation(libs.junit)
7978
testImplementation(libs.kotlinx.coroutines.test)
79+
testImplementation(libs.mockwebserver)
8080
testImplementation(libs.robolectric)
8181
androidTestImplementation(libs.assertj.core)
8282
androidTestImplementation(libs.androidx.test.ext.junit)

encryptedlogging/src/main/kotlin/com/automattic/encryptedlogging/AutomatticEncryptedLogging.kt

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@ package com.automattic.encryptedlogging
22

33
import android.content.Context
44
import android.util.Base64
5-
import com.android.volley.RequestQueue
6-
import com.android.volley.toolbox.BasicNetwork
7-
import com.android.volley.toolbox.DiskBasedCache
8-
import com.android.volley.toolbox.HurlStack
95
import com.automattic.encryptedlogging.model.encryptedlogging.EncryptedLoggingKey
106
import com.automattic.encryptedlogging.model.encryptedlogging.LogEncrypter
7+
import com.automattic.encryptedlogging.network.EncryptedLogHttpClient
118
import com.automattic.encryptedlogging.network.rest.wpcom.encryptedlog.EncryptedLogRestClient
129
import com.automattic.encryptedlogging.persistence.EncryptedLogDatabase
1310
import com.automattic.encryptedlogging.store.EncryptedLogStore
@@ -23,22 +20,11 @@ internal class AutomatticEncryptedLogging(
2320
encryptedLoggingKey: String,
2421
clientSecret: String,
2522
) : EncryptedLogging {
26-
private companion object {
27-
private const val MAX_CACHE_SIZE_IN_BYTES = 1024 * 1024 * 10
28-
}
29-
3023
private val encryptedLogStore: EncryptedLogStore
3124

3225
init {
33-
val cache = DiskBasedCache(
34-
File.createTempFile("tempcache", null),
35-
MAX_CACHE_SIZE_IN_BYTES
36-
)
37-
val network = BasicNetwork(HurlStack())
38-
val requestQueue = RequestQueue(cache, network).apply {
39-
start()
40-
}
41-
val encryptedLogRestClient = EncryptedLogRestClient(requestQueue, clientSecret)
26+
val httpClient = EncryptedLogHttpClient(clientSecret)
27+
val encryptedLogRestClient = EncryptedLogRestClient(httpClient)
4228
val database = EncryptedLogDatabase.getInstance(context)
4329
val logEncrypter = LogEncrypter(
4430
EncryptedLoggingKey(Key.fromBytes(Base64.decode(encryptedLoggingKey, Base64.DEFAULT)))
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.automattic.encryptedlogging.network
2+
3+
import java.io.IOException
4+
import java.net.HttpURLConnection
5+
import java.net.URL
6+
7+
private const val AUTHORIZATION_HEADER = "Authorization"
8+
private const val CONTENT_TYPE_HEADER = "Content-Type"
9+
private const val CONTENT_TYPE_JSON = "application/json"
10+
private const val UUID_HEADER = "log-uuid"
11+
private const val DEFAULT_UPLOAD_URL = "https://public-api.wordpress.com/rest/v1.1/encrypted-logging/"
12+
13+
internal class EncryptedLogHttpClient(
14+
private val clientSecret: String,
15+
private val uploadUrl: String = DEFAULT_UPLOAD_URL
16+
) {
17+
@Throws(IOException::class)
18+
fun uploadLog(logUuid: String, contents: String): HttpResponse {
19+
val url = URL(uploadUrl)
20+
val connection = (url.openConnection() as HttpURLConnection).apply {
21+
requestMethod = "POST"
22+
doOutput = true
23+
setRequestProperty(CONTENT_TYPE_HEADER, CONTENT_TYPE_JSON)
24+
setRequestProperty(AUTHORIZATION_HEADER, clientSecret)
25+
setRequestProperty(UUID_HEADER, logUuid)
26+
}
27+
28+
try {
29+
connection.outputStream.use { outputStream ->
30+
outputStream.write(contents.toByteArray())
31+
outputStream.flush()
32+
}
33+
34+
val statusCode = connection.responseCode
35+
val responseBody = if (statusCode in 200..299) {
36+
connection.inputStream.bufferedReader().use { it.readText() }
37+
} else {
38+
connection.errorStream?.bufferedReader()?.use { it.readText() } ?: ""
39+
}
40+
41+
return HttpResponse(statusCode, responseBody)
42+
} finally {
43+
connection.disconnect()
44+
}
45+
}
46+
}
47+
48+
internal data class HttpResponse(
49+
val statusCode: Int,
50+
val body: String
51+
)

encryptedlogging/src/main/kotlin/com/automattic/encryptedlogging/network/EncryptedLogUploadRequest.kt

Lines changed: 0 additions & 56 deletions
This file was deleted.

encryptedlogging/src/main/kotlin/com/automattic/encryptedlogging/network/rest/wpcom/encryptedlog/EncryptedLogRestClient.kt

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,52 @@
11
package com.automattic.encryptedlogging.network.rest.wpcom.encryptedlog
22

33
import android.util.Log
4-
import com.android.volley.NoConnectionError
5-
import com.android.volley.RequestQueue
6-
import com.android.volley.VolleyError
7-
import kotlinx.coroutines.suspendCancellableCoroutine
4+
import com.automattic.encryptedlogging.network.EncryptedLogHttpClient
5+
import com.automattic.encryptedlogging.store.UploadEncryptedLogError
6+
import kotlinx.coroutines.Dispatchers
7+
import kotlinx.coroutines.withContext
88
import org.json.JSONException
99
import org.json.JSONObject
10-
import com.automattic.encryptedlogging.network.EncryptedLogUploadRequest
11-
import com.automattic.encryptedlogging.store.UploadEncryptedLogError
12-
import kotlin.coroutines.resume
10+
import java.io.IOException
1311

1412
private const val INVALID_REQUEST = "invalid-request"
1513
private const val TOO_MANY_REQUESTS = "too_many_requests"
1614

1715
internal class EncryptedLogRestClient(
18-
private val requestQueue: RequestQueue,
19-
private val clientSecret: String,
16+
private val httpClient: EncryptedLogHttpClient,
2017
) {
2118
suspend fun uploadLog(logUuid: String, contents: String): UploadEncryptedLogResult {
22-
return suspendCancellableCoroutine { cont ->
23-
val request = EncryptedLogUploadRequest(logUuid, contents, clientSecret, {
24-
cont.resume(UploadEncryptedLogResult.LogUploaded)
25-
}, { error ->
26-
cont.resume(UploadEncryptedLogResult.LogUploadFailed(mapError(error)))
27-
})
28-
cont.invokeOnCancellation { request.cancel() }
29-
requestQueue.add(request)
19+
return withContext(Dispatchers.IO) {
20+
try {
21+
val response = httpClient.uploadLog(logUuid, contents)
22+
if (response.statusCode in 200..299) {
23+
UploadEncryptedLogResult.LogUploaded
24+
} else {
25+
UploadEncryptedLogResult.LogUploadFailed(mapError(response.statusCode, response.body))
26+
}
27+
} catch (e: IOException) {
28+
UploadEncryptedLogResult.LogUploadFailed(UploadEncryptedLogError.NoConnection)
29+
}
3030
}
3131
}
3232

33-
/**
34-
* {
35-
* "error":"too_many_requests",
36-
* "message":"You're sending too many messages. Please slow down."
37-
* }
38-
* {
39-
* "error":"invalid-request",
40-
* "message":"Invalid UUID: uuids must only contain letters, numbers, dashes, and curly brackets"
41-
* }
42-
*/
4333
@Suppress("ReturnCount")
44-
private fun mapError(error: VolleyError): UploadEncryptedLogError {
45-
if (error is NoConnectionError) {
46-
return UploadEncryptedLogError.NoConnection
34+
private fun mapError(statusCode: Int, responseBody: String): UploadEncryptedLogError {
35+
val json = try {
36+
JSONObject(responseBody)
37+
} catch (jsonException: JSONException) {
38+
Log.e(TAG, "Received response not in JSON format: " + jsonException.message)
39+
return UploadEncryptedLogError.Unknown(statusCode = statusCode, message = responseBody)
4740
}
48-
error.networkResponse?.let { networkResponse ->
49-
val statusCode = networkResponse.statusCode
50-
val dataString = String(networkResponse.data)
51-
val json = try {
52-
JSONObject(dataString)
53-
} catch (jsonException: JSONException) {
54-
Log.e(TAG, "Received response not in JSON format: " + jsonException.message)
55-
return UploadEncryptedLogError.Unknown(message = dataString)
56-
}
57-
val errorMessage = json.getString("message")
58-
json.getString("error").let { errorType ->
59-
if (errorType == INVALID_REQUEST) {
60-
return UploadEncryptedLogError.InvalidRequest
61-
} else if (errorType == TOO_MANY_REQUESTS) {
62-
return UploadEncryptedLogError.TooManyRequests
63-
}
41+
val errorMessage = json.getString("message")
42+
json.getString("error").let { errorType ->
43+
if (errorType == INVALID_REQUEST) {
44+
return UploadEncryptedLogError.InvalidRequest
45+
} else if (errorType == TOO_MANY_REQUESTS) {
46+
return UploadEncryptedLogError.TooManyRequests
6447
}
65-
return UploadEncryptedLogError.Unknown(statusCode, errorMessage)
6648
}
67-
return UploadEncryptedLogError.Unknown()
49+
return UploadEncryptedLogError.Unknown(statusCode, errorMessage)
6850
}
6951

7052
companion object {

0 commit comments

Comments
 (0)