Extract code to retrieve .well-known files to its own modules.

This commit is contained in:
Benoit Marty 2025-08-08 12:21:36 +02:00
parent 1afcce2b97
commit db64ce3142
26 changed files with 337 additions and 199 deletions

View file

@ -0,0 +1,13 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
plugins {
id("io.element.android-library")
}
android {
namespace = "io.element.android.libraries.wellknown.api"
}

View file

@ -0,0 +1,13 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.api
data class ElementWellKnown(
val registrationHelperUrl: String? = null,
val enforceElementPro: Boolean? = null,
)

View file

@ -0,0 +1,17 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.api
data class WellKnown(
val homeServer: WellKnownBaseConfig? = null,
val identityServer: WellKnownBaseConfig? = null,
)
data class WellKnownBaseConfig(
val baseURL: String? = null
)

View file

@ -0,0 +1,13 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.api
interface WellknownRetriever {
suspend fun getWellKnown(baseUrl: String): WellKnown?
suspend fun getElementWellKnown(baseUrl: String): ElementWellKnown?
}

View file

@ -0,0 +1,32 @@
import extension.setupAnvil
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
plugins {
id("io.element.android-library")
id("kotlin-parcelize")
alias(libs.plugins.kotlin.serialization)
}
android {
namespace = "io.element.android.libraries.wellknown.impl"
}
setupAnvil()
dependencies {
implementation(libs.androidx.annotationjvm)
implementation(libs.coroutines.core)
implementation(platform(libs.network.retrofit.bom))
implementation(libs.network.retrofit)
implementation(libs.serialization.json)
implementation(projects.libraries.architecture)
implementation(projects.libraries.core)
implementation(projects.libraries.network)
implementation(projects.libraries.wellknown.api)
}

View file

@ -0,0 +1,69 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.impl
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.core.uri.ensureProtocol
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.network.RetrofitFactory
import io.element.android.libraries.wellknown.api.ElementWellKnown
import io.element.android.libraries.wellknown.api.WellKnown
import io.element.android.libraries.wellknown.api.WellKnownBaseConfig
import io.element.android.libraries.wellknown.api.WellknownRetriever
import timber.log.Timber
import javax.inject.Inject
@ContributesBinding(AppScope::class)
class DefaultWellknownRetriever @Inject constructor(
private val retrofitFactory: RetrofitFactory,
) : WellknownRetriever {
override suspend fun getWellKnown(baseUrl: String): WellKnown? {
val wellknownApi = buildWellknownApi(baseUrl) ?: return null
return try {
wellknownApi.getWellKnown().map()
} catch (e: Exception) {
Timber.e(e, "Failed to retrieve well-known data for $baseUrl")
null
}
}
override suspend fun getElementWellKnown(baseUrl: String): ElementWellKnown? {
val wellknownApi = buildWellknownApi(baseUrl) ?: return null
return try {
wellknownApi.getElementWellKnown().map()
} catch (e: Exception) {
Timber.e(e, "Failed to retrieve Element well-known data for $baseUrl")
null
}
}
private fun buildWellknownApi(accountProviderUrl: String): WellknownAPI? {
return try {
retrofitFactory.create(accountProviderUrl.ensureProtocol())
.create(WellknownAPI::class.java)
} catch (e: Exception) {
// If the base URL is not valid, we cannot retrieve the well-known data
Timber.e(e, "Failed to create Retrofit instance for $accountProviderUrl")
null
}
}
}
private fun InternalElementWellKnown.map() = ElementWellKnown(
registrationHelperUrl = registrationHelperUrl,
enforceElementPro = enforceElementPro,
)
private fun InternalWellKnown.map() = WellKnown(
homeServer = homeServer?.map(),
identityServer = identityServer?.map(),
)
private fun InternalWellKnownBaseConfig.map() = WellKnownBaseConfig(
baseURL = baseURL,
)

View file

@ -0,0 +1,28 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.impl
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Example:
* <pre>
* {
* "registration_helper_url": "https://element.io"
* }
* </pre>
* .
*/
@Serializable
data class InternalElementWellKnown(
@SerialName("registration_helper_url")
val registrationHelperUrl: String? = null,
@SerialName("enforce_element_pro")
val enforceElementPro: Boolean? = null,
)

View file

@ -0,0 +1,33 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.impl
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery
* <pre>
* {
* "m.homeserver": {
* "base_url": "https://matrix.org"
* },
* "m.identity_server": {
* "base_url": "https://vector.im"
* },
* }
* </pre>
* .
*/
@Serializable
data class InternalWellKnown(
@SerialName("m.homeserver")
val homeServer: InternalWellKnownBaseConfig? = null,
@SerialName("m.identity_server")
val identityServer: InternalWellKnownBaseConfig? = null,
)

View file

@ -0,0 +1,26 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.impl
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* https://matrix.org/docs/spec/client_server/r0.4.0.html#server-discovery
* <pre>
* {
* "base_url": "https://element.io"
* }
* </pre>
* .
*/
@Serializable
data class InternalWellKnownBaseConfig(
@SerialName("base_url")
val baseURL: String? = null
)

View file

@ -0,0 +1,18 @@
/*
* Copyright 2023, 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.wellknown.impl
import retrofit2.http.GET
internal interface WellknownAPI {
@GET(".well-known/matrix/client")
suspend fun getWellKnown(): InternalWellKnown
@GET(".well-known/element/element.json")
suspend fun getElementWellKnown(): InternalElementWellKnown
}

View file

@ -0,0 +1,19 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
plugins {
id("io.element.android-library")
}
android {
namespace = "io.element.android.features.wellknown.test"
}
dependencies {
implementation(projects.libraries.wellknown.api)
implementation(projects.tests.testutils)
}

View file

@ -0,0 +1,26 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.wellknown.test
import io.element.android.libraries.wellknown.api.ElementWellKnown
import io.element.android.libraries.wellknown.api.WellKnown
import io.element.android.libraries.wellknown.api.WellknownRetriever
import io.element.android.tests.testutils.simulateLongTask
class FakeWellknownRetriever(
private val getWellKnownResult: (String) -> WellKnown? = { null },
private val getElementWellKnownResult: (String) -> ElementWellKnown? = { null },
) : WellknownRetriever {
override suspend fun getWellKnown(baseUrl: String): WellKnown? = simulateLongTask {
getWellKnownResult(baseUrl)
}
override suspend fun getElementWellKnown(baseUrl: String): ElementWellKnown? = simulateLongTask {
getElementWellKnownResult(baseUrl)
}
}