From 3915ec6d8ff547b832256dd1c2fdb08ac531cd62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joris=20Pelgr=C3=B6m?= Date: Tue, 19 Sep 2023 21:38:50 +0200 Subject: [PATCH] Automatically fix broken registrations/webhooks (#3875) --- .../FirebaseCloudMessagingService.kt | 5 ++-- .../data/integration/IntegrationRepository.kt | 2 +- .../impl/IntegrationRepositoryImpl.kt | 30 +++++++++++++++---- .../FirebaseCloudMessagingService.kt | 5 ++-- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/app/src/full/java/io/homeassistant/companion/android/notifications/FirebaseCloudMessagingService.kt b/app/src/full/java/io/homeassistant/companion/android/notifications/FirebaseCloudMessagingService.kt index f19950fc149..1c01ff42a57 100644 --- a/app/src/full/java/io/homeassistant/companion/android/notifications/FirebaseCloudMessagingService.kt +++ b/app/src/full/java/io/homeassistant/companion/android/notifications/FirebaseCloudMessagingService.kt @@ -49,9 +49,8 @@ class FirebaseCloudMessagingService : FirebaseMessagingService() { launch { try { serverManager.integrationRepository(it.id).updateRegistration( - DeviceRegistration( - pushToken = token - ) + deviceRegistration = DeviceRegistration(pushToken = token), + allowReregistration = false ) } catch (e: Exception) { Log.e(TAG, "Issue updating token", e) diff --git a/common/src/main/java/io/homeassistant/companion/android/common/data/integration/IntegrationRepository.kt b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/IntegrationRepository.kt index b15e34a52e6..07c8c458d06 100644 --- a/common/src/main/java/io/homeassistant/companion/android/common/data/integration/IntegrationRepository.kt +++ b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/IntegrationRepository.kt @@ -10,7 +10,7 @@ import kotlinx.coroutines.flow.Flow interface IntegrationRepository { suspend fun registerDevice(deviceRegistration: DeviceRegistration) - suspend fun updateRegistration(deviceRegistration: DeviceRegistration) + suspend fun updateRegistration(deviceRegistration: DeviceRegistration, allowReregistration: Boolean = true) suspend fun getRegistration(): DeviceRegistration suspend fun deletePreferences() diff --git a/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/IntegrationRepositoryImpl.kt b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/IntegrationRepositoryImpl.kt index fc622d9d15a..48b704ccaf3 100644 --- a/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/IntegrationRepositoryImpl.kt +++ b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/IntegrationRepositoryImpl.kt @@ -117,7 +117,7 @@ class IntegrationRepositoryImpl @AssistedInject constructor( } } - override suspend fun updateRegistration(deviceRegistration: DeviceRegistration) { + override suspend fun updateRegistration(deviceRegistration: DeviceRegistration, allowReregistration: Boolean) { val request = IntegrationRequest( "update_registration", @@ -126,9 +126,20 @@ class IntegrationRepositoryImpl @AssistedInject constructor( var causeException: Exception? = null for (it in server.connection.getApiUrls()) { try { - if (integrationService.callWebhook(it.toHttpUrlOrNull()!!, request).isSuccessful) { - persistDeviceRegistration(deviceRegistration) - return + val response = integrationService.callWebhook(it.toHttpUrlOrNull()!!, request) + // The server should return a body with the registration, but might return: + // 200 with empty body for broken direct webhook + // 404 for broken cloudhook + // 410 for missing config entry + if (response.isSuccessful) { + if (response.code() == 200 && (response.body()?.contentLength() ?: 0) == 0L) { + throw IllegalStateException("update_registration returned empty body") + } else { + persistDeviceRegistration(deviceRegistration) + return + } + } else if (response.code() == 404 || response.code() == 410) { + throw IllegalStateException("update_registration returned code ${response.code()}") } } catch (e: Exception) { if (causeException == null) causeException = e @@ -137,7 +148,16 @@ class IntegrationRepositoryImpl @AssistedInject constructor( } if (causeException != null) { - throw IntegrationException(causeException) + if (allowReregistration && (causeException is IllegalStateException)) { + Log.w(TAG, "Device registration broken, reregistering", causeException) + try { + registerDevice(deviceRegistration) + } catch (e: Exception) { + throw IntegrationException(e) + } + } else { + throw IntegrationException(causeException) + } } else { throw IntegrationException("Error calling integration request update_registration") } diff --git a/wear/src/main/java/io/homeassistant/companion/android/notifications/FirebaseCloudMessagingService.kt b/wear/src/main/java/io/homeassistant/companion/android/notifications/FirebaseCloudMessagingService.kt index 9b6ffd95331..e886caaf3dc 100755 --- a/wear/src/main/java/io/homeassistant/companion/android/notifications/FirebaseCloudMessagingService.kt +++ b/wear/src/main/java/io/homeassistant/companion/android/notifications/FirebaseCloudMessagingService.kt @@ -49,10 +49,11 @@ class FirebaseCloudMessagingService : FirebaseMessagingService() { launch { try { serverManager.integrationRepository(it.id).updateRegistration( - DeviceRegistration( + deviceRegistration = DeviceRegistration( pushToken = token, pushWebsocket = false - ) + ), + allowReregistration = false ) } catch (e: Exception) { Log.e(TAG, "Issue updating token", e)