splitting the unified push reciever logic to a testable delegate
This commit is contained in:
parent
b6f223c8c9
commit
093e5b64bb
|
@ -0,0 +1,69 @@
|
|||
package app.dapk.st.push.unifiedpush
|
||||
|
||||
import android.content.Context
|
||||
import app.dapk.st.core.AppLogTag
|
||||
import app.dapk.st.core.log
|
||||
import app.dapk.st.core.module
|
||||
import app.dapk.st.matrix.common.EventId
|
||||
import app.dapk.st.matrix.common.RoomId
|
||||
import app.dapk.st.push.PushModule
|
||||
import app.dapk.st.push.PushTokenPayload
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.net.URL
|
||||
|
||||
private const val FALLBACK_UNIFIED_PUSH_GATEWAY = "https://matrix.gateway.unifiedpush.org/_matrix/push/v1/notify"
|
||||
private val json = Json { ignoreUnknownKeys = true }
|
||||
|
||||
class UnifiedPushMessageDelegate(
|
||||
private val scope: CoroutineScope = CoroutineScope(SupervisorJob()),
|
||||
private val pushModuleProvider: (Context) -> PushModule = { it.module() }
|
||||
) {
|
||||
|
||||
fun onMessage(context: Context, message: ByteArray) {
|
||||
log(AppLogTag.PUSH, "UnifiedPush onMessage, $message")
|
||||
val module = pushModuleProvider(context)
|
||||
val handler = module.pushHandler()
|
||||
scope.launch {
|
||||
withContext(module.dispatcher().io) {
|
||||
val payload = json.decodeFromString(UnifiedPushMessagePayload.serializer(), String(message))
|
||||
handler.onMessageReceived(payload.notification.eventId?.let { EventId(it) }, payload.notification.roomId?.let { RoomId(it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onNewEndpoint(context: Context, endpoint: String) {
|
||||
log(AppLogTag.PUSH, "UnifiedPush onNewEndpoint $endpoint")
|
||||
val module = pushModuleProvider(context)
|
||||
val handler = module.pushHandler()
|
||||
scope.launch {
|
||||
withContext(module.dispatcher().io) {
|
||||
val matrixEndpoint = URL(endpoint).let { URL("${it.protocol}://${it.host}/_matrix/push/v1/notify") }
|
||||
val content = runCatching { matrixEndpoint.openStream().use { String(it.readBytes()) } }.getOrNull() ?: ""
|
||||
val gatewayUrl = when {
|
||||
content.contains("\"gateway\":\"matrix\"") -> matrixEndpoint.toString()
|
||||
else -> FALLBACK_UNIFIED_PUSH_GATEWAY
|
||||
}
|
||||
handler.onNewToken(PushTokenPayload(token = endpoint, gatewayUrl = gatewayUrl))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
private data class UnifiedPushMessagePayload(
|
||||
@SerialName("notification") val notification: Notification,
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
data class Notification(
|
||||
@SerialName("event_id") val eventId: String? = null,
|
||||
@SerialName("room_id") val roomId: String? = null,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -3,56 +3,19 @@ package app.dapk.st.push.unifiedpush
|
|||
import android.content.Context
|
||||
import app.dapk.st.core.AppLogTag
|
||||
import app.dapk.st.core.log
|
||||
import app.dapk.st.core.module
|
||||
import app.dapk.st.matrix.common.EventId
|
||||
import app.dapk.st.matrix.common.RoomId
|
||||
import app.dapk.st.push.PushModule
|
||||
import app.dapk.st.push.PushTokenPayload
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.unifiedpush.android.connector.MessagingReceiver
|
||||
import java.net.URL
|
||||
|
||||
private val json = Json { ignoreUnknownKeys = true }
|
||||
|
||||
private const val FALLBACK_UNIFIED_PUSH_GATEWAY = "https://matrix.gateway.unifiedpush.org/_matrix/push/v1/notify"
|
||||
|
||||
class UnifiedPushMessageReceiver : MessagingReceiver() {
|
||||
|
||||
private val scope = CoroutineScope(SupervisorJob())
|
||||
private val delegate = UnifiedPushMessageDelegate()
|
||||
|
||||
override fun onMessage(context: Context, message: ByteArray, instance: String) {
|
||||
log(AppLogTag.PUSH, "UnifiedPush onMessage, $message")
|
||||
val module = context.module<PushModule>()
|
||||
val handler = module.pushHandler()
|
||||
scope.launch {
|
||||
withContext(module.dispatcher().io) {
|
||||
val payload = json.decodeFromString(UnifiedPushMessagePayload.serializer(), String(message))
|
||||
handler.onMessageReceived(payload.notification.eventId?.let { EventId(it) }, payload.notification.roomId?.let { RoomId(it) })
|
||||
}
|
||||
}
|
||||
delegate.onMessage(context, message)
|
||||
}
|
||||
|
||||
override fun onNewEndpoint(context: Context, endpoint: String, instance: String) {
|
||||
log(AppLogTag.PUSH, "UnifiedPush onNewEndpoint $endpoint")
|
||||
val module = context.module<PushModule>()
|
||||
val handler = module.pushHandler()
|
||||
scope.launch {
|
||||
withContext(module.dispatcher().io) {
|
||||
val matrixEndpoint = URL(endpoint).let { URL("${it.protocol}://${it.host}/_matrix/push/v1/notify") }
|
||||
val content = runCatching { matrixEndpoint.openStream().use { String(it.readBytes()) } }.getOrNull() ?: ""
|
||||
val gatewayUrl = when {
|
||||
content.contains("\"gateway\":\"matrix\"") -> matrixEndpoint.toString()
|
||||
else -> FALLBACK_UNIFIED_PUSH_GATEWAY
|
||||
}
|
||||
handler.onNewToken(PushTokenPayload(token = endpoint, gatewayUrl = gatewayUrl))
|
||||
}
|
||||
}
|
||||
delegate.onNewEndpoint(context, endpoint)
|
||||
}
|
||||
|
||||
override fun onRegistrationFailed(context: Context, instance: String) {
|
||||
|
@ -63,15 +26,4 @@ class UnifiedPushMessageReceiver : MessagingReceiver() {
|
|||
log(AppLogTag.PUSH, "UnifiedPush onUnregistered")
|
||||
}
|
||||
|
||||
@Serializable
|
||||
private data class UnifiedPushMessagePayload(
|
||||
@SerialName("notification") val notification: Notification,
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
data class Notification(
|
||||
@SerialName("event_id") val eventId: String? = null,
|
||||
@SerialName("room_id") val roomId: String? = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ def excludes = [
|
|||
'**/*Activity*',
|
||||
'**/*AndroidService*',
|
||||
'**/*Application*',
|
||||
'**/*Receiver*',
|
||||
|
||||
// Generated
|
||||
'**/*serializer*',
|
||||
|
|
Loading…
Reference in New Issue