From 0c6a6afe74c25a75cc3bafb19b68a742b600a4d5 Mon Sep 17 00:00:00 2001 From: Christian Melchior Date: Wed, 23 Aug 2023 11:36:52 +0200 Subject: [PATCH] Rework sync exceptions based on new error codes. --- CHANGELOG.md | 3 +- .../realm/kotlin/test/sync/SyncEnumTests.kt | 35 +++--- .../realm/kotlin/internal/interop/Callback.kt | 3 +- .../kotlin/internal/interop/CoreError.kt | 68 ++++++++++++ .../internal/interop/CoreErrorConverter.kt | 6 +- .../kotlin/internal/interop/ErrorCategory.kt | 3 +- .../kotlin/internal/interop/ErrorCode.kt | 20 +++- .../kotlin/internal/interop/RealmInterop.kt | 11 +- .../interop/sync/ProtocolErrorCode.kt | 90 ++++++++-------- .../kotlin/internal/interop/sync/SyncError.kt | 17 ++- .../internal/interop/sync/SyncErrorCode.kt | 55 ---------- .../interop/sync/SyncErrorCodeCategory.kt | 36 ------- .../kotlin/internal/interop/ErrorCategory.kt | 3 +- .../kotlin/internal/interop/ErrorCode.kt | 22 +++- .../kotlin/internal/interop/RealmInterop.kt | 14 +-- ...VMSyncSessionTransferCompletionCallback.kt | 5 +- .../interop/sync/ProtocolErrorCode.kt | 96 ++++++++--------- .../interop/sync/SyncErrorCodeCategory.kt | 37 ------- packages/cinterop/src/native/realm.def | 2 +- .../kotlin/internal/interop/ErrorCategory.kt | 3 +- .../kotlin/internal/interop/ErrorCode.kt | 28 +++-- .../kotlin/internal/interop/RealmInterop.kt | 44 +++----- .../interop/sync/ProtocolErrorCode.kt | 96 ++++++++--------- .../interop/sync/SyncErrorCodeCategory.kt | 40 ------- packages/external/core | 2 +- .../src/main/jni/realm_api_helpers.cpp | 21 ++-- .../src/main/jni/realm_api_helpers.h | 2 +- .../kotlin/mongodb/internal/RealmSyncUtils.kt | 100 +++++------------- .../mongodb/internal/SyncSessionImpl.kt | 15 ++- .../common/SyncClientResetIntegrationTests.kt | 43 ++------ .../common/internal/RealmSyncUtilsTest.kt | 93 +++++++++------- 31 files changed, 424 insertions(+), 589 deletions(-) create mode 100644 packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/CoreError.kt delete mode 100644 packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCode.kt delete mode 100644 packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCodeCategory.kt delete mode 100644 packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCodeCategory.kt delete mode 100644 packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCodeCategory.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index e0380bda7c..a73832bba9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ childA == childC ``` ### Enhancements +* Fulltext queries now support prefix search by using the * operator, like `description TEXT 'alex*'`. (Core issue [#6860](https://github.com/realm/realm-core/issues/6860)) * Realm model classes now generate custom `toString`, `equals` and `hashCode` implementations. This makes it possible to compare by object reference across multiple collections. Note that two objects at different versions will not be considered equal, even if the content is the same. Custom implementations of these methods will be respected if they are present. (Issue [#1097](https://github.com/realm/realm-kotlin/issues/1097)) * Support for performing geospatial queries using the new classes: `GeoPoint`, `GeoCircle`, `GeoBox`, and `GeoPolygon`. See `GeoPoint` documentation on how to persist locations. (Issue [#1403](https://github.com/realm/realm-kotlin/pull/1403)) @@ -46,7 +47,7 @@ if the content is the same. Custom implementations of these methods will be resp * Minimum Android SDK: 16. ### Internal -* None. +* Updated to Realm Core 13.18.0, commit 48d6d672cb30f86976ba19a44ffffe25ed447128. ## 1.10.2 (2023-07-21) diff --git a/packages/cinterop/src/androidInstrumentedTest/kotlin/io/realm/kotlin/test/sync/SyncEnumTests.kt b/packages/cinterop/src/androidInstrumentedTest/kotlin/io/realm/kotlin/test/sync/SyncEnumTests.kt index 4f9490dbe9..1effc3cd32 100644 --- a/packages/cinterop/src/androidInstrumentedTest/kotlin/io/realm/kotlin/test/sync/SyncEnumTests.kt +++ b/packages/cinterop/src/androidInstrumentedTest/kotlin/io/realm/kotlin/test/sync/SyncEnumTests.kt @@ -16,6 +16,7 @@ package io.realm.kotlin.test.sync +import io.realm.kotlin.internal.interop.CategoryFlags import io.realm.kotlin.internal.interop.ErrorCategory import io.realm.kotlin.internal.interop.ErrorCode import io.realm.kotlin.internal.interop.realm_auth_provider_e @@ -23,23 +24,21 @@ import io.realm.kotlin.internal.interop.realm_errno_e import io.realm.kotlin.internal.interop.realm_error_category_e import io.realm.kotlin.internal.interop.realm_sync_client_metadata_mode_e import io.realm.kotlin.internal.interop.realm_sync_connection_state_e -import io.realm.kotlin.internal.interop.realm_sync_errno_client_e import io.realm.kotlin.internal.interop.realm_sync_errno_connection_e import io.realm.kotlin.internal.interop.realm_sync_errno_session_e -import io.realm.kotlin.internal.interop.realm_sync_error_category_e import io.realm.kotlin.internal.interop.realm_sync_session_resync_mode_e import io.realm.kotlin.internal.interop.realm_sync_session_state_e import io.realm.kotlin.internal.interop.realm_user_state_e +import io.realm.kotlin.internal.interop.realm_web_socket_errno_e import io.realm.kotlin.internal.interop.sync.AuthProvider import io.realm.kotlin.internal.interop.sync.CoreConnectionState import io.realm.kotlin.internal.interop.sync.CoreSyncSessionState import io.realm.kotlin.internal.interop.sync.CoreUserState import io.realm.kotlin.internal.interop.sync.MetadataMode -import io.realm.kotlin.internal.interop.sync.ProtocolClientErrorCode -import io.realm.kotlin.internal.interop.sync.ProtocolConnectionErrorCode -import io.realm.kotlin.internal.interop.sync.ProtocolSessionErrorCode -import io.realm.kotlin.internal.interop.sync.SyncErrorCodeCategory +import io.realm.kotlin.internal.interop.sync.SyncConnectionErrorCode +import io.realm.kotlin.internal.interop.sync.SyncSessionErrorCode import io.realm.kotlin.internal.interop.sync.SyncSessionResyncMode +import io.realm.kotlin.internal.interop.sync.WebsocketErrorCode import org.junit.Test import kotlin.reflect.KClass import kotlin.test.BeforeTest @@ -59,10 +58,11 @@ class SyncEnumTests { } @Test - fun appErrorCategory() { + fun errorCategory() { checkEnum(realm_error_category_e::class) { nativeValue -> ErrorCategory.of(nativeValue) } + assertEquals(ErrorCategory.values().size, CategoryFlags.CATEGORY_ORDER.size) } @Test @@ -94,30 +94,23 @@ class SyncEnumTests { } @Test - fun protocolClientErrorCode() { - checkEnum(realm_sync_errno_client_e::class) { nativeValue -> - ProtocolClientErrorCode.of(nativeValue) - } - } - - @Test - fun protocolConnectionErrorCode() { + fun syncConnectionErrorCode() { checkEnum(realm_sync_errno_connection_e::class) { nativeValue -> - ProtocolConnectionErrorCode.of(nativeValue) + SyncConnectionErrorCode.of(nativeValue) } } @Test - fun protocolSessionErrorCode() { + fun syncSessionErrorCode() { checkEnum(realm_sync_errno_session_e::class) { nativeValue -> - ProtocolSessionErrorCode.of(nativeValue) + SyncSessionErrorCode.of(nativeValue) } } @Test - fun syncErrorCodeCategory() { - checkEnum(realm_sync_error_category_e::class) { nativeValue -> - SyncErrorCodeCategory.of(nativeValue) + fun websocketErrorCode() { + checkEnum(realm_web_socket_errno_e::class) { nativeValue -> + WebsocketErrorCode.of(nativeValue) } } diff --git a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/Callback.kt b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/Callback.kt index b8534d0b67..4d262f206d 100644 --- a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/Callback.kt +++ b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/Callback.kt @@ -19,7 +19,6 @@ package io.realm.kotlin.internal.interop import io.realm.kotlin.internal.interop.sync.AppError import io.realm.kotlin.internal.interop.sync.CoreSubscriptionSetState import io.realm.kotlin.internal.interop.sync.SyncError -import io.realm.kotlin.internal.interop.sync.SyncErrorCode // TODO Could be replace by lambda. See realm_app_config_new networkTransportFactory for example. interface Callback { @@ -39,7 +38,7 @@ fun interface SyncErrorCallback { // Interface exposed towards `library-sync` interface SyncSessionTransferCompletionCallback { - fun invoke(error: SyncErrorCode?) + fun invoke(error: CoreError?) } interface LogCallback { diff --git a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/CoreError.kt b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/CoreError.kt new file mode 100644 index 0000000000..0e6821cba1 --- /dev/null +++ b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/CoreError.kt @@ -0,0 +1,68 @@ +package io.realm.kotlin.internal.interop + +/** + * Wrapper for C-API `realm_error_t`. + * See https://github.com/realm/realm-core/blob/master/src/realm.h#L231 + */ +class CoreError( + categoriesNativeValue: Int, + val errorCodeNativeValue: Int, + messageNativeValue: String?, + path: String, + userError: Throwable? +) { + val categories: CategoryFlags = CategoryFlags((categoriesNativeValue)) + val errorCode: ErrorCode? = ErrorCode.of(errorCodeNativeValue) + val message = messageNativeValue + val realmPath: String = path + val userError: Throwable? = userError + + operator fun contains(category: ErrorCategory): Boolean = category in categories +} + +data class CategoryFlags(val categoryFlags: Int) { + + companion object { + /** + * See error code mapping to categories here: + * https://github.com/realm/realm-core/blob/master/src/realm/error_codes.cpp#L29 + * + * In most cases, only 1 category is assigned, but some errors have multiple. So instead of + * overwhelming the user with many categories, we only select the most important to show + * in the error message. "important" is of course tricky to define, but generally + * we consider vague categories like [ErrorCategory.RLM_ERR_CAT_RUNTIME] as less important + * than more specific ones like [ErrorCategory.RLM_ERR_CAT_JSON_ERROR]. + * + * In the current implementation, categories between index 0 and 7 are considered equal + * and the order is somewhat arbitrary. No error codes has multiple of these categories + * associated either. + */ + val CATEGORY_ORDER: List = listOf( + ErrorCategory.RLM_ERR_CAT_CUSTOM_ERROR, + ErrorCategory.RLM_ERR_CAT_WEBSOCKET_ERROR, + ErrorCategory.RLM_ERR_CAT_SERVICE_ERROR, + ErrorCategory.RLM_ERR_CAT_JSON_ERROR, + ErrorCategory.RLM_ERR_CAT_CLIENT_ERROR, + ErrorCategory.RLM_ERR_CAT_SYSTEM_ERROR, + ErrorCategory.RLM_ERR_CAT_FILE_ACCESS, + ErrorCategory.RLM_ERR_CAT_HTTP_ERROR, + ErrorCategory.RLM_ERR_CAT_INVALID_ARG, + ErrorCategory.RLM_ERR_CAT_APP_ERROR, + ErrorCategory.RLM_ERR_CAT_LOGIC, + ErrorCategory.RLM_ERR_CAT_RUNTIME, + ) + } + + /** + * Returns a description of the most important category defined in [categoryFlags]. + * If no known categories are found, "Unknown[categoryFlags]" is returned. + */ + val description: String = CATEGORY_ORDER.firstOrNull { category -> + category in this + }?.description ?: "$categoryFlags" + + /** + * Check whether a given [ErrorCategory] is included in the [categoryFlags]. + */ + operator fun contains(category: ErrorCategory): Boolean = (categoryFlags and category.nativeValue) != 0 +} diff --git a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/CoreErrorConverter.kt b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/CoreErrorConverter.kt index fddf363cdf..36174fb949 100644 --- a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/CoreErrorConverter.kt +++ b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/CoreErrorConverter.kt @@ -31,7 +31,7 @@ object CoreErrorConverter { path: String?, userError: Throwable? ): Throwable { - val categories: CategoryFlag = CategoryFlag(categoriesNativeValue) + val categories: CategoryFlags = CategoryFlags(categoriesNativeValue) val errorCode: ErrorCode? = ErrorCode.of(errorCodeNativeValue) val message: String = "[$errorCode]: $messageNativeValue" @@ -45,8 +45,4 @@ object CoreErrorConverter { else -> Error(message) // This can happen when propagating user level exceptions. } } - - data class CategoryFlag(val categoryCode: Int) { - operator fun contains(other: ErrorCategory): Boolean = categoryCode and other.nativeValue != 0 - } } diff --git a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/ErrorCategory.kt b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/ErrorCategory.kt index fb1716377d..53053fc1da 100644 --- a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/ErrorCategory.kt +++ b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/ErrorCategory.kt @@ -32,7 +32,8 @@ expect enum class ErrorCategory : CodeDescription { RLM_ERR_CAT_SERVICE_ERROR, RLM_ERR_CAT_HTTP_ERROR, RLM_ERR_CAT_CUSTOM_ERROR, - RLM_ERR_CAT_WEBSOCKET_ERROR; + RLM_ERR_CAT_WEBSOCKET_ERROR, + RLM_ERR_CAT_SYNC_ERROR; companion object { internal fun of(nativeValue: Int): ErrorCategory? diff --git a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/ErrorCode.kt b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/ErrorCode.kt index 13138a5605..b4d95acbf2 100644 --- a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/ErrorCode.kt +++ b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/ErrorCode.kt @@ -50,6 +50,22 @@ expect enum class ErrorCode : CodeDescription { RLM_ERR_SCHEMA_VERSION_MISMATCH, RLM_ERR_NO_SUBSCRIPTION_FOR_WRITE, RLM_ERR_OPERATION_ABORTED, + RLM_ERR_AUTO_CLIENT_RESET_FAILED, + RLM_ERR_BAD_SYNC_PARTITION_VALUE, + RLM_ERR_CONNECTION_CLOSED, + RLM_ERR_INVALID_SUBSCRIPTION_QUERY, + RLM_ERR_SYNC_CLIENT_RESET_REQUIRED, + RLM_ERR_SYNC_COMPENSATING_WRITE, + RLM_ERR_SYNC_CONNECT_FAILED, + RLM_ERR_SYNC_INVALID_SCHEMA_CHANGE, + RLM_ERR_SYNC_PERMISSION_DENIED, + RLM_ERR_SYNC_PROTOCOL_INVARIANT_FAILED, + RLM_ERR_SYNC_PROTOCOL_NEGOTIATION_FAILED, + RLM_ERR_SYNC_SERVER_PERMISSIONS_CHANGED, + RLM_ERR_SYNC_USER_MISMATCH, + RLM_ERR_TLS_HANDSHAKE_FAILED, + RLM_ERR_WRONG_SYNC_TYPE, + RLM_ERR_SYNC_WRITE_NOT_ALLOWED, RLM_ERR_SYSTEM_ERROR, RLM_ERR_LOGIC, RLM_ERR_NOT_SUPPORTED, @@ -162,9 +178,7 @@ expect enum class ErrorCode : CodeDescription { RLM_ERR_MAINTENANCE_IN_PROGRESS, RLM_ERR_USERPASS_TOKEN_INVALID, RLM_ERR_INVALID_SERVER_RESPONSE, - RLM_ERR_WEBSOCKET_RESOLVE_FAILED_ERROR, - RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_CLIENT_ERROR, - RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_SERVER_ERROR, + REALM_ERR_APP_SERVER_ERROR, RLM_ERR_CALLBACK, RLM_ERR_UNKNOWN; diff --git a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt index 33332f2450..731a6a1e57 100644 --- a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt +++ b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt @@ -27,8 +27,6 @@ import io.realm.kotlin.internal.interop.sync.CoreUserState import io.realm.kotlin.internal.interop.sync.MetadataMode import io.realm.kotlin.internal.interop.sync.NetworkTransport import io.realm.kotlin.internal.interop.sync.ProgressDirection -import io.realm.kotlin.internal.interop.sync.ProtocolClientErrorCode -import io.realm.kotlin.internal.interop.sync.SyncErrorCodeCategory import io.realm.kotlin.internal.interop.sync.SyncSessionResyncMode import io.realm.kotlin.internal.interop.sync.SyncUserIdentity import kotlinx.coroutines.CoroutineDispatcher @@ -127,8 +125,6 @@ typealias RealmMutableSubscriptionSetPointer = NativePointer ) : this( - SyncErrorCode.newInstance(category, value, message), - detailedMessage, + CoreError(categoryFlags, value, message, path, null), originalFilePath, recoveryFilePath, isFatal, diff --git a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCode.kt b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCode.kt deleted file mode 100644 index 93a9b78052..0000000000 --- a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCode.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2022 Realm Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.realm.kotlin.internal.interop.sync - -import io.realm.kotlin.internal.interop.CodeDescription -import io.realm.kotlin.internal.interop.UnknownCodeDescription - -/** - * Wrapper for C-API `realm_sync_error_code`. - * See https://github.com/realm/realm-core/blob/master/src/realm.h#L3306 - */ -data class SyncErrorCode internal constructor( - val category: CodeDescription, - val code: CodeDescription, - val message: String -) { - companion object { - fun newInstance( - categoryCode: Int, - errorCode: Int, - message: String - ): SyncErrorCode { - val category = SyncErrorCodeCategory.of(categoryCode) ?: UnknownCodeDescription(categoryCode) - - val code: CodeDescription = when (category) { - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_CLIENT -> ProtocolClientErrorCode.of(errorCode) - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_CONNECTION -> ProtocolConnectionErrorCode.of(errorCode) - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_SESSION -> ProtocolSessionErrorCode.of(errorCode) - // SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_SYSTEM -> // no mapping available - // SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_UNKNOWN -> // no mapping available - else -> null - } ?: UnknownCodeDescription(errorCode) - - return SyncErrorCode( - category, - code, - message - ) - } - } -} diff --git a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCodeCategory.kt b/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCodeCategory.kt deleted file mode 100644 index 049e3fbd1b..0000000000 --- a/packages/cinterop/src/commonMain/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCodeCategory.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2022 Realm Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.realm.kotlin.internal.interop.sync - -import io.realm.kotlin.internal.interop.CodeDescription - -/** - * Wrapper for C-API `realm_sync_error_category`. - * See https://github.com/realm/realm-core/blob/master/src/realm.h#L3198 - */ -expect enum class SyncErrorCodeCategory : CodeDescription { - RLM_SYNC_ERROR_CATEGORY_CLIENT, - RLM_SYNC_ERROR_CATEGORY_CONNECTION, - RLM_SYNC_ERROR_CATEGORY_SESSION, - RLM_SYNC_ERROR_CATEGORY_WEBSOCKET, - RLM_SYNC_ERROR_CATEGORY_SYSTEM, - RLM_SYNC_ERROR_CATEGORY_UNKNOWN; - - companion object { - internal fun of(nativeValue: Int): SyncErrorCodeCategory? - } -} diff --git a/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/ErrorCategory.kt b/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/ErrorCategory.kt index 423f657111..5319d0bc90 100644 --- a/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/ErrorCategory.kt +++ b/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/ErrorCategory.kt @@ -31,7 +31,8 @@ actual enum class ErrorCategory( RLM_ERR_CAT_SERVICE_ERROR("Service", realm_error_category_e.RLM_ERR_CAT_SERVICE_ERROR), RLM_ERR_CAT_HTTP_ERROR("Http", realm_error_category_e.RLM_ERR_CAT_HTTP_ERROR), RLM_ERR_CAT_CUSTOM_ERROR("Custom", realm_error_category_e.RLM_ERR_CAT_CUSTOM_ERROR), - RLM_ERR_CAT_WEBSOCKET_ERROR("Websocket", realm_error_category_e.RLM_ERR_CAT_WEBSOCKET_ERROR); + RLM_ERR_CAT_WEBSOCKET_ERROR("Websocket", realm_error_category_e.RLM_ERR_CAT_WEBSOCKET_ERROR), + RLM_ERR_CAT_SYNC_ERROR("Sync", realm_error_category_e.RLM_ERR_CAT_SYNC_ERROR); actual companion object { internal actual fun of(nativeValue: Int): ErrorCategory? = diff --git a/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/ErrorCode.kt b/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/ErrorCode.kt index 935354e9cb..36bcd30327 100644 --- a/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/ErrorCode.kt +++ b/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/ErrorCode.kt @@ -47,6 +47,22 @@ actual enum class ErrorCode(override val description: String, override val nativ RLM_ERR_SCHEMA_VERSION_MISMATCH("SchemaVersionMismatch", realm_errno_e.RLM_ERR_SCHEMA_VERSION_MISMATCH), RLM_ERR_NO_SUBSCRIPTION_FOR_WRITE("NoSubscriptionForWrite", realm_errno_e.RLM_ERR_NO_SUBSCRIPTION_FOR_WRITE), RLM_ERR_OPERATION_ABORTED("OperationAborted", realm_errno_e.RLM_ERR_OPERATION_ABORTED), + RLM_ERR_AUTO_CLIENT_RESET_FAILED("AutoClientResetFailed", realm_errno_e.RLM_ERR_AUTO_CLIENT_RESET_FAILED), + RLM_ERR_BAD_SYNC_PARTITION_VALUE("BadSyncPartitionValue", realm_errno_e.RLM_ERR_BAD_SYNC_PARTITION_VALUE), + RLM_ERR_CONNECTION_CLOSED("ConnectionClosed", realm_errno_e.RLM_ERR_CONNECTION_CLOSED), + RLM_ERR_INVALID_SUBSCRIPTION_QUERY("InvalidSubscriptionQuery", realm_errno_e.RLM_ERR_INVALID_SUBSCRIPTION_QUERY), + RLM_ERR_SYNC_CLIENT_RESET_REQUIRED("SyncClientResetRequired", realm_errno_e.RLM_ERR_SYNC_CLIENT_RESET_REQUIRED), + RLM_ERR_SYNC_COMPENSATING_WRITE("CompensatingWrite", realm_errno_e.RLM_ERR_SYNC_COMPENSATING_WRITE), + RLM_ERR_SYNC_CONNECT_FAILED("SyncConnectFailed", realm_errno_e.RLM_ERR_SYNC_CONNECT_FAILED), + RLM_ERR_SYNC_INVALID_SCHEMA_CHANGE("SyncInvalidSchemaChange", realm_errno_e.RLM_ERR_SYNC_INVALID_SCHEMA_CHANGE), + RLM_ERR_SYNC_PERMISSION_DENIED("SyncPermissionDenied", realm_errno_e.RLM_ERR_SYNC_PERMISSION_DENIED), + RLM_ERR_SYNC_PROTOCOL_INVARIANT_FAILED("SyncProtocolInvariantFailed", realm_errno_e.RLM_ERR_SYNC_PROTOCOL_INVARIANT_FAILED), + RLM_ERR_SYNC_PROTOCOL_NEGOTIATION_FAILED("SyncProtocolNegotiationFailed", realm_errno_e.RLM_ERR_SYNC_PROTOCOL_NEGOTIATION_FAILED), + RLM_ERR_SYNC_SERVER_PERMISSIONS_CHANGED("SyncServerPermissionsChanged", realm_errno_e.RLM_ERR_SYNC_SERVER_PERMISSIONS_CHANGED), + RLM_ERR_SYNC_USER_MISMATCH("SyncUserMismatch", realm_errno_e.RLM_ERR_SYNC_USER_MISMATCH), + RLM_ERR_TLS_HANDSHAKE_FAILED("TLSHandshakeFailed", realm_errno_e.RLM_ERR_TLS_HANDSHAKE_FAILED), + RLM_ERR_WRONG_SYNC_TYPE("WrongSyncType", realm_errno_e.RLM_ERR_WRONG_SYNC_TYPE), + RLM_ERR_SYNC_WRITE_NOT_ALLOWED("SyncWriteNotAllowed", realm_errno_e.RLM_ERR_SYNC_WRITE_NOT_ALLOWED), RLM_ERR_SYSTEM_ERROR("SystemError", realm_errno_e.RLM_ERR_SYSTEM_ERROR), RLM_ERR_LOGIC("Logic", realm_errno_e.RLM_ERR_LOGIC), RLM_ERR_NOT_SUPPORTED("NotSupported", realm_errno_e.RLM_ERR_NOT_SUPPORTED), @@ -118,7 +134,7 @@ actual enum class ErrorCode(override val description: String, override val nativ RLM_ERR_MONGODB_ERROR("MongodbError", realm_errno_e.RLM_ERR_MONGODB_ERROR), RLM_ERR_ARGUMENTS_NOT_ALLOWED("ArgumentsNotAllowed", realm_errno_e.RLM_ERR_ARGUMENTS_NOT_ALLOWED), RLM_ERR_FUNCTION_EXECUTION_ERROR("FunctionExecutionError", realm_errno_e.RLM_ERR_FUNCTION_EXECUTION_ERROR), - RLM_ERR_NO_MATCHING_RULE("NoMatchingRule", realm_errno_e.RLM_ERR_NO_MATCHING_RULE), + RLM_ERR_NO_MATCHING_RULE("NoMatchingRule", realm_errno_e.RLM_ERR_NO_MATCHING_RULE_FOUND), RLM_ERR_INTERNAL_SERVER_ERROR("InternalServerError", realm_errno_e.RLM_ERR_INTERNAL_SERVER_ERROR), RLM_ERR_AUTH_PROVIDER_NOT_FOUND("AuthProviderNotFound", realm_errno_e.RLM_ERR_AUTH_PROVIDER_NOT_FOUND), RLM_ERR_AUTH_PROVIDER_ALREADY_EXISTS("AuthProviderAlreadyExists", realm_errno_e.RLM_ERR_AUTH_PROVIDER_ALREADY_EXISTS), @@ -159,9 +175,7 @@ actual enum class ErrorCode(override val description: String, override val nativ RLM_ERR_MAINTENANCE_IN_PROGRESS("MaintenanceInProgress", realm_errno_e.RLM_ERR_MAINTENANCE_IN_PROGRESS), RLM_ERR_USERPASS_TOKEN_INVALID("UserpassTokenInvalid", realm_errno_e.RLM_ERR_USERPASS_TOKEN_INVALID), RLM_ERR_INVALID_SERVER_RESPONSE("InvalidServerResponse", realm_errno_e.RLM_ERR_INVALID_SERVER_RESPONSE), - RLM_ERR_WEBSOCKET_RESOLVE_FAILED_ERROR("ResolveFailedError", realm_errno_e.RLM_ERR_WEBSOCKET_RESOLVE_FAILED_ERROR), - RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_CLIENT_ERROR("ConnectionClosedClientError", realm_errno_e.RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_CLIENT_ERROR), - RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_SERVER_ERROR("ConnectionClosedServerError", realm_errno_e.RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_SERVER_ERROR), + REALM_ERR_APP_SERVER_ERROR("AppServerError", realm_errno_e.RLM_ERR_APP_SERVER_ERROR), RLM_ERR_CALLBACK("Callback", realm_errno_e.RLM_ERR_CALLBACK), RLM_ERR_UNKNOWN("Unknown", realm_errno_e.RLM_ERR_UNKNOWN); diff --git a/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt b/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt index 88b254ca0b..35a6a7e8b2 100644 --- a/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt +++ b/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt @@ -27,8 +27,6 @@ import io.realm.kotlin.internal.interop.sync.JVMSyncSessionTransferCompletionCal import io.realm.kotlin.internal.interop.sync.MetadataMode import io.realm.kotlin.internal.interop.sync.NetworkTransport import io.realm.kotlin.internal.interop.sync.ProgressDirection -import io.realm.kotlin.internal.interop.sync.ProtocolClientErrorCode -import io.realm.kotlin.internal.interop.sync.SyncErrorCodeCategory import io.realm.kotlin.internal.interop.sync.SyncSessionResyncMode import io.realm.kotlin.internal.interop.sync.SyncUserIdentity import kotlinx.coroutines.CoroutineDispatcher @@ -1340,15 +1338,13 @@ actual object RealmInterop { actual fun realm_sync_session_handle_error_for_testing( syncSession: RealmSyncSessionPointer, - errorCode: ProtocolClientErrorCode, - category: SyncErrorCodeCategory, + error: ErrorCode, errorMessage: String, isFatal: Boolean ) { realmc.realm_sync_session_handle_error_for_testing( syncSession.cptr(), - errorCode.nativeValue, - category.nativeValue, + error.nativeValue, errorMessage, isFatal ) @@ -1396,12 +1392,6 @@ actual object RealmInterop { baseUrl?.let { realmc.realm_app_config_set_base_url(config, it) } // Sync Connection Parameters - connectionParams.localAppName?.let { appName -> - realmc.realm_app_config_set_local_app_name(config, appName) - } - connectionParams.localAppVersion?.let { appVersion -> - realmc.realm_app_config_set_local_app_name(config, appVersion) - } realmc.realm_app_config_set_sdk(config, connectionParams.sdkName) realmc.realm_app_config_set_sdk_version(config, connectionParams.sdkVersion) realmc.realm_app_config_set_platform_version(config, connectionParams.platformVersion) diff --git a/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/sync/JVMSyncSessionTransferCompletionCallback.kt b/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/sync/JVMSyncSessionTransferCompletionCallback.kt index d06b775d09..94df1f403e 100644 --- a/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/sync/JVMSyncSessionTransferCompletionCallback.kt +++ b/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/sync/JVMSyncSessionTransferCompletionCallback.kt @@ -16,6 +16,7 @@ package io.realm.kotlin.internal.interop.sync +import io.realm.kotlin.internal.interop.CoreError import io.realm.kotlin.internal.interop.SyncSessionTransferCompletionCallback // Interface used internally as a bridge between Kotlin (JVM) and JNI. @@ -28,7 +29,7 @@ internal class JVMSyncSessionTransferCompletionCallback( fun onSuccess() { callback.invoke(null) } - fun onError(category: Int, value: Int, message: String) { - callback.invoke(SyncErrorCode.newInstance(category, value, message)) + fun onError(categoryFlags: Int, value: Int, message: String, path: String) { + callback.invoke(CoreError(categoryFlags, value, message, path, null)) } } diff --git a/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/sync/ProtocolErrorCode.kt b/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/sync/ProtocolErrorCode.kt index bfc9f20ec5..8ba8028fa8 100644 --- a/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/sync/ProtocolErrorCode.kt +++ b/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/sync/ProtocolErrorCode.kt @@ -17,55 +17,11 @@ package io.realm.kotlin.internal.interop.sync import io.realm.kotlin.internal.interop.CodeDescription -import io.realm.kotlin.internal.interop.realm_sync_errno_client_e import io.realm.kotlin.internal.interop.realm_sync_errno_connection_e import io.realm.kotlin.internal.interop.realm_sync_errno_session_e +import io.realm.kotlin.internal.interop.realm_web_socket_errno_e -actual enum class ProtocolClientErrorCode( - override val description: String, - override val nativeValue: Int -) : CodeDescription { - RLM_SYNC_ERR_CLIENT_CONNECTION_CLOSED("ConnectionClosed", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_CONNECTION_CLOSED), - RLM_SYNC_ERR_CLIENT_UNKNOWN_MESSAGE("UnknownMessage", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_UNKNOWN_MESSAGE), - RLM_SYNC_ERR_CLIENT_BAD_SYNTAX("BadSyntax", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_SYNTAX), - RLM_SYNC_ERR_CLIENT_LIMITS_EXCEEDED("LimitsExceeded", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_LIMITS_EXCEEDED), - RLM_SYNC_ERR_CLIENT_BAD_SESSION_IDENT("BadSessionIdent", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_SESSION_IDENT), - RLM_SYNC_ERR_CLIENT_BAD_MESSAGE_ORDER("BadMessageOrder", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_MESSAGE_ORDER), - RLM_SYNC_ERR_CLIENT_BAD_CLIENT_FILE_IDENT("BadClientFileIdent", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_CLIENT_FILE_IDENT), - RLM_SYNC_ERR_CLIENT_BAD_PROGRESS("BadProgress", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_PROGRESS), - RLM_SYNC_ERR_CLIENT_BAD_CHANGESET_HEADER_SYNTAX("BadChangesetHeaderSyntax", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_CHANGESET_HEADER_SYNTAX), - RLM_SYNC_ERR_CLIENT_BAD_CHANGESET_SIZE("BadChangesetSize", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_CHANGESET_SIZE), - RLM_SYNC_ERR_CLIENT_BAD_ORIGIN_FILE_IDENT("BadOriginFileIdent", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_ORIGIN_FILE_IDENT), - RLM_SYNC_ERR_CLIENT_BAD_SERVER_VERSION("BadServerVersion", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_SERVER_VERSION), - RLM_SYNC_ERR_CLIENT_BAD_CHANGESET("BadChangeset", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_CHANGESET), - RLM_SYNC_ERR_CLIENT_BAD_REQUEST_IDENT("BadRequestIdent", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_REQUEST_IDENT), - RLM_SYNC_ERR_CLIENT_BAD_ERROR_CODE("BadErrorCode", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_ERROR_CODE), - RLM_SYNC_ERR_CLIENT_BAD_COMPRESSION("BadCompression", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_COMPRESSION), - RLM_SYNC_ERR_CLIENT_BAD_CLIENT_VERSION("BadClientVersion", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_CLIENT_VERSION), - RLM_SYNC_ERR_CLIENT_SSL_SERVER_CERT_REJECTED("SslServerCertRejected", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_SSL_SERVER_CERT_REJECTED), - RLM_SYNC_ERR_CLIENT_PONG_TIMEOUT("PongTimeout", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_PONG_TIMEOUT), - RLM_SYNC_ERR_CLIENT_BAD_CLIENT_FILE_IDENT_SALT("BadClientFileIdentSalt", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_CLIENT_FILE_IDENT_SALT), - RLM_SYNC_ERR_CLIENT_BAD_FILE_IDENT("BadFileIdent", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_FILE_IDENT), - RLM_SYNC_ERR_CLIENT_CONNECT_TIMEOUT("ConnectTimeout", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_CONNECT_TIMEOUT), - RLM_SYNC_ERR_CLIENT_BAD_TIMESTAMP("BadTimestamp", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_TIMESTAMP), - RLM_SYNC_ERR_CLIENT_BAD_PROTOCOL_FROM_SERVER("BadProtocolFromServer", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_PROTOCOL_FROM_SERVER), - RLM_SYNC_ERR_CLIENT_CLIENT_TOO_OLD_FOR_SERVER("ClientTooOldForServer", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_CLIENT_TOO_OLD_FOR_SERVER), - RLM_SYNC_ERR_CLIENT_CLIENT_TOO_NEW_FOR_SERVER("ClientTooNewForServer", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_CLIENT_TOO_NEW_FOR_SERVER), - RLM_SYNC_ERR_CLIENT_PROTOCOL_MISMATCH("ProtocolMismatch", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_PROTOCOL_MISMATCH), - RLM_SYNC_ERR_CLIENT_BAD_STATE_MESSAGE("BadStateMessage", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_BAD_STATE_MESSAGE), - RLM_SYNC_ERR_CLIENT_MISSING_PROTOCOL_FEATURE("MissingProtocolFeature", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_MISSING_PROTOCOL_FEATURE), - RLM_SYNC_ERR_CLIENT_HTTP_TUNNEL_FAILED("HttpTunnelFailed", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_HTTP_TUNNEL_FAILED), - RLM_SYNC_ERR_CLIENT_AUTO_CLIENT_RESET_FAILURE("AutoClientResetFailure", realm_sync_errno_client_e.RLM_SYNC_ERR_CLIENT_AUTO_CLIENT_RESET_FAILURE); - - actual companion object { - internal actual fun of(nativeValue: Int): ProtocolClientErrorCode? = - values().firstOrNull { value -> - value.nativeValue == nativeValue - } - } -} - -actual enum class ProtocolConnectionErrorCode( +actual enum class SyncConnectionErrorCode( override val description: String, override val nativeValue: Int ) : CodeDescription { @@ -74,7 +30,7 @@ actual enum class ProtocolConnectionErrorCode( RLM_SYNC_ERR_CONNECTION_UNKNOWN_MESSAGE("UnknownMessage", realm_sync_errno_connection_e.RLM_SYNC_ERR_CONNECTION_UNKNOWN_MESSAGE), RLM_SYNC_ERR_CONNECTION_BAD_SYNTAX("BadSyntax", realm_sync_errno_connection_e.RLM_SYNC_ERR_CONNECTION_BAD_SYNTAX), RLM_SYNC_ERR_CONNECTION_LIMITS_EXCEEDED("LimitsExceeded", realm_sync_errno_connection_e.RLM_SYNC_ERR_CONNECTION_LIMITS_EXCEEDED), - RLM_SYNC_ERR_CONNECTION_WRONG_PROTOCOL_VERSION("WrongProtocolVersion", realm_sync_errno_connection_e.RLM_SYNC_ERR_CONNECTION_WRONG_PROTOCOL_VERSION), + RLM_SYNC_ERR_CONNECTION_WRONG_PROTOCOL_VERSION("WrongBadSyncPartitionValueProtocolVersion", realm_sync_errno_connection_e.RLM_SYNC_ERR_CONNECTION_WRONG_PROTOCOL_VERSION), RLM_SYNC_ERR_CONNECTION_BAD_SESSION_IDENT("BadSessionIdent", realm_sync_errno_connection_e.RLM_SYNC_ERR_CONNECTION_BAD_SESSION_IDENT), RLM_SYNC_ERR_CONNECTION_REUSE_OF_SESSION_IDENT("ReuseOfSessionIdent", realm_sync_errno_connection_e.RLM_SYNC_ERR_CONNECTION_REUSE_OF_SESSION_IDENT), RLM_SYNC_ERR_CONNECTION_BOUND_IN_OTHER_SESSION("BoundInOtherSession", realm_sync_errno_connection_e.RLM_SYNC_ERR_CONNECTION_BOUND_IN_OTHER_SESSION), @@ -86,14 +42,14 @@ actual enum class ProtocolConnectionErrorCode( RLM_SYNC_ERR_CONNECTION_SWITCH_TO_PBS("SwitchToPbs", realm_sync_errno_connection_e.RLM_SYNC_ERR_CONNECTION_SWITCH_TO_PBS); actual companion object { - internal actual fun of(nativeValue: Int): ProtocolConnectionErrorCode? = + internal actual fun of(nativeValue: Int): SyncConnectionErrorCode? = values().firstOrNull { value -> value.nativeValue == nativeValue } } } -actual enum class ProtocolSessionErrorCode( +actual enum class SyncSessionErrorCode( override val description: String, override val nativeValue: Int ) : CodeDescription { @@ -133,7 +89,47 @@ actual enum class ProtocolSessionErrorCode( RLM_SYNC_ERR_SESSION_REVERT_TO_PBS("RevertToPartitionBasedSync", realm_sync_errno_session_e.RLM_SYNC_ERR_SESSION_REVERT_TO_PBS); actual companion object { - internal actual fun of(nativeValue: Int): ProtocolSessionErrorCode? = + internal actual fun of(nativeValue: Int): SyncSessionErrorCode? = + values().firstOrNull { value -> + value.nativeValue == nativeValue + } + } +} + +actual enum class WebsocketErrorCode( + override val description: String, + override val nativeValue: Int +) : CodeDescription { + RLM_ERR_WEBSOCKET_OK("Ok", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_OK), + RLM_ERR_WEBSOCKET_GOINGAWAY("GoingAway", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_GOINGAWAY), + RLM_ERR_WEBSOCKET_PROTOCOLERROR("ProtocolError", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_PROTOCOLERROR), + RLM_ERR_WEBSOCKET_UNSUPPORTEDDATA("UnsupportedData", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_UNSUPPORTEDDATA), + RLM_ERR_WEBSOCKET_RESERVED("Reserved", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_RESERVED), + RLM_ERR_WEBSOCKET_NOSTATUSRECEIVED("NoStatusReceived", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_NOSTATUSRECEIVED), + RLM_ERR_WEBSOCKET_ABNORMALCLOSURE("AbnormalClosure", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_ABNORMALCLOSURE), + RLM_ERR_WEBSOCKET_INVALIDPAYLOADDATA("InvalidPayloadData", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_INVALIDPAYLOADDATA), + RLM_ERR_WEBSOCKET_POLICYVIOLATION("PolicyViolation", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_POLICYVIOLATION), + RLM_ERR_WEBSOCKET_MESSAGETOOBIG("MessageToBig", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_MESSAGETOOBIG), + RLM_ERR_WEBSOCKET_INAVALIDEXTENSION("InvalidExtension", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_INAVALIDEXTENSION), + RLM_ERR_WEBSOCKET_INTERNALSERVERERROR("InternalServerError", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_INTERNALSERVERERROR), + RLM_ERR_WEBSOCKET_TLSHANDSHAKEFAILED("TlsHandshakeFailed", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_TLSHANDSHAKEFAILED), + + RLM_ERR_WEBSOCKET_UNAUTHORIZED("Unauthorized", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_UNAUTHORIZED), + RLM_ERR_WEBSOCKET_FORBIDDEN("Forbidden", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_FORBIDDEN), + RLM_ERR_WEBSOCKET_MOVEDPERMANENTLY("MovedPermanently", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_MOVEDPERMANENTLY), + RLM_ERR_WEBSOCKET_CLIENT_TOO_OLD("ClientTooOld", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_CLIENT_TOO_OLD), + RLM_ERR_WEBSOCKET_CLIENT_TOO_NEW("ClientTooNew", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_CLIENT_TOO_NEW), + RLM_ERR_WEBSOCKET_PROTOCOL_MISMATCH("ProtocolMismatch", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_PROTOCOL_MISMATCH), + + RLM_ERR_WEBSOCKET_RESOLVE_FAILED("ResolveFailed", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_RESOLVE_FAILED), + RLM_ERR_WEBSOCKET_CONNECTION_FAILED("ConnectionFailed", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_CONNECTION_FAILED), + RLM_ERR_WEBSOCKET_READ_ERROR("ReadError", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_READ_ERROR), + RLM_ERR_WEBSOCKET_WRITE_ERROR("WriteError", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_WRITE_ERROR), + RLM_ERR_WEBSOCKET_RETRY_ERROR("RetryError", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_RETRY_ERROR), + RLM_ERR_WEBSOCKET_FATAL_ERROR("FatalError", realm_web_socket_errno_e.RLM_ERR_WEBSOCKET_FATAL_ERROR); + + actual companion object { + internal actual fun of(nativeValue: Int): WebsocketErrorCode? = values().firstOrNull { value -> value.nativeValue == nativeValue } diff --git a/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCodeCategory.kt b/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCodeCategory.kt deleted file mode 100644 index 6c66bfbd38..0000000000 --- a/packages/cinterop/src/jvm/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCodeCategory.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2022 Realm Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.realm.kotlin.internal.interop.sync - -import io.realm.kotlin.internal.interop.CodeDescription -import io.realm.kotlin.internal.interop.realm_sync_error_category_e - -actual enum class SyncErrorCodeCategory(override val description: String, override val nativeValue: Int) : - CodeDescription { - RLM_SYNC_ERROR_CATEGORY_CLIENT("Client", realm_sync_error_category_e.RLM_SYNC_ERROR_CATEGORY_CLIENT), - RLM_SYNC_ERROR_CATEGORY_CONNECTION("Connection", realm_sync_error_category_e.RLM_SYNC_ERROR_CATEGORY_CONNECTION), - RLM_SYNC_ERROR_CATEGORY_SESSION("Session", realm_sync_error_category_e.RLM_SYNC_ERROR_CATEGORY_SESSION), - RLM_SYNC_ERROR_CATEGORY_WEBSOCKET("Websocket", realm_sync_error_category_e.RLM_SYNC_ERROR_CATEGORY_WEBSOCKET), - RLM_SYNC_ERROR_CATEGORY_SYSTEM("System", realm_sync_error_category_e.RLM_SYNC_ERROR_CATEGORY_SYSTEM), - RLM_SYNC_ERROR_CATEGORY_UNKNOWN("Unknown", realm_sync_error_category_e.RLM_SYNC_ERROR_CATEGORY_UNKNOWN); - - actual companion object { - internal actual fun of(nativeValue: Int): SyncErrorCodeCategory? = - values().firstOrNull { value -> - value.nativeValue == nativeValue - } - } -} diff --git a/packages/cinterop/src/native/realm.def b/packages/cinterop/src/native/realm.def index d5f34c6379..0c92edfbee 100644 --- a/packages/cinterop/src/native/realm.def +++ b/packages/cinterop/src/native/realm.def @@ -11,7 +11,7 @@ headerFilter = realm.h realm/error_codes.h // libraryPaths.macos_x64 = ../external/core/build-macos_x64/src/realm/object-store/c_api ../external/core/build-macos_x64/src/realm ../external/core/build-macos_x64/src/realm/parser ../external/core/build-macos_x64/src/realm/object-store/ // libraryPaths.ios_x64 = ../external/core/build-macos_x64/src/realm/object-store/c_api ../external/core/build-macos_x64/src/realm ../external/core/build-macos_x64/src/realm/parser ../external/core/build-macos_x64/src/realm/object-store/ linkerOpts = -lcompression -lz -framework Foundation -framework CoreFoundation -framework Security -strictEnums = realm_errno realm_error_category realm_sync_errno_client realm_sync_errno_connection realm_sync_errno_session +strictEnums = realm_errno realm_error_category realm_sync_errno_client realm_sync_errno_connection realm_sync_errno_session realm_web_socket_errno --- #include #include diff --git a/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/ErrorCategory.kt b/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/ErrorCategory.kt index a792b233d7..ab2a7bfad5 100644 --- a/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/ErrorCategory.kt +++ b/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/ErrorCategory.kt @@ -35,7 +35,8 @@ actual enum class ErrorCategory( RLM_ERR_CAT_SERVICE_ERROR("Service", realm_error_category.RLM_ERR_CAT_SERVICE_ERROR.value.toInt()), RLM_ERR_CAT_HTTP_ERROR("Http", realm_error_category.RLM_ERR_CAT_HTTP_ERROR.value.toInt()), RLM_ERR_CAT_CUSTOM_ERROR("Custom", realm_error_category.RLM_ERR_CAT_CUSTOM_ERROR.value.toInt()), - RLM_ERR_CAT_WEBSOCKET_ERROR("Websocket", realm_error_category.RLM_ERR_CAT_WEBSOCKET_ERROR.value.toInt()); + RLM_ERR_CAT_WEBSOCKET_ERROR("Websocket", realm_error_category.RLM_ERR_CAT_WEBSOCKET_ERROR.value.toInt()), + RLM_ERR_CAT_SYNC_ERROR("Sync", realm_error_category.RLM_ERR_CAT_SYNC_ERROR.value.toInt()); actual companion object { diff --git a/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/ErrorCode.kt b/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/ErrorCode.kt index 70987acd03..3fb35d665c 100644 --- a/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/ErrorCode.kt +++ b/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/ErrorCode.kt @@ -20,7 +20,7 @@ import realm_wrapper.realm_errno actual enum class ErrorCode( override val description: String, - error: realm_errno + private val nativeError: realm_errno ) : CodeDescription { RLM_ERR_NONE("None", realm_errno.RLM_ERR_NONE), RLM_ERR_RUNTIME("Runtime", realm_errno.RLM_ERR_RUNTIME), @@ -51,6 +51,22 @@ actual enum class ErrorCode( RLM_ERR_SCHEMA_VERSION_MISMATCH("SchemaVersionMismatch", realm_errno.RLM_ERR_SCHEMA_VERSION_MISMATCH), RLM_ERR_NO_SUBSCRIPTION_FOR_WRITE("NoSubscriptionForWrite", realm_errno.RLM_ERR_NO_SUBSCRIPTION_FOR_WRITE), RLM_ERR_OPERATION_ABORTED("OperationAborted", realm_errno.RLM_ERR_OPERATION_ABORTED), + RLM_ERR_AUTO_CLIENT_RESET_FAILED("AutoClientResetFailed", realm_errno.RLM_ERR_AUTO_CLIENT_RESET_FAILED), + RLM_ERR_BAD_SYNC_PARTITION_VALUE("BadSyncPartitionValue", realm_errno.RLM_ERR_BAD_SYNC_PARTITION_VALUE), + RLM_ERR_CONNECTION_CLOSED("ConnectionClosed", realm_errno.RLM_ERR_CONNECTION_CLOSED), + RLM_ERR_INVALID_SUBSCRIPTION_QUERY("InvalidSubscriptionQuery", realm_errno.RLM_ERR_INVALID_SUBSCRIPTION_QUERY), + RLM_ERR_SYNC_CLIENT_RESET_REQUIRED("SyncClientResetRequired", realm_errno.RLM_ERR_SYNC_CLIENT_RESET_REQUIRED), + RLM_ERR_SYNC_COMPENSATING_WRITE("CompensatingWrite", realm_errno.RLM_ERR_SYNC_COMPENSATING_WRITE), + RLM_ERR_SYNC_CONNECT_FAILED("SyncConnectFailed", realm_errno.RLM_ERR_SYNC_CONNECT_FAILED), + RLM_ERR_SYNC_INVALID_SCHEMA_CHANGE("SyncInvalidSchemaChange", realm_errno.RLM_ERR_SYNC_INVALID_SCHEMA_CHANGE), + RLM_ERR_SYNC_PERMISSION_DENIED("SyncPermissionDenied", realm_errno.RLM_ERR_SYNC_PERMISSION_DENIED), + RLM_ERR_SYNC_PROTOCOL_INVARIANT_FAILED("SyncProtocolInvariantFailed", realm_errno.RLM_ERR_SYNC_PROTOCOL_INVARIANT_FAILED), + RLM_ERR_SYNC_PROTOCOL_NEGOTIATION_FAILED("SyncProtocolNegotiationFailed", realm_errno.RLM_ERR_SYNC_PROTOCOL_NEGOTIATION_FAILED), + RLM_ERR_SYNC_SERVER_PERMISSIONS_CHANGED("SyncServerPermissionsChanged", realm_errno.RLM_ERR_SYNC_SERVER_PERMISSIONS_CHANGED), + RLM_ERR_SYNC_USER_MISMATCH("SyncUserMismatch", realm_errno.RLM_ERR_SYNC_USER_MISMATCH), + RLM_ERR_TLS_HANDSHAKE_FAILED("TLSHandshakeFailed", realm_errno.RLM_ERR_TLS_HANDSHAKE_FAILED), + RLM_ERR_WRONG_SYNC_TYPE("WrongSyncType", realm_errno.RLM_ERR_WRONG_SYNC_TYPE), + RLM_ERR_SYNC_WRITE_NOT_ALLOWED("SyncWriteNotAllowed", realm_errno.RLM_ERR_SYNC_WRITE_NOT_ALLOWED), RLM_ERR_SYSTEM_ERROR("SystemError", realm_errno.RLM_ERR_SYSTEM_ERROR), RLM_ERR_LOGIC("Logic", realm_errno.RLM_ERR_LOGIC), RLM_ERR_NOT_SUPPORTED("NotSupported", realm_errno.RLM_ERR_NOT_SUPPORTED), @@ -122,7 +138,7 @@ actual enum class ErrorCode( RLM_ERR_MONGODB_ERROR("MongodbError", realm_errno.RLM_ERR_MONGODB_ERROR), RLM_ERR_ARGUMENTS_NOT_ALLOWED("ArgumentsNotAllowed", realm_errno.RLM_ERR_ARGUMENTS_NOT_ALLOWED), RLM_ERR_FUNCTION_EXECUTION_ERROR("FunctionExecutionError", realm_errno.RLM_ERR_FUNCTION_EXECUTION_ERROR), - RLM_ERR_NO_MATCHING_RULE("NoMatchingRule", realm_errno.RLM_ERR_NO_MATCHING_RULE), + RLM_ERR_NO_MATCHING_RULE("NoMatchingRule", realm_errno.RLM_ERR_NO_MATCHING_RULE_FOUND), RLM_ERR_INTERNAL_SERVER_ERROR("InternalServerError", realm_errno.RLM_ERR_INTERNAL_SERVER_ERROR), RLM_ERR_AUTH_PROVIDER_NOT_FOUND("AuthProviderNotFound", realm_errno.RLM_ERR_AUTH_PROVIDER_NOT_FOUND), RLM_ERR_AUTH_PROVIDER_ALREADY_EXISTS("AuthProviderAlreadyExists", realm_errno.RLM_ERR_AUTH_PROVIDER_ALREADY_EXISTS), @@ -163,13 +179,13 @@ actual enum class ErrorCode( RLM_ERR_MAINTENANCE_IN_PROGRESS("MaintenanceInProgress", realm_errno.RLM_ERR_MAINTENANCE_IN_PROGRESS), RLM_ERR_USERPASS_TOKEN_INVALID("UserpassTokenInvalid", realm_errno.RLM_ERR_USERPASS_TOKEN_INVALID), RLM_ERR_INVALID_SERVER_RESPONSE("InvalidServerResponse", realm_errno.RLM_ERR_INVALID_SERVER_RESPONSE), - RLM_ERR_WEBSOCKET_RESOLVE_FAILED_ERROR("ResolveFailedError", realm_errno.RLM_ERR_WEBSOCKET_RESOLVE_FAILED_ERROR), - RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_CLIENT_ERROR("ConnectionClosedClientError", realm_errno.RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_CLIENT_ERROR), - RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_SERVER_ERROR("ConnectionClosedServerError", realm_errno.RLM_ERR_WEBSOCKET_CONNECTION_CLOSED_SERVER_ERROR), + REALM_ERR_APP_SERVER_ERROR("AppServerError", realm_errno.RLM_ERR_APP_SERVER_ERROR), RLM_ERR_CALLBACK("Callback", realm_errno.RLM_ERR_CALLBACK), RLM_ERR_UNKNOWN("Unknown", realm_errno.RLM_ERR_UNKNOWN); - override val nativeValue: Int = error.value.toInt() + override val nativeValue: Int = nativeError.value.toInt() + + val asNativeEnum: realm_errno = nativeError actual companion object { actual fun of(nativeValue: Int): ErrorCode? = diff --git a/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt b/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt index 96a5d86e00..d5e4780534 100644 --- a/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt +++ b/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/RealmInterop.kt @@ -19,9 +19,9 @@ package io.realm.kotlin.internal.interop import io.realm.kotlin.internal.interop.Constants.ENCRYPTION_KEY_LENGTH -import io.realm.kotlin.internal.interop.RealmInterop.safeKString import io.realm.kotlin.internal.interop.sync.ApiKeyWrapper import io.realm.kotlin.internal.interop.sync.AppError +import io.realm.kotlin.internal.interop.sync.AppError.Companion.newInstance import io.realm.kotlin.internal.interop.sync.AuthProvider import io.realm.kotlin.internal.interop.sync.CoreCompensatingWriteInfo import io.realm.kotlin.internal.interop.sync.CoreConnectionState @@ -31,11 +31,8 @@ import io.realm.kotlin.internal.interop.sync.CoreUserState import io.realm.kotlin.internal.interop.sync.MetadataMode import io.realm.kotlin.internal.interop.sync.NetworkTransport import io.realm.kotlin.internal.interop.sync.ProgressDirection -import io.realm.kotlin.internal.interop.sync.ProtocolClientErrorCode import io.realm.kotlin.internal.interop.sync.Response import io.realm.kotlin.internal.interop.sync.SyncError -import io.realm.kotlin.internal.interop.sync.SyncErrorCode -import io.realm.kotlin.internal.interop.sync.SyncErrorCodeCategory import io.realm.kotlin.internal.interop.sync.SyncSessionResyncMode import io.realm.kotlin.internal.interop.sync.SyncUserIdentity import kotlinx.atomicfu.AtomicBoolean @@ -121,7 +118,6 @@ import realm_wrapper.realm_scheduler_t import realm_wrapper.realm_set_t import realm_wrapper.realm_string_t import realm_wrapper.realm_sync_client_metadata_mode -import realm_wrapper.realm_sync_error_code_t import realm_wrapper.realm_sync_session_resync_mode import realm_wrapper.realm_sync_session_state_e import realm_wrapper.realm_sync_session_stop_policy_e @@ -562,7 +558,7 @@ actual object RealmInterop { ) err.usercode_error?.let { disposeUserData(it) } } else { - realm_wrapper.realm_release(realm) + realm_release(realm) } safeUserData(userData).invoke(exception) } @@ -2391,10 +2387,12 @@ actual object RealmInterop { syncConfig.cptr(), staticCFunction { userData, syncSession, error -> val syncError: SyncError = error.useContents { - val code = SyncErrorCode.newInstance( - error_code.category.value.toInt(), - error_code.value, - error_code.message.safeKString() + val code = CoreError( + this.status.categories.toInt(), + this.status.error.value.toInt(), + this.status.message.safeKString(), + this.status.path.safeKString(), + null ) val userInfoMap = (0 until user_info_length.toInt()) @@ -2421,7 +2419,6 @@ actual object RealmInterop { SyncError( errorCode = code, - detailedMessage = detailed_message.safeKString(), originalFilePath = userInfoMap[c_original_file_path_key.safeKString()], recoveryFilePath = userInfoMap[c_recovery_file_path_key.safeKString()], isFatal = is_fatal, @@ -2527,7 +2524,7 @@ actual object RealmInterop { ) { realm_wrapper.realm_sync_session_wait_for_download_completion( syncSession.cptr(), - staticCFunction?, Unit> { userData, error -> + staticCFunction?, Unit> { userData, error -> handleCompletionCallback(userData, error) }, StableRef.create(callback).asCPointer(), @@ -2543,7 +2540,7 @@ actual object RealmInterop { ) { realm_wrapper.realm_sync_session_wait_for_upload_completion( syncSession.cptr(), - staticCFunction?, Unit> { userData, error -> + staticCFunction?, Unit> { userData, error -> handleCompletionCallback(userData, error) }, StableRef.create(callback).asCPointer(), @@ -2574,15 +2571,13 @@ actual object RealmInterop { actual fun realm_sync_session_handle_error_for_testing( syncSession: RealmSyncSessionPointer, - errorCode: ProtocolClientErrorCode, - category: SyncErrorCodeCategory, + error: ErrorCode, errorMessage: String, isFatal: Boolean ) { realm_wrapper.realm_sync_session_handle_error_for_testing( syncSession.cptr(), - errorCode.nativeValue.toInt(), - category.nativeValue, + error.asNativeEnum, errorMessage, isFatal ) @@ -2636,14 +2631,15 @@ actual object RealmInterop { private fun handleCompletionCallback( userData: CPointer?, - error: CPointer? + error: CPointer? ) { val completionCallback = safeUserData(userData) if (error != null) { - val category = error.pointed.category.value.toInt() - val value: Int = error.pointed.value + val category = error.pointed.categories.toInt() + val value: Int = error.pointed.error.value.toInt() val message = error.pointed.message.safeKString() - completionCallback.invoke(SyncErrorCode.newInstance(category, value, message)) + val path = error.pointed.path.safeKString() + completionCallback.invoke(CoreError(category, value, message, path, null)) } else { completionCallback.invoke(null) } @@ -2672,12 +2668,6 @@ actual object RealmInterop { baseUrl?.let { realm_wrapper.realm_app_config_set_base_url(appConfig, it) } // Sync Connection Parameters - connectionParams.localAppName?.let { appName -> - realm_wrapper.realm_app_config_set_local_app_name(appConfig, appName) - } - connectionParams.localAppVersion?.let { appVersion -> - realm_wrapper.realm_app_config_set_local_app_name(appConfig, appVersion) - } realm_wrapper.realm_app_config_set_sdk(appConfig, connectionParams.sdkName) realm_wrapper.realm_app_config_set_sdk_version(appConfig, connectionParams.sdkVersion) realm_wrapper.realm_app_config_set_platform_version(appConfig, connectionParams.platformVersion) diff --git a/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/sync/ProtocolErrorCode.kt b/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/sync/ProtocolErrorCode.kt index 6504d9b0ea..20817a0ae5 100644 --- a/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/sync/ProtocolErrorCode.kt +++ b/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/sync/ProtocolErrorCode.kt @@ -16,57 +16,11 @@ package io.realm.kotlin.internal.interop.sync import io.realm.kotlin.internal.interop.CodeDescription -import realm_wrapper.realm_sync_errno_client import realm_wrapper.realm_sync_errno_connection import realm_wrapper.realm_sync_errno_session +import realm_wrapper.realm_web_socket_errno -actual enum class ProtocolClientErrorCode( - override val description: String, - errorCode: realm_sync_errno_client -) : CodeDescription { - RLM_SYNC_ERR_CLIENT_CONNECTION_CLOSED("ConnectionClosed", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_CONNECTION_CLOSED), - RLM_SYNC_ERR_CLIENT_UNKNOWN_MESSAGE("UnknownMessage", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_UNKNOWN_MESSAGE), - RLM_SYNC_ERR_CLIENT_BAD_SYNTAX("BadSyntax", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_SYNTAX), - RLM_SYNC_ERR_CLIENT_LIMITS_EXCEEDED("LimitsExceeded", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_LIMITS_EXCEEDED), - RLM_SYNC_ERR_CLIENT_BAD_SESSION_IDENT("BadSessionIdent", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_SESSION_IDENT), - RLM_SYNC_ERR_CLIENT_BAD_MESSAGE_ORDER("BadMessageOrder", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_MESSAGE_ORDER), - RLM_SYNC_ERR_CLIENT_BAD_CLIENT_FILE_IDENT("BadClientFileIdent", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_CLIENT_FILE_IDENT), - RLM_SYNC_ERR_CLIENT_BAD_PROGRESS("BadProgress", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_PROGRESS), - RLM_SYNC_ERR_CLIENT_BAD_CHANGESET_HEADER_SYNTAX("BadChangesetHeaderSyntax", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_CHANGESET_HEADER_SYNTAX), - RLM_SYNC_ERR_CLIENT_BAD_CHANGESET_SIZE("BadChangesetSize", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_CHANGESET_SIZE), - RLM_SYNC_ERR_CLIENT_BAD_ORIGIN_FILE_IDENT("BadOriginFileIdent", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_ORIGIN_FILE_IDENT), - RLM_SYNC_ERR_CLIENT_BAD_SERVER_VERSION("BadServerVersion", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_SERVER_VERSION), - RLM_SYNC_ERR_CLIENT_BAD_CHANGESET("BadChangeset", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_CHANGESET), - RLM_SYNC_ERR_CLIENT_BAD_REQUEST_IDENT("BadRequestIdent", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_REQUEST_IDENT), - RLM_SYNC_ERR_CLIENT_BAD_ERROR_CODE("BadErrorCode", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_ERROR_CODE), - RLM_SYNC_ERR_CLIENT_BAD_COMPRESSION("BadCompression", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_COMPRESSION), - RLM_SYNC_ERR_CLIENT_BAD_CLIENT_VERSION("BadClientVersion", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_CLIENT_VERSION), - RLM_SYNC_ERR_CLIENT_SSL_SERVER_CERT_REJECTED("SslServerCertRejected", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_SSL_SERVER_CERT_REJECTED), - RLM_SYNC_ERR_CLIENT_PONG_TIMEOUT("PongTimeout", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_PONG_TIMEOUT), - RLM_SYNC_ERR_CLIENT_BAD_CLIENT_FILE_IDENT_SALT("BadClientFileIdentSalt", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_CLIENT_FILE_IDENT_SALT), - RLM_SYNC_ERR_CLIENT_BAD_FILE_IDENT("BadFileIdent", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_FILE_IDENT), - RLM_SYNC_ERR_CLIENT_CONNECT_TIMEOUT("ConnectTimeout", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_CONNECT_TIMEOUT), - RLM_SYNC_ERR_CLIENT_BAD_TIMESTAMP("BadTimestamp", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_TIMESTAMP), - RLM_SYNC_ERR_CLIENT_BAD_PROTOCOL_FROM_SERVER("BadProtocolFromServer", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_PROTOCOL_FROM_SERVER), - RLM_SYNC_ERR_CLIENT_CLIENT_TOO_OLD_FOR_SERVER("ClientTooOldForServer", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_CLIENT_TOO_OLD_FOR_SERVER), - RLM_SYNC_ERR_CLIENT_CLIENT_TOO_NEW_FOR_SERVER("ClientTooNewForServer", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_CLIENT_TOO_NEW_FOR_SERVER), - RLM_SYNC_ERR_CLIENT_PROTOCOL_MISMATCH("ProtocolMismatch", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_PROTOCOL_MISMATCH), - RLM_SYNC_ERR_CLIENT_BAD_STATE_MESSAGE("BadStateMessage", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_BAD_STATE_MESSAGE), - RLM_SYNC_ERR_CLIENT_MISSING_PROTOCOL_FEATURE("MissingProtocolFeature", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_MISSING_PROTOCOL_FEATURE), - RLM_SYNC_ERR_CLIENT_HTTP_TUNNEL_FAILED("HttpTunnelFailed", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_HTTP_TUNNEL_FAILED), - RLM_SYNC_ERR_CLIENT_AUTO_CLIENT_RESET_FAILURE("AutoClientResetFailure", realm_sync_errno_client.RLM_SYNC_ERR_CLIENT_AUTO_CLIENT_RESET_FAILURE); - - override val nativeValue: Int = errorCode.value.toInt() - - actual companion object { - internal actual fun of(nativeValue: Int): ProtocolClientErrorCode? = - values().firstOrNull { value -> - value.nativeValue == nativeValue - } - } -} - -actual enum class ProtocolConnectionErrorCode( +actual enum class SyncConnectionErrorCode( override val description: String, errorCode: realm_sync_errno_connection ) : CodeDescription { @@ -89,14 +43,14 @@ actual enum class ProtocolConnectionErrorCode( override val nativeValue: Int = errorCode.value.toInt() actual companion object { - internal actual fun of(nativeValue: Int): ProtocolConnectionErrorCode? = + internal actual fun of(nativeValue: Int): SyncConnectionErrorCode? = values().firstOrNull { value -> value.nativeValue == nativeValue } } } -actual enum class ProtocolSessionErrorCode( +actual enum class SyncSessionErrorCode( override val description: String, errorCode: realm_sync_errno_session ) : CodeDescription { @@ -138,7 +92,47 @@ actual enum class ProtocolSessionErrorCode( override val nativeValue: Int = errorCode.value.toInt() actual companion object { - internal actual fun of(nativeValue: Int): ProtocolSessionErrorCode? = + internal actual fun of(nativeValue: Int): SyncSessionErrorCode? = + values().firstOrNull { value -> + value.nativeValue == nativeValue + } + } +} + +actual enum class WebsocketErrorCode( + override val description: String, + errorCode: realm_web_socket_errno, +) : CodeDescription { + RLM_ERR_WEBSOCKET_OK("Ok", realm_web_socket_errno.RLM_ERR_WEBSOCKET_OK), + RLM_ERR_WEBSOCKET_GOINGAWAY("GoingAway", realm_web_socket_errno.RLM_ERR_WEBSOCKET_GOINGAWAY), + RLM_ERR_WEBSOCKET_PROTOCOLERROR("ProtocolError", realm_web_socket_errno.RLM_ERR_WEBSOCKET_PROTOCOLERROR), + RLM_ERR_WEBSOCKET_UNSUPPORTEDDATA("UnsupportedData", realm_web_socket_errno.RLM_ERR_WEBSOCKET_UNSUPPORTEDDATA), + RLM_ERR_WEBSOCKET_RESERVED("Reserved", realm_web_socket_errno.RLM_ERR_WEBSOCKET_RESERVED), + RLM_ERR_WEBSOCKET_NOSTATUSRECEIVED("NoStatusReceived", realm_web_socket_errno.RLM_ERR_WEBSOCKET_NOSTATUSRECEIVED), + RLM_ERR_WEBSOCKET_ABNORMALCLOSURE("AbnormalClosure", realm_web_socket_errno.RLM_ERR_WEBSOCKET_ABNORMALCLOSURE), + RLM_ERR_WEBSOCKET_INVALIDPAYLOADDATA("InvalidPayloadData", realm_web_socket_errno.RLM_ERR_WEBSOCKET_INVALIDPAYLOADDATA), + RLM_ERR_WEBSOCKET_POLICYVIOLATION("PolicyViolation", realm_web_socket_errno.RLM_ERR_WEBSOCKET_POLICYVIOLATION), + RLM_ERR_WEBSOCKET_MESSAGETOOBIG("MessageToBig", realm_web_socket_errno.RLM_ERR_WEBSOCKET_MESSAGETOOBIG), + RLM_ERR_WEBSOCKET_INAVALIDEXTENSION("InvalidExtension", realm_web_socket_errno.RLM_ERR_WEBSOCKET_INAVALIDEXTENSION), + RLM_ERR_WEBSOCKET_INTERNALSERVERERROR("InternalServerError", realm_web_socket_errno.RLM_ERR_WEBSOCKET_INTERNALSERVERERROR), + RLM_ERR_WEBSOCKET_TLSHANDSHAKEFAILED("TlsHandshakeFailed", realm_web_socket_errno.RLM_ERR_WEBSOCKET_TLSHANDSHAKEFAILED), + RLM_ERR_WEBSOCKET_UNAUTHORIZED("Unauthorized", realm_web_socket_errno.RLM_ERR_WEBSOCKET_UNAUTHORIZED), + RLM_ERR_WEBSOCKET_FORBIDDEN("Forbidden", realm_web_socket_errno.RLM_ERR_WEBSOCKET_FORBIDDEN), + RLM_ERR_WEBSOCKET_MOVEDPERMANENTLY("MovedPermanently", realm_web_socket_errno.RLM_ERR_WEBSOCKET_MOVEDPERMANENTLY), + RLM_ERR_WEBSOCKET_CLIENT_TOO_OLD("ClientTooOld", realm_web_socket_errno.RLM_ERR_WEBSOCKET_CLIENT_TOO_OLD), + RLM_ERR_WEBSOCKET_CLIENT_TOO_NEW("ClientTooNew", realm_web_socket_errno.RLM_ERR_WEBSOCKET_CLIENT_TOO_NEW), + RLM_ERR_WEBSOCKET_PROTOCOL_MISMATCH("ProtocolMismatch", realm_web_socket_errno.RLM_ERR_WEBSOCKET_PROTOCOL_MISMATCH), + RLM_ERR_WEBSOCKET_RESOLVE_FAILED("ResolveFailed", realm_web_socket_errno.RLM_ERR_WEBSOCKET_RESOLVE_FAILED), + RLM_ERR_WEBSOCKET_CONNECTION_FAILED("ConnectionFailed", realm_web_socket_errno.RLM_ERR_WEBSOCKET_CONNECTION_FAILED), + RLM_ERR_WEBSOCKET_READ_ERROR("ReadError", realm_web_socket_errno.RLM_ERR_WEBSOCKET_READ_ERROR), + RLM_ERR_WEBSOCKET_WRITE_ERROR("WriteError", realm_web_socket_errno.RLM_ERR_WEBSOCKET_WRITE_ERROR), + RLM_ERR_WEBSOCKET_RETRY_ERROR("RetryError", realm_web_socket_errno.RLM_ERR_WEBSOCKET_RETRY_ERROR), + RLM_ERR_WEBSOCKET_FATAL_ERROR("FatalError", realm_web_socket_errno.RLM_ERR_WEBSOCKET_FATAL_ERROR); + + override val nativeValue: Int = errorCode.value.toInt() + + actual companion object { + internal actual fun of(nativeValue: Int): WebsocketErrorCode? = values().firstOrNull { value -> value.nativeValue == nativeValue } diff --git a/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCodeCategory.kt b/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCodeCategory.kt deleted file mode 100644 index 80254655ff..0000000000 --- a/packages/cinterop/src/nativeDarwin/kotlin/io/realm/kotlin/internal/interop/sync/SyncErrorCodeCategory.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2022 Realm Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.realm.kotlin.internal.interop.sync - -import io.realm.kotlin.internal.interop.CodeDescription -import realm_wrapper.realm_sync_error_category - -actual enum class SyncErrorCodeCategory( - override val description: String, - override val nativeValue: Int -) : CodeDescription { - RLM_SYNC_ERROR_CATEGORY_CLIENT("Client", realm_sync_error_category.RLM_SYNC_ERROR_CATEGORY_CLIENT.value.toInt()), - RLM_SYNC_ERROR_CATEGORY_CONNECTION("Connection", realm_sync_error_category.RLM_SYNC_ERROR_CATEGORY_CONNECTION.value.toInt()), - RLM_SYNC_ERROR_CATEGORY_SESSION("Session", realm_sync_error_category.RLM_SYNC_ERROR_CATEGORY_SESSION.value.toInt()), - RLM_SYNC_ERROR_CATEGORY_WEBSOCKET("Websocket", realm_sync_error_category.RLM_SYNC_ERROR_CATEGORY_WEBSOCKET.value.toInt()), - RLM_SYNC_ERROR_CATEGORY_SYSTEM("System", realm_sync_error_category.RLM_SYNC_ERROR_CATEGORY_SYSTEM.value.toInt()), - RLM_SYNC_ERROR_CATEGORY_UNKNOWN("Unknown", realm_sync_error_category.RLM_SYNC_ERROR_CATEGORY_UNKNOWN.value.toInt()); - - actual companion object { - - internal actual fun of(nativeValue: Int): SyncErrorCodeCategory? = - values().firstOrNull { value -> - value.nativeValue == nativeValue - } - } -} diff --git a/packages/external/core b/packages/external/core index f1e962cd44..d1ace25101 160000 --- a/packages/external/core +++ b/packages/external/core @@ -1 +1 @@ -Subproject commit f1e962cd447f8b69f8f7cf46a188b1c6246923c5 +Subproject commit d1ace25101b638520be8fbcbe7ed14f50e74c23d diff --git a/packages/jni-swig-stub/src/main/jni/realm_api_helpers.cpp b/packages/jni-swig-stub/src/main/jni/realm_api_helpers.cpp index 9848fc99c4..8359e823ce 100644 --- a/packages/jni-swig-stub/src/main/jni/realm_api_helpers.cpp +++ b/packages/jni-swig-stub/src/main/jni/realm_api_helpers.cpp @@ -716,10 +716,10 @@ jobject convert_to_jvm_sync_error(JNIEnv* jenv, const realm_sync_error_t& error) "", "(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZ[Lio/realm/kotlin/internal/interop/sync/CoreCompensatingWriteInfo;)V"); - jint category = static_cast(error.error_code.category); - jint value = error.error_code.value; - jstring msg = to_jstring(jenv, error.error_code.message); - jstring detailed_msg = to_jstring(jenv, error.detailed_message); + jint category = static_cast(error.status.categories); + jint value = static_cast(error.status.error); + jstring msg = to_jstring(jenv, error.status.message); + jstring path = to_jstring(jenv, error.status.path); jstring joriginal_file_path = nullptr; jstring jrecovery_file_path = nullptr; jboolean is_fatal = error.is_fatal; @@ -793,7 +793,7 @@ jobject convert_to_jvm_sync_error(JNIEnv* jenv, const realm_sync_error_t& error) category, value, msg, - detailed_msg, + path, joriginal_file_path, jrecovery_file_path, is_fatal, @@ -827,7 +827,7 @@ void sync_set_error_handler(realm_sync_config_t* sync_config, jobject error_hand }); } -void transfer_completion_callback(void* userdata, realm_sync_error_code_t* error) { +void transfer_completion_callback(void* userdata, realm_error_t* error) { auto env = get_env(true); static JavaMethod java_success_callback_method(env, JavaClassGlobalDef::sync_session_transfer_completion_callback(), @@ -836,12 +836,13 @@ void transfer_completion_callback(void* userdata, realm_sync_error_code_t* error static JavaMethod java_error_callback_method(env, JavaClassGlobalDef::sync_session_transfer_completion_callback(), "onError", - "(IILjava/lang/String;)V"); + "(IILjava/lang/String;Ljava/lang/String;)V"); if (error) { - jint category = static_cast(error->category); - jint value = error->value; + jint category = static_cast(error->categories); + jint value = error->error; jstring msg = to_jstring(env, error->message); - env->CallVoidMethod(static_cast(userdata), java_error_callback_method, category, value, msg); + jstring path = to_jstring(env, error->path); + env->CallVoidMethod(static_cast(userdata), java_error_callback_method, category, value, msg, path); } else { env->CallVoidMethod(static_cast(userdata), java_success_callback_method); } diff --git a/packages/jni-swig-stub/src/main/jni/realm_api_helpers.h b/packages/jni-swig-stub/src/main/jni/realm_api_helpers.h index 0854631d72..133b0095ee 100644 --- a/packages/jni-swig-stub/src/main/jni/realm_api_helpers.h +++ b/packages/jni-swig-stub/src/main/jni/realm_api_helpers.h @@ -72,7 +72,7 @@ void complete_http_request(void* request_context, jobject j_response); void -transfer_completion_callback(void* userdata, realm_sync_error_code_t* error); +transfer_completion_callback(void* userdata, realm_error_t* error); void realm_subscriptionset_changed_callback(void* userdata, diff --git a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/RealmSyncUtils.kt b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/RealmSyncUtils.kt index e5c3d424bb..db0313cfb2 100644 --- a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/RealmSyncUtils.kt +++ b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/RealmSyncUtils.kt @@ -1,14 +1,11 @@ package io.realm.kotlin.mongodb.internal import io.realm.kotlin.internal.interop.AppCallback +import io.realm.kotlin.internal.interop.CoreError import io.realm.kotlin.internal.interop.ErrorCategory import io.realm.kotlin.internal.interop.ErrorCode import io.realm.kotlin.internal.interop.sync.AppError -import io.realm.kotlin.internal.interop.sync.ProtocolConnectionErrorCode -import io.realm.kotlin.internal.interop.sync.ProtocolSessionErrorCode import io.realm.kotlin.internal.interop.sync.SyncError -import io.realm.kotlin.internal.interop.sync.SyncErrorCode -import io.realm.kotlin.internal.interop.sync.SyncErrorCodeCategory import io.realm.kotlin.mongodb.exceptions.AppException import io.realm.kotlin.mongodb.exceptions.AuthException import io.realm.kotlin.mongodb.exceptions.BadFlexibleSyncQueryException @@ -80,64 +77,26 @@ internal fun channelResultCallback( internal fun convertSyncError(syncError: SyncError): SyncException { val errorCode = syncError.errorCode - // FIXME Client Reset errors are just reported as normal Sync Errors for now. - // Will be fixed by https://github.com/realm/realm-kotlin/issues/417 val message = createMessageFromSyncError(errorCode) - return when (errorCode.category) { - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_CLIENT -> { - // See https://github.com/realm/realm-core/blob/master/src/realm/sync/client_base.hpp#L73 - // For now, it is unclear how to categorize these, so for now, just report as generic - // errors. - SyncException(message) - } - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_CONNECTION -> { - // See https://github.com/realm/realm-core/blob/master/src/realm/sync/protocol.hpp#L200 - // Use https://docs.google.com/spreadsheets/d/1SmiRxhFpD1XojqCKC-xAjjV-LKa9azeeWHg-zgr07lE/edit - // as guide for how to categorize Connection type errors. - when (errorCode.code) { - ProtocolConnectionErrorCode.RLM_SYNC_ERR_CONNECTION_UNKNOWN_MESSAGE, // Unknown type of input message - ProtocolConnectionErrorCode.RLM_SYNC_ERR_CONNECTION_BAD_SYNTAX, // Bad syntax in input message head - ProtocolConnectionErrorCode.RLM_SYNC_ERR_CONNECTION_WRONG_PROTOCOL_VERSION, // Wrong protocol version (CLIENT) (obsolete) - ProtocolConnectionErrorCode.RLM_SYNC_ERR_CONNECTION_BAD_SESSION_IDENT, // Bad session identifier in input message - ProtocolConnectionErrorCode.RLM_SYNC_ERR_CONNECTION_REUSE_OF_SESSION_IDENT, // Overlapping reuse of session identifier (BIND) - ProtocolConnectionErrorCode.RLM_SYNC_ERR_CONNECTION_BOUND_IN_OTHER_SESSION, // Client file bound in other session (IDENT) - ProtocolConnectionErrorCode.RLM_SYNC_ERR_CONNECTION_BAD_MESSAGE_ORDER, // Bad input message order - ProtocolConnectionErrorCode.RLM_SYNC_ERR_CONNECTION_BAD_DECOMPRESSION, // Error in decompression (UPLOAD) - ProtocolConnectionErrorCode.RLM_SYNC_ERR_CONNECTION_BAD_CHANGESET_HEADER_SYNTAX, // Bad syntax in a changeset header (UPLOAD) - ProtocolConnectionErrorCode.RLM_SYNC_ERR_CONNECTION_BAD_CHANGESET_SIZE -> { // Bad size specified in changeset header (UPLOAD) - UnrecoverableSyncException(message) - } - ProtocolConnectionErrorCode.RLM_SYNC_ERR_CONNECTION_SWITCH_TO_FLX_SYNC, // Connected with wrong wire protocol - should switch to FLX sync - ProtocolConnectionErrorCode.RLM_SYNC_ERR_CONNECTION_SWITCH_TO_PBS -> { // Connected with wrong wire protocol - should switch to PBS - WrongSyncTypeException(message) - } - else -> SyncException(message) - } - } - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_SESSION -> { - // See https://github.com/realm/realm-core/blob/master/src/realm/sync/protocol.hpp#L217 - // Use https://docs.google.com/spreadsheets/d/1SmiRxhFpD1XojqCKC-xAjjV-LKa9azeeWHg-zgr07lE/edit - // as guide for how to categorize Session type errors. - when (errorCode.code) { - ProtocolSessionErrorCode.RLM_SYNC_ERR_SESSION_BAD_QUERY -> { // Flexible Sync Query was rejected by the server - BadFlexibleSyncQueryException(message) - } - ProtocolSessionErrorCode.RLM_SYNC_ERR_SESSION_PERMISSION_DENIED -> - // Permission denied errors should be unrecoverable according to Core, i.e. the - // client will disconnect sync and transition to the "inactive" state - UnrecoverableSyncException(message) - ProtocolSessionErrorCode.RLM_SYNC_ERR_SESSION_COMPENSATING_WRITE -> - CompensatingWriteException(message, syncError.compensatingWrites) - else -> SyncException(message) - } + return when (errorCode.errorCode) { + ErrorCode.RLM_ERR_WRONG_SYNC_TYPE -> WrongSyncTypeException(message) + + ErrorCode.RLM_ERR_INVALID_SUBSCRIPTION_QUERY -> { + // Flexible Sync Query was rejected by the server + BadFlexibleSyncQueryException(message) } - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_SYSTEM, - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_UNKNOWN -> { - // It is unclear how to handle system level errors, so even though some of them - // are probably benign, report as top-level errors for now. - SyncException(message) + ErrorCode.RLM_ERR_SYNC_COMPENSATING_WRITE -> CompensatingWriteException(message, syncError.compensatingWrites) + + ErrorCode.RLM_ERR_SYNC_PROTOCOL_INVARIANT_FAILED, + ErrorCode.RLM_ERR_SYNC_PROTOCOL_NEGOTIATION_FAILED, + ErrorCode.RLM_ERR_SYNC_PERMISSION_DENIED -> { + // Permission denied errors should be unrecoverable according to Core, i.e. the + // client will disconnect sync and transition to the "inactive" state + UnrecoverableSyncException(message) } else -> { + // An error happened we are not sure how to handle. Just report as a generic + // SyncException. SyncException(message) } } @@ -277,28 +236,25 @@ internal fun convertAppError(appError: AppError): Throwable { } } -internal fun createMessageFromSyncError(error: SyncErrorCode): String { - val categoryDesc = error.category.description ?: error.category.nativeValue.toString() - val errorCodeDesc: String? = error.code.description ?: when (error.category) { - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_SYSTEM, - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_UNKNOWN, - -> { - // We lack information about these kinds of errors, - // so rather than returning a potentially misleading - // name, just return nothing. - null - } - else -> "Unknown" +internal fun createMessageFromSyncError(error: CoreError): String { + val categoryDesc = error.categories.description + val errorCodeDesc: String? = error.errorCode?.description ?: if (ErrorCategory.RLM_ERR_CAT_SYSTEM_ERROR in error.categories) { + // We lack information about these kinds of errors, + // so rather than returning a potentially misleading + // name, just return nothing. + null + } else { + "Unknown" } // Combine all the parts to form an error format that is human-readable. // An example could be this: `[Connection][WrongProtocolVersion(104)] Wrong protocol version was used: 25` val errorDesc: String = - if (errorCodeDesc == null) error.code.nativeValue.toString() else "$errorCodeDesc(${error.code.nativeValue})" + if (errorCodeDesc == null) error.errorCodeNativeValue.toString() else "$errorCodeDesc(${error.errorCodeNativeValue})" // Make sure that messages are uniformly formatted, so it looks nice if we append the // server log. - val msg = error.message.let { message: String -> + val msg = error.message!!.let { message: String -> " $message${if (!message.endsWith(".")) "." else ""}" } diff --git a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/SyncSessionImpl.kt b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/SyncSessionImpl.kt index 8409b7c556..720d2e4de2 100644 --- a/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/SyncSessionImpl.kt +++ b/packages/library-sync/src/commonMain/kotlin/io/realm/kotlin/mongodb/internal/SyncSessionImpl.kt @@ -19,16 +19,15 @@ package io.realm.kotlin.mongodb.internal import io.realm.kotlin.internal.InternalConfiguration import io.realm.kotlin.internal.NotificationToken import io.realm.kotlin.internal.RealmImpl +import io.realm.kotlin.internal.interop.CoreError +import io.realm.kotlin.internal.interop.ErrorCode import io.realm.kotlin.internal.interop.RealmInterop import io.realm.kotlin.internal.interop.RealmSyncSessionPointer import io.realm.kotlin.internal.interop.SyncSessionTransferCompletionCallback import io.realm.kotlin.internal.interop.sync.CoreConnectionState import io.realm.kotlin.internal.interop.sync.CoreSyncSessionState import io.realm.kotlin.internal.interop.sync.ProgressDirection -import io.realm.kotlin.internal.interop.sync.ProtocolClientErrorCode import io.realm.kotlin.internal.interop.sync.SyncError -import io.realm.kotlin.internal.interop.sync.SyncErrorCode -import io.realm.kotlin.internal.interop.sync.SyncErrorCodeCategory import io.realm.kotlin.internal.util.Validation import io.realm.kotlin.internal.util.trySendWithBufferOverflowCheck import io.realm.kotlin.mongodb.User @@ -165,15 +164,13 @@ internal open class SyncSessionImpl( /** * Simulates a sync error. Internal visibility only for testing. */ - internal fun simulateError( - errorCode: ProtocolClientErrorCode, - category: SyncErrorCodeCategory, + internal fun simulateSyncError( + error: ErrorCode, message: String = "Simulate Client Reset" ) { RealmInterop.realm_sync_session_handle_error_for_testing( nativePointer, - errorCode, - category, + error, message, true ) @@ -201,7 +198,7 @@ internal open class SyncSessionImpl( val result: Any = withTimeout(timeout) { withContext(realm.notificationDispatcherHolder.dispatcher) { val callback = object : SyncSessionTransferCompletionCallback { - override fun invoke(errorCode: SyncErrorCode?) { + override fun invoke(errorCode: CoreError?) { if (errorCode != null) { // Transform the errorCode into a dummy syncError so we can have a // common path. diff --git a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/SyncClientResetIntegrationTests.kt b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/SyncClientResetIntegrationTests.kt index 6dbadc3571..3cf2b72d18 100644 --- a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/SyncClientResetIntegrationTests.kt +++ b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/SyncClientResetIntegrationTests.kt @@ -25,8 +25,7 @@ import io.realm.kotlin.entities.sync.flx.FlexChildObject import io.realm.kotlin.entities.sync.flx.FlexEmbeddedObject import io.realm.kotlin.entities.sync.flx.FlexParentObject import io.realm.kotlin.ext.query -import io.realm.kotlin.internal.interop.sync.ProtocolClientErrorCode -import io.realm.kotlin.internal.interop.sync.SyncErrorCodeCategory +import io.realm.kotlin.internal.interop.ErrorCode import io.realm.kotlin.internal.platform.fileExists import io.realm.kotlin.internal.platform.runBlocking import io.realm.kotlin.log.LogLevel @@ -609,10 +608,7 @@ class SyncClientResetIntegrationTests { realm.syncSession.downloadAllServerChanges(defaultTimeout) with(realm.syncSession as SyncSessionImpl) { - simulateError( - ProtocolClientErrorCode.RLM_SYNC_ERR_CLIENT_AUTO_CLIENT_RESET_FAILURE, - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_CLIENT - ) + simulateSyncError(ErrorCode.RLM_ERR_AUTO_CLIENT_RESET_FAILED) // TODO Twice until the deprecated method is removed assertEquals(ClientResetEvents.ON_MANUAL_RESET_FALLBACK, channel.receiveOrFail()) @@ -682,10 +678,7 @@ class SyncClientResetIntegrationTests { realm.syncSession.downloadAllServerChanges(defaultTimeout) with(realm.syncSession as SyncSessionImpl) { - simulateError( - ProtocolClientErrorCode.RLM_SYNC_ERR_CLIENT_AUTO_CLIENT_RESET_FAILURE, - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_CLIENT - ) + simulateSyncError(ErrorCode.RLM_ERR_AUTO_CLIENT_RESET_FAILED) // TODO Twice until the deprecated method is removed assertEquals(ClientResetEvents.ON_MANUAL_RESET_FALLBACK, channel.receiveOrFail()) @@ -898,9 +891,8 @@ class SyncClientResetIntegrationTests { ) // assertEquals(ClientResetLogEvents.DISCARD_LOCAL_ON_AFTER_RESET, logChannel.receiveOrFail()) - (realm.syncSession as SyncSessionImpl).simulateError( - ProtocolClientErrorCode.RLM_SYNC_ERR_CLIENT_AUTO_CLIENT_RESET_FAILURE, - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_CLIENT + (realm.syncSession as SyncSessionImpl).simulateSyncError( + ErrorCode.RLM_ERR_AUTO_CLIENT_RESET_FAILED ) // Validate that we receive logs on the error callback val actual = logChannel.receiveOrFail() @@ -948,10 +940,7 @@ class SyncClientResetIntegrationTests { realm.syncSession.downloadAllServerChanges(defaultTimeout) with((realm.syncSession as SyncSessionImpl)) { - simulateError( - ProtocolClientErrorCode.RLM_SYNC_ERR_CLIENT_AUTO_CLIENT_RESET_FAILURE, - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_CLIENT - ) + simulateSyncError(ErrorCode.RLM_ERR_AUTO_CLIENT_RESET_FAILED) val exception = channel.receiveOrFail() val originalFilePath = assertNotNull(exception.originalFilePath) @@ -1002,10 +991,7 @@ class SyncClientResetIntegrationTests { realm.syncSession.downloadAllServerChanges(defaultTimeout) with(realm.syncSession as SyncSessionImpl) { - simulateError( - ProtocolClientErrorCode.RLM_SYNC_ERR_CLIENT_AUTO_CLIENT_RESET_FAILURE, - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_CLIENT - ) + simulateSyncError(ErrorCode.RLM_ERR_AUTO_CLIENT_RESET_FAILED) val exception = channel.receiveOrFail() @@ -1121,10 +1107,7 @@ class SyncClientResetIntegrationTests { runBlocking { realm.syncSession.downloadAllServerChanges(defaultTimeout) - (realm.syncSession as SyncSessionImpl).simulateError( - ProtocolClientErrorCode.RLM_SYNC_ERR_CLIENT_AUTO_CLIENT_RESET_FAILURE, - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_CLIENT - ) + (realm.syncSession as SyncSessionImpl).simulateSyncError(ErrorCode.RLM_ERR_AUTO_CLIENT_RESET_FAILED) val exception = channel.receiveOrFail() assertNotNull(exception.recoveryFilePath) @@ -1248,10 +1231,7 @@ class SyncClientResetIntegrationTests { realm.syncSession.downloadAllServerChanges(defaultTimeout) with(realm.syncSession as SyncSessionImpl) { - simulateError( - ProtocolClientErrorCode.RLM_SYNC_ERR_CLIENT_AUTO_CLIENT_RESET_FAILURE, - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_CLIENT - ) + simulateSyncError(ErrorCode.RLM_ERR_AUTO_CLIENT_RESET_FAILED) // TODO Twice until the deprecated method is removed assertEquals(ClientResetEvents.ON_MANUAL_RESET_FALLBACK, channel.receiveOrFail()) @@ -1449,10 +1429,7 @@ class SyncClientResetIntegrationTests { realm.syncSession.downloadAllServerChanges(defaultTimeout) with(realm.syncSession as SyncSessionImpl) { - simulateError( - ProtocolClientErrorCode.RLM_SYNC_ERR_CLIENT_AUTO_CLIENT_RESET_FAILURE, - SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_CLIENT - ) + simulateSyncError(ErrorCode.RLM_ERR_AUTO_CLIENT_RESET_FAILED) // TODO Twice until the deprecated method is removed assertEquals(ClientResetEvents.ON_MANUAL_RESET_FALLBACK, channel.receiveOrFail()) diff --git a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/internal/RealmSyncUtilsTest.kt b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/internal/RealmSyncUtilsTest.kt index 9cf0bd49fd..7ed110597c 100644 --- a/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/internal/RealmSyncUtilsTest.kt +++ b/packages/test-sync/src/commonTest/kotlin/io/realm/kotlin/test/mongodb/common/internal/RealmSyncUtilsTest.kt @@ -18,67 +18,80 @@ package io.realm.kotlin.test.mongodb.common.internal +import io.realm.kotlin.internal.interop.CoreError import io.realm.kotlin.internal.interop.ErrorCategory +import io.realm.kotlin.internal.interop.ErrorCode import io.realm.kotlin.internal.interop.UnknownCodeDescription import io.realm.kotlin.internal.interop.sync.AppError import io.realm.kotlin.internal.interop.sync.SyncError -import io.realm.kotlin.internal.interop.sync.SyncErrorCode -import io.realm.kotlin.internal.interop.sync.SyncErrorCodeCategory import io.realm.kotlin.mongodb.internal.convertAppError import io.realm.kotlin.mongodb.internal.convertSyncError import kotlin.test.Test import kotlin.test.assertEquals -const val UNMAPPED_CODE: Int = 0 +const val UNMAPPED_CATEGORY_CODE: Int = 0 +const val UNMAPPED_ERROR_CODE: Int = -1 class RealmSyncUtilsTest { + @Test - fun convertSyncErrorCode_unmappedErrorCode_categoryTypeUnknown() { + fun convertSyncErrorCode_unmappedErrorCode2() { val syncException = convertSyncError( SyncError( - SyncErrorCode( - category = SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_UNKNOWN, - code = UnknownCodeDescription(UNMAPPED_CODE), - message = "Placeholder message" + CoreError( + categoriesNativeValue = ErrorCategory.RLM_ERR_CAT_CLIENT_ERROR.nativeValue, + errorCodeNativeValue = UNMAPPED_ERROR_CODE, + messageNativeValue = "Placeholder message", + path = "no-path", + userError = null ) ) ) - assertEquals("[Unknown][$UNMAPPED_CODE] Placeholder message.", syncException.message) + assertEquals( + "[Client][Unknown($UNMAPPED_ERROR_CODE)] Placeholder message.", + syncException.message + ) } @Test - fun convertSyncErrorCode_unmappedErrorCode2() { + fun convertSyncErrorCode_unmappedErrorCategory() { val syncException = convertSyncError( SyncError( - SyncErrorCode( - category = SyncErrorCodeCategory.RLM_SYNC_ERROR_CATEGORY_CONNECTION, - code = UnknownCodeDescription(UNMAPPED_CODE), - message = "Placeholder message" + CoreError( + categoriesNativeValue = UNMAPPED_CATEGORY_CODE, + errorCodeNativeValue = UNMAPPED_ERROR_CODE, + messageNativeValue = "Placeholder message", + path = "no-path", + userError = null ) ) ) assertEquals( - "[Connection][Unknown($UNMAPPED_CODE)] Placeholder message.", + "[$UNMAPPED_CATEGORY_CODE][Unknown($UNMAPPED_ERROR_CODE)] Placeholder message.", syncException.message ) } + // Core also has a concept of an "unknown" error code. It is being reported the same way + // as a truly unknown code with the description "Unknown()" @Test - fun convertSyncErrorCode_unmappedErrorCategory() { + fun convertSyncErrorCode_unknownNativeErrrorCode() { val syncException = convertSyncError( SyncError( - SyncErrorCode( - category = UnknownCodeDescription(UNMAPPED_CODE), - code = UnknownCodeDescription(UNMAPPED_CODE), - message = "Placeholder message" + CoreError( + categoriesNativeValue = ErrorCategory.RLM_ERR_CAT_CLIENT_ERROR.nativeValue, + errorCodeNativeValue = ErrorCode.RLM_ERR_UNKNOWN.nativeValue, + messageNativeValue = "Placeholder message", + path = "no-path", + userError = null ) ) ) assertEquals( - "[$UNMAPPED_CODE][Unknown($UNMAPPED_CODE)] Placeholder message.", + "[Client][Unknown(2000000)] Placeholder message.", syncException.message ) } @@ -88,30 +101,30 @@ class RealmSyncUtilsTest { val appException = convertAppError( AppError( categoryFlags = ErrorCategory.RLM_ERR_CAT_CUSTOM_ERROR.nativeValue, - code = UnknownCodeDescription(UNMAPPED_CODE), + code = UnknownCodeDescription(UNMAPPED_ERROR_CODE), message = "Placeholder message", - httpStatusCode = UNMAPPED_CODE, + httpStatusCode = UNMAPPED_ERROR_CODE, linkToServerLog = null ) ) - assertEquals("[Custom][Unknown($UNMAPPED_CODE)] Placeholder message.", appException.message) + assertEquals("[Custom][Unknown($UNMAPPED_ERROR_CODE)] Placeholder message.", appException.message) } @Test fun convertAppError_unmappedErrorCategory() { val appException = convertAppError( AppError( - categoryFlags = UnknownCodeDescription(UNMAPPED_CODE).nativeValue, - code = UnknownCodeDescription(UNMAPPED_CODE), + categoryFlags = UnknownCodeDescription(UNMAPPED_CATEGORY_CODE).nativeValue, + code = UnknownCodeDescription(UNMAPPED_ERROR_CODE), message = "Placeholder message", - httpStatusCode = UNMAPPED_CODE, + httpStatusCode = UNMAPPED_ERROR_CODE, linkToServerLog = null ) ) assertEquals( - "[$UNMAPPED_CODE][Unknown($UNMAPPED_CODE)] Placeholder message.", + "[$UNMAPPED_CATEGORY_CODE][Unknown($UNMAPPED_ERROR_CODE)] Placeholder message.", appException.message ) } @@ -120,31 +133,31 @@ class RealmSyncUtilsTest { fun convertAppError_unmappedErrorCategoryAndErrorCode_noMessage() { val appException = convertAppError( AppError( - categoryFlags = UnknownCodeDescription(UNMAPPED_CODE).nativeValue, - code = UnknownCodeDescription(UNMAPPED_CODE), + categoryFlags = UnknownCodeDescription(UNMAPPED_CATEGORY_CODE).nativeValue, + code = UnknownCodeDescription(UNMAPPED_ERROR_CODE), message = null, - httpStatusCode = UNMAPPED_CODE, + httpStatusCode = UNMAPPED_ERROR_CODE, linkToServerLog = null ) ) - assertEquals("[$UNMAPPED_CODE][Unknown($UNMAPPED_CODE)]", appException.message) + assertEquals("[$UNMAPPED_CATEGORY_CODE][Unknown($UNMAPPED_ERROR_CODE)]", appException.message) } @Test fun convertAppError_unmappedErrorCategoryAndErrorCode_linkServerLog() { val appException = convertAppError( AppError( - categoryFlags = UnknownCodeDescription(UNMAPPED_CODE).nativeValue, - code = UnknownCodeDescription(UNMAPPED_CODE), + categoryFlags = UnknownCodeDescription(UNMAPPED_CATEGORY_CODE).nativeValue, + code = UnknownCodeDescription(UNMAPPED_ERROR_CODE), message = "Placeholder message", - httpStatusCode = UNMAPPED_CODE, + httpStatusCode = UNMAPPED_ERROR_CODE, linkToServerLog = "http://realm.io" ) ) assertEquals( - "[$UNMAPPED_CODE][Unknown($UNMAPPED_CODE)] Placeholder message. Server log entry: http://realm.io", + "[$UNMAPPED_CATEGORY_CODE][Unknown($UNMAPPED_ERROR_CODE)] Placeholder message. Server log entry: http://realm.io", appException.message ) } @@ -153,16 +166,16 @@ class RealmSyncUtilsTest { fun convertAppError_unmappedErrorCategoryAndErrorCode_noMessage_linkServerLog() { val appException = convertAppError( AppError( - categoryFlags = UnknownCodeDescription(UNMAPPED_CODE).nativeValue, - code = UnknownCodeDescription(UNMAPPED_CODE), + categoryFlags = UnknownCodeDescription(UNMAPPED_CATEGORY_CODE).nativeValue, + code = UnknownCodeDescription(UNMAPPED_ERROR_CODE), message = null, - httpStatusCode = UNMAPPED_CODE, + httpStatusCode = UNMAPPED_ERROR_CODE, linkToServerLog = "http://realm.io" ) ) assertEquals( - "[$UNMAPPED_CODE][Unknown($UNMAPPED_CODE)] Server log entry: http://realm.io", + "[$UNMAPPED_CATEGORY_CODE][Unknown($UNMAPPED_ERROR_CODE)] Server log entry: http://realm.io", appException.message ) }