Skip to content

Commit

Permalink
Merge branch 'develop' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
jakubuid authored Jul 11, 2024
2 parents 63fb56b + 75fee10 commit 7cdd52c
Show file tree
Hide file tree
Showing 33 changed files with 319 additions and 217 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci_relay.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:

- name: Run Relay CI
env:
TEST_RELAY_URL: wss://relay.walletconnect.com
TEST_RELAY_URL: wss://relay.walletconnect.org
TEST_PROJECT_ID: ${{ secrets.WC_CLOUD_PROJECT_ID }}
NOTIFY_INTEGRATION_TESTS_PROJECT_ID: ${{ secrets.NOTIFY_INTEGRATION_TESTS_PROJECT_ID }}
NOTIFY_INTEGRATION_TESTS_SECRET: ${{ secrets.NOTIFY_INTEGRATION_TESTS_SECRET }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci_scheduled.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:

- name: Run Relay CI
env:
TEST_RELAY_URL: wss://relay.walletconnect.com
TEST_RELAY_URL: wss://relay.walletconnect.org
TEST_PROJECT_ID: ${{ secrets.WC_CLOUD_PROJECT_ID }}
with:
SECRETS_PROPERTIES: ${{ secrets.SECRETS_PROPERTIES }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class WCInstrumentedActivityScenario : TestRule {
}
}
}.fold(
onSuccess = { Timber.d("Connection established with: ${TestClient.RELAY_URL}") },
onSuccess = { Timber.d("Connection established with successfully") },
onFailure = { fail("Unable to establish connection within $timeoutDuration") }
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import org.koin.core.qualifier.named
import timber.log.Timber

internal object TestClient {
const val RELAY_URL = "wss://relay.walletconnect.com?projectId=${BuildConfig.PROJECT_ID}"
private val app = ApplicationProvider.getApplicationContext<Application>()
fun KoinApplication.Companion.createNewWCKoinApp(): KoinApplication = KoinApplication.init().apply { createEagerInstances() }

Expand All @@ -40,7 +39,7 @@ internal object TestClient {

private val coreProtocol = CoreClient.apply {
Timber.d("Primary CP start: ")
initialize(metadata, RELAY_URL, ConnectionType.MANUAL, app, onError = ::globalOnError)
initialize(app, BuildConfig.PROJECT_ID, metadata, ConnectionType.MANUAL, onError = ::globalOnError)
Relay.connect(::globalOnError)
_isInitialized.tryEmit(true)
Timber.d("Primary CP finish: ")
Expand Down Expand Up @@ -72,7 +71,7 @@ internal object TestClient {

private val coreProtocol = CoreProtocol(secondaryKoinApp).apply {
Timber.d("Secondary CP start: ")
initialize(metadata, RELAY_URL, ConnectionType.MANUAL, app) { Timber.e(it.throwable) }
initialize(app, BuildConfig.PROJECT_ID, metadata, ConnectionType.MANUAL) { Timber.e(it.throwable) }

// Override of previous Relay necessary for reinitialization of `eventsFlow`
Relay = RelayClient(secondaryKoinApp)
Expand All @@ -91,8 +90,5 @@ internal object TestClient {
}

internal val Relay get() = coreProtocol.Relay
internal val jsonRpcInteractor: JsonRpcInteractorInterface by lazy { secondaryKoinApp.koin.get() }
internal val keyManagementRepository: KeyManagementRepository by lazy { secondaryKoinApp.koin.get() }

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,24 @@ interface CoreInterface {
fun initialize(
metaData: Core.Model.AppMetaData,
relayServerUrl: String,
connectionType: ConnectionType,
connectionType: ConnectionType = ConnectionType.AUTOMATIC,
application: Application,
relay: RelayConnectionInterface? = null,
keyServerUrl: String? = null,
networkClientTimeout: NetworkClientTimeout? = null,
telemetryEnabled: Boolean = true,
onError: (Core.Model.Error) -> Unit,
)

fun initialize(
application: Application,
projectId: String,
metaData: Core.Model.AppMetaData,
connectionType: ConnectionType = ConnectionType.AUTOMATIC,
relay: RelayConnectionInterface? = null,
keyServerUrl: String? = null,
networkClientTimeout: NetworkClientTimeout? = null,
telemetryEnabled: Boolean = true,
onError: (Core.Model.Error) -> Unit,
)
}
125 changes: 92 additions & 33 deletions core/android/src/main/kotlin/com/walletconnect/android/CoreProtocol.kt
Original file line number Diff line number Diff line change
Expand Up @@ -76,44 +76,103 @@ class CoreProtocol(private val koinApp: KoinApplication = wcKoinApp) : CoreInter
onError: (Core.Model.Error) -> Unit
) {
try {
val bundleId: String = application.packageName
with(koinApp) {
androidContext(application)
require(relayServerUrl.isValidRelayServerUrl()) { "Check the schema and projectId parameter of the Server Url" }
modules(
module { single { ProjectId(relayServerUrl.projectId()) } },
module { single(named(AndroidCommonDITags.TELEMETRY_ENABLED)) { TelemetryEnabled(telemetryEnabled) } },
coreAndroidNetworkModule(relayServerUrl, connectionType.toCommonConnectionType(), BuildConfig.SDK_VERSION, networkClientTimeout, bundleId),
coreCommonModule(),
coreCryptoModule(),
)
require(relayServerUrl.isValidRelayServerUrl()) { "Check the schema and projectId parameter of the Server Url" }

if (relay == null) {
Relay.initialize { error -> onError(Core.Model.Error(error)) }
}
setup(
application = application,
serverUrl = relayServerUrl,
projectId = relayServerUrl.projectId(),
telemetryEnabled = telemetryEnabled,
connectionType = connectionType,
networkClientTimeout = networkClientTimeout,
relay = relay,
onError = onError,
metaData = metaData,
keyServerUrl = keyServerUrl
)
} catch (e: Exception) {
onError(Core.Model.Error(e))
}
}

modules(
coreStorageModule(bundleId = bundleId),
pushModule(),
module { single { relay ?: Relay } },
module { single { with(metaData) { AppMetaData(name = name, description = description, url = url, icons = icons, redirect = Redirect(redirect)) } } },
module { single { Echo } },
module { single { Push } },
module { single { Verify } },
coreJsonRpcModule(),
corePairingModule(Pairing, PairingController),
keyServerModule(keyServerUrl),
explorerModule(),
web3ModalModule(),
pulseModule(bundleId)
)
}
override fun initialize(
application: Application,
projectId: String,
metaData: Core.Model.AppMetaData,
connectionType: ConnectionType,
relay: RelayConnectionInterface?,
keyServerUrl: String?,
networkClientTimeout: NetworkClientTimeout?,
telemetryEnabled: Boolean,
onError: (Core.Model.Error) -> Unit
) {
try {
require(projectId.isNotEmpty()) { "Project Id cannot be empty" }

Verify.initialize()
Pairing.initialize()
PairingController.initialize()
setup(
application = application,
projectId = projectId,
telemetryEnabled = telemetryEnabled,
connectionType = connectionType,
networkClientTimeout = networkClientTimeout,
relay = relay,
onError = onError,
metaData = metaData,
keyServerUrl = keyServerUrl
)
} catch (e: Exception) {
onError(Core.Model.Error(e))
}
}

private fun CoreProtocol.setup(
application: Application,
serverUrl: String? = null,
projectId: String,
telemetryEnabled: Boolean,
connectionType: ConnectionType,
networkClientTimeout: NetworkClientTimeout?,
relay: RelayConnectionInterface?,
onError: (Core.Model.Error) -> Unit,
metaData: Core.Model.AppMetaData,
keyServerUrl: String?
) {
val bundleId: String = application.packageName
val relayServerUrl = if (serverUrl.isNullOrEmpty()) "wss://relay.walletconnect.org?projectId=$projectId" else serverUrl

with(koinApp) {
androidContext(application)
modules(
module { single { ProjectId(projectId) } },
module { single(named(AndroidCommonDITags.TELEMETRY_ENABLED)) { TelemetryEnabled(telemetryEnabled) } },
coreAndroidNetworkModule(relayServerUrl, connectionType.toCommonConnectionType(), BuildConfig.SDK_VERSION, networkClientTimeout, bundleId),
coreCommonModule(),
coreCryptoModule(),
)

if (relay == null) {
Relay.initialize { error -> onError(Core.Model.Error(error)) }
}

modules(
coreStorageModule(bundleId = bundleId),
pushModule(),
module { single { relay ?: Relay } },
module { single { with(metaData) { AppMetaData(name = name, description = description, url = url, icons = icons, redirect = Redirect(redirect)) } } },
module { single { Echo } },
module { single { Push } },
module { single { Verify } },
coreJsonRpcModule(),
corePairingModule(Pairing, PairingController),
keyServerModule(keyServerUrl),
explorerModule(),
web3ModalModule(),
pulseModule(bundleId)
)
}

Verify.initialize()
Pairing.initialize()
PairingController.initialize()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,21 @@ import com.walletconnect.foundation.network.data.service.RelayService
import okhttp3.Authenticator
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import org.koin.android.ext.koin.androidApplication
import org.koin.core.qualifier.named
import org.koin.dsl.module
import java.io.IOException
import java.net.SocketTimeoutException
import java.util.concurrent.TimeUnit

private var SERVER_URL: String = ""
private const val DEFAULT_RELAY_URL = "relay.walletconnect.com"
private const val DEFAULT_BACKOFF_SECONDS = 5L

@Suppress("LocalVariableName")
@JvmSynthetic
fun coreAndroidNetworkModule(serverUrl: String, connectionType: ConnectionType, sdkVersion: String, timeout: NetworkClientTimeout? = null, bundleId: String) = module {
val networkClientTimeout = timeout ?: NetworkClientTimeout.getDefaultTimeout()
SERVER_URL = serverUrl

factory(named(AndroidCommonDITags.RELAY_URL)) {
val jwt = get<GenerateJwtStoreClientIdUseCase>().invoke(SERVER_URL)
Uri.parse(SERVER_URL)
val jwt = get<GenerateJwtStoreClientIdUseCase>().invoke(serverUrl)
Uri.parse(serverUrl)
.buildUpon()
.appendQueryParameter("auth", jwt)
.appendQueryParameter("ua", get(named(AndroidCommonDITags.USER_AGENT)))
Expand Down Expand Up @@ -74,42 +67,10 @@ fun coreAndroidNetworkModule(serverUrl: String, connectionType: ConnectionType,
HttpLoggingInterceptor().apply { setLevel(HttpLoggingInterceptor.Level.BODY) }
}

single(named(AndroidCommonDITags.FAIL_OVER_INTERCEPTOR)) {
Interceptor { chain ->
var request = chain.request()
var response: Response? = null

if (request.url.host.contains(DEFAULT_RELAY_URL)) {
try {
response = chain.proceed(request)

return@Interceptor response
} catch (e: Exception) {
when (e) {
is SocketTimeoutException, is IOException -> {
val failoverUrl = request.url.host.replace(".com", ".org")
val newHttpUrl = request.url.newBuilder().host(failoverUrl).build()

request = request.newBuilder().url(newHttpUrl).build()
return@Interceptor chain.proceed(request)
}
else -> {
throw e
}
}
} finally {
response?.close()
}
} else {
return@Interceptor chain.proceed(request)
}
}
}

single(named(AndroidCommonDITags.AUTHENTICATOR)) {
Authenticator { _, response ->
response.request.run {
if (Uri.parse(SERVER_URL).host == this.url.host) {
if (Uri.parse(serverUrl).host == this.url.host) {
this.newBuilder().url(get<String>(named(AndroidCommonDITags.RELAY_URL))).build()
} else {
null
Expand All @@ -121,7 +82,6 @@ fun coreAndroidNetworkModule(serverUrl: String, connectionType: ConnectionType,
single(named(AndroidCommonDITags.OK_HTTP)) {
OkHttpClient.Builder()
.addInterceptor(get<Interceptor>(named(AndroidCommonDITags.SHARED_INTERCEPTOR)))
.addInterceptor(get<Interceptor>(named(AndroidCommonDITags.FAIL_OVER_INTERCEPTOR)))
.authenticator((get(named(AndroidCommonDITags.AUTHENTICATOR))))
.writeTimeout(networkClientTimeout.timeout, networkClientTimeout.timeUnit)
.readTimeout(networkClientTimeout.timeout, networkClientTimeout.timeUnit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ data class NetworkClientTimeout(

companion object {

private const val MIN_TIMEOUT_LIMIT_AS_MILLIS = 5_000L
private const val MIN_TIMEOUT_LIMIT_AS_MILLIS = 10_000L
private const val MAX_TIMEOUT_LIMIT_AS_MILLIS = 60_000L

fun getDefaultTimeout() = NetworkClientTimeout(
timeout = MAX_TIMEOUT_LIMIT_AS_MILLIS,
timeout = MIN_TIMEOUT_LIMIT_AS_MILLIS,
timeUnit = TimeUnit.MILLISECONDS
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,10 @@ class SendEventUseCaseTest : KoinTest {
private lateinit var useCase: SendEventUseCase
private val testDispatcher = StandardTestDispatcher()

private val testModule: Module = module {
single(named(AndroidCommonDITags.ENABLE_WEB_3_MODAL_ANALYTICS)) { true }
}

@OptIn(ExperimentalCoroutinesApi::class)
@Before
fun setUp() {
Dispatchers.setMain(testDispatcher)
val app = startKoin { modules(testModule) }
useCase = SendEventUseCase(pulseService, logger, bundleId)
wcKoinApp = app
}

@OptIn(ExperimentalCoroutinesApi::class)
Expand All @@ -64,6 +57,14 @@ class SendEventUseCaseTest : KoinTest {
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun `send should log and send event when analytics is enabled and response is successful`() = runTest(testDispatcher) {
stopKoin()
val module: Module = module {
single(named(AndroidCommonDITags.ENABLE_WEB_3_MODAL_ANALYTICS)) { true }
}
val app = startKoin { modules(module) }
useCase = SendEventUseCase(pulseService, logger, bundleId)
wcKoinApp = app

val props = Props(type = "testEvent")
val sdkType = SDKType.WEB3MODAL
val event = Event(props = props, bundleId = bundleId)
Expand All @@ -82,6 +83,14 @@ class SendEventUseCaseTest : KoinTest {
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun `send should log error when analytics is enabled and response is unsuccessful`() = runTest(testDispatcher) {
stopKoin()
val module: Module = module {
single(named(AndroidCommonDITags.ENABLE_WEB_3_MODAL_ANALYTICS)) { true }
}
val app = startKoin { modules(module) }
useCase = SendEventUseCase(pulseService, logger, bundleId)
wcKoinApp = app

val props = Props(type = "testEvent")
val sdkType = SDKType.WEB3MODAL
val event = Event(props = props, bundleId = bundleId)
Expand All @@ -100,6 +109,14 @@ class SendEventUseCaseTest : KoinTest {
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun `send should log exception when analytics is enabled and an exception occurs`() = runTest(testDispatcher) {
stopKoin()
val module: Module = module {
single(named(AndroidCommonDITags.ENABLE_WEB_3_MODAL_ANALYTICS)) { true }
}
val app = startKoin { modules(module) }
useCase = SendEventUseCase(pulseService, logger, bundleId)
wcKoinApp = app

val props = Props(type = "testEvent")
val sdkType = SDKType.WEB3MODAL
val event = Event(props = props, bundleId = bundleId)
Expand Down
Loading

0 comments on commit 7cdd52c

Please sign in to comment.