Skip to content

Commit

Permalink
Merge pull request #525 from matomo-org/KotlinDefaultPacketSender
Browse files Browse the repository at this point in the history
Kotlin DefaultPacketSender
hannesa2 authored Jul 11, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents 8ab31c9 + a9f4b07 commit baa9238
Showing 7 changed files with 164 additions and 175 deletions.

This file was deleted.

140 changes: 140 additions & 0 deletions tracker/src/main/java/org/matomo/sdk/dispatcher/DefaultPacketSender.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package org.matomo.sdk.dispatcher

import org.matomo.sdk.Matomo.Companion.tag
import timber.log.Timber
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStreamReader
import java.io.OutputStream
import java.io.OutputStreamWriter
import java.net.HttpURLConnection
import java.net.URL
import java.nio.charset.StandardCharsets
import java.util.zip.GZIPOutputStream

class DefaultPacketSender : PacketSender {
private var mTimeout = Dispatcher.DEFAULT_CONNECTION_TIMEOUT.toLong()
private var mGzip = false

override fun send(packet: Packet): Boolean {
var urlConnection: HttpURLConnection? = null
try {
urlConnection = URL(packet.targetURL).openConnection() as HttpURLConnection

Timber.tag(TAG).v("Connection is open to %s", urlConnection.url.toExternalForm())
Timber.tag(TAG).v("Sending: %s", packet)

urlConnection.connectTimeout = mTimeout.toInt()
urlConnection.readTimeout = mTimeout.toInt()

// IF there is json data we have to do a post
if (packet.postData != null) { // POST
urlConnection.doOutput = true // Forces post
urlConnection.setRequestProperty("Content-Type", "application/json")
urlConnection.setRequestProperty("charset", "utf-8")

val toPost = packet.postData.toString()
if (mGzip) {
urlConnection.addRequestProperty("Content-Encoding", "gzip")
val byteArrayOS = ByteArrayOutputStream()

GZIPOutputStream(byteArrayOS).use { gzipStream ->
gzipStream.write(toPost.toByteArray(StandardCharsets.UTF_8))
}
// If closing fails we assume the written data to be invalid.
// Don't catch the exception and let it abort the `send(Packet)` call.
var outputStream: OutputStream? = null
try {
outputStream = urlConnection.outputStream
outputStream.write(byteArrayOS.toByteArray())
} finally {
if (outputStream != null) {
try {
outputStream.close()
} catch (e: IOException) {
// Failing to close the stream is not enough to consider the transmission faulty.
Timber.tag(TAG).d(e, "Failed to close output stream after writing gzipped POST data.")
}
}
}
} else {
var writer: BufferedWriter? = null
try {
writer = BufferedWriter(OutputStreamWriter(urlConnection.outputStream, StandardCharsets.UTF_8))
writer.write(toPost)
} finally {
if (writer != null) {
try {
writer.close()
} catch (e: IOException) {
// Failing to close the stream is not enough to consider the transmission faulty.
Timber.tag(TAG).d(e, "Failed to close output stream after writing POST data.")
}
}
}
}
} else { // GET
urlConnection.doOutput = false // Defaults to false, but for readability
}

val statusCode = urlConnection.responseCode
Timber.tag(TAG).v("Transmission finished (code=%d).", statusCode)
val successful = checkResponseCode(statusCode)

if (successful) {
// https://github.com/matomo-org/matomo-sdk-android/issues/226

val `is` = urlConnection.inputStream
if (`is` != null) {
try {
`is`.close()
} catch (e: IOException) {
Timber.tag(TAG).d(e, "Failed to close the error stream.")
}
}
} else {
// Consume the error stream (or at least close it) if the status code was non-OK (not 2XX)
val errorReason = StringBuilder()
var errorReader: BufferedReader? = null
try {
errorReader = BufferedReader(InputStreamReader(urlConnection.errorStream))
var line: String?
while ((errorReader.readLine().also { line = it }) != null) errorReason.append(line)
} finally {
if (errorReader != null) {
try {
errorReader.close()
} catch (e: IOException) {
Timber.tag(TAG).d(e, "Failed to close the error stream.")
}
}
}
Timber.tag(TAG).w("Transmission failed (code=%d, reason=%s)", statusCode, errorReason.toString())
}

return successful
} catch (e: Exception) {
Timber.tag(TAG).e(e, "Transmission failed unexpectedly.")
return false
} finally {
urlConnection?.disconnect()
}
}

override fun setTimeout(timeout: Long) {
mTimeout = timeout
}

override fun setGzipData(gzip: Boolean) {
mGzip = gzip
}

companion object {
private val TAG = tag(DefaultPacketSender::class.java)
private fun checkResponseCode(code: Int): Boolean {
return code == HttpURLConnection.HTTP_NO_CONTENT || code == HttpURLConnection.HTTP_OK
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.matomo.sdk.dispatcher

import org.matomo.sdk.Tracker

interface DispatcherFactory {
fun build(tracker: Tracker?): Dispatcher?
}
16 changes: 0 additions & 16 deletions tracker/src/main/java/org/matomo/sdk/dispatcher/PacketSender.java

This file was deleted.

16 changes: 16 additions & 0 deletions tracker/src/main/java/org/matomo/sdk/dispatcher/PacketSender.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.matomo.sdk.dispatcher


interface PacketSender {
/**
* @return true if successful
*/
fun send(packet: Packet): Boolean

/**
* @param timeout in milliseconds
*/
fun setTimeout(timeout: Long)

fun setGzipData(gzip: Boolean)
}
2 changes: 1 addition & 1 deletion tracker/src/main/java/org/matomo/sdk/tools/UrlHelper.java
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ public class UrlHelper {
public static List<Pair<String, String>> parse(@NonNull final URI uri, @Nullable final String encoding) {
List<Pair<String, String>> result = Collections.emptyList();
final String query = uri.getRawQuery();
if (query != null && query.length() > 0) {
if (query != null && !query.isEmpty()) {
result = new ArrayList<>();
parse(result, new Scanner(query), encoding);
}

0 comments on commit baa9238

Please sign in to comment.