-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Platform networking #1528
Platform networking #1528
Changes from 14 commits
88c9565
49c757d
2470859
824e049
e521d62
455ab2e
698e86a
d64b0b2
16b62ab
3505926
aa38a74
01e6d62
c92871c
2c68075
bb4105b
4de15a9
da49df3
7133797
5098395
c0180c5
5234ba4
ed8e5f9
8da19a0
19bc7c8
ed1b5a9
dc02b10
98e718d
8fc52a9
ee4fe03
bacf3b0
f0b5f6a
5e141da
b62ba74
dd37a22
073e4be
0e41956
0105a73
aecef93
1120c1b
ea50805
fed3971
fdb717a
50639db
042eb8a
ccda0ec
71359d3
a55e9ed
96be9c1
486686c
0ae12f8
d491fee
e423e3e
0c8dca8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ | |
* [Sync] If calling a function on App Services that resulted in a redirect, it would only redirect for | ||
GET requests. (Issue [#1517](https://github.com/realm/realm-kotlin/pull/1517)) | ||
* [Sync] If calling a function on App Services that resulted in a redirect, it would only redirect for GET requests. (Issue [#1517](https://github.com/realm/realm-kotlin/pull/1517)) | ||
* [Sync] Added option to use managed WebSockets via Ktor instead of Realm's built-in WebSocket client for Sync traffic. Managed WebSockets offer improved support for proxies and firewalls that require authentication. This feature is currently opt-in and can be enabled by using `AppConfiguration.usePlatformNetworking()`. Managed WebSockets will become the default in a future version. (PR [#1528](https://github.com/realm/realm-kotlin/pull/1528)). Currently only JVM and Android platforms are supported. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does it only work on JVM? Seems like the whole Darwin implementation is in place 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes the Darwin implementation is in place but it still has an issue with the engine to be fixed see https://github.com/realm/realm-kotlin/pull/1528/files/7133797711950bfe1d7eec2cb30ad696823879bb#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4edR38 |
||
|
||
### Compatibility | ||
* File format: Generates Realms with file format v23. | ||
|
@@ -32,7 +33,7 @@ GET requests. (Issue [#1517](https://github.com/realm/realm-kotlin/pull/1517)) | |
* Minimum Android SDK: 16. | ||
|
||
### Internal | ||
* None. | ||
* Updated to Realm Core 13.22.0, commit 9fe0653fef672f14c771019ba27d54d568f622d0. | ||
|
||
|
||
## 1.11.1 (2023-09-07) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -188,7 +188,7 @@ pipeline { | |
"integrationtest", | ||
{ | ||
forwardAdbPorts() | ||
testAndCollect("packages", "cleanAllTests -PincludeSdkModules=false connectedAndroidTest") | ||
testAndCollect("packages", "cleanAllTests -PREALM_USE_PLATFORM_NETWORKING=true -PincludeSdkModules=false connectedAndroidTest") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it correct that we no longer run full unit tests on the old implementation? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this is running with the new implementation for Android/JVM, we can duplicate the job to run also on legacy impl |
||
} | ||
) | ||
} | ||
|
@@ -212,7 +212,7 @@ pipeline { | |
steps { | ||
testWithServer([ | ||
{ | ||
testAndCollect("packages", 'cleanAllTests jvmTest -PincludeSdkModules=false ') | ||
testAndCollect("packages", 'cleanAllTests jvmTest -PREALM_USE_PLATFORM_NETWORKING=true -PincludeSdkModules=false ') | ||
} | ||
]) | ||
} | ||
|
@@ -232,7 +232,7 @@ pipeline { | |
steps { | ||
testWithServer([ | ||
{ | ||
testAndCollect("packages", 'cleanAllTests :test-sync:connectedAndroidtest -PincludeSdkModules=false -PtestBuildType=debugMinified') | ||
testAndCollect("packages", 'cleanAllTests :test-sync:connectedAndroidtest -PREALM_USE_PLATFORM_NETWORKING=true -PincludeSdkModules=false -PtestBuildType=debugMinified') | ||
} | ||
]) | ||
sh 'rm mapping.zip || true' | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -121,6 +121,21 @@ expect enum class WebsocketErrorCode : CodeDescription { | |
RLM_ERR_WEBSOCKET_FATAL_ERROR; | ||
|
||
companion object { | ||
internal fun of(nativeValue: Int): WebsocketErrorCode? | ||
fun of(nativeValue: Int): WebsocketErrorCode? | ||
} | ||
} | ||
|
||
expect enum class WebsocketCallbackResult : CodeDescription { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tests for this mapping should be added to |
||
RLM_ERR_SYNC_SOCKET_SUCCESS, | ||
RLM_ERR_SYNC_SOCKET_OPERATION_ABORTED, | ||
RLM_ERR_SYNC_SOCKET_RUNTIME, | ||
RLM_ERR_SYNC_SOCKET_OUT_OF_MEMORY, | ||
RLM_ERR_SYNC_SOCKET_ADDRESS_SPACE_EXHAUSTED, | ||
RLM_ERR_SYNC_SOCKET_CONNECTION_CLOSED, | ||
RLM_ERR_SYNC_SOCKET_NOT_SUPPORTED, | ||
RLM_ERR_SYNC_SOCKET_INVALID_ARGUMENT; | ||
|
||
companion object { | ||
fun of(nativeValue: Int): WebsocketCallbackResult? | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package io.realm.kotlin.internal.interop.sync | ||
nhachicha marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
import io.realm.kotlin.internal.interop.RealmInterop | ||
import io.realm.kotlin.internal.interop.RealmWebsocketHandlerCallbackPointer | ||
import io.realm.kotlin.internal.interop.RealmWebsocketProviderPointer | ||
import kotlinx.coroutines.Job | ||
|
||
interface WebSocketTransport { | ||
nhachicha marked this conversation as resolved.
Show resolved
Hide resolved
|
||
fun post(handlerCallback: RealmWebsocketHandlerCallbackPointer) | ||
|
||
fun createTimer( | ||
delayInMilliseconds: Long, | ||
handlerCallback: RealmWebsocketHandlerCallbackPointer, | ||
): CancellableTimer | ||
|
||
@Suppress("LongParameterList") | ||
fun connect( | ||
observer: WebSocketObserver, | ||
path: String, | ||
address: String, | ||
port: Long, | ||
isSsl: Boolean, | ||
numProtocols: Long, | ||
supportedProtocols: String | ||
): WebSocketClient | ||
|
||
fun write( | ||
webSocketClient: WebSocketClient, | ||
data: ByteArray, | ||
length: Long, | ||
handlerCallback: RealmWebsocketHandlerCallbackPointer | ||
) | ||
|
||
fun runCallback( | ||
handlerCallback: RealmWebsocketHandlerCallbackPointer, | ||
cancelled: Boolean = false, | ||
status: WebsocketCallbackResult = WebsocketCallbackResult.RLM_ERR_SYNC_SOCKET_SUCCESS, | ||
reason: String = "" | ||
) { | ||
RealmInterop.realm_sync_socket_callback_complete( | ||
handlerCallback, | ||
cancelled, | ||
status, | ||
reason | ||
) | ||
} | ||
|
||
fun close() | ||
} | ||
|
||
class CancellableTimer( | ||
private val job: Job, | ||
private val cancelCallback: () -> Unit | ||
) { | ||
fun cancel() { | ||
job.cancel() | ||
cancelCallback() | ||
} | ||
} | ||
|
||
interface WebSocketClient { | ||
fun send(message: ByteArray, handlerCallback: RealmWebsocketHandlerCallbackPointer) | ||
fun closeWebsocket() | ||
} | ||
|
||
class WebSocketObserver(private val webSocketObserverPointer: RealmWebsocketProviderPointer) { | ||
fun onConnected(protocol: String) { | ||
RealmInterop.realm_sync_socket_websocket_connected(webSocketObserverPointer, protocol) | ||
} | ||
|
||
fun onError() { | ||
RealmInterop.realm_sync_socket_websocket_error(webSocketObserverPointer) | ||
} | ||
|
||
fun onNewMessage(data: ByteArray): Boolean { | ||
return RealmInterop.realm_sync_socket_websocket_message(webSocketObserverPointer, data) | ||
} | ||
|
||
fun onClose(wasClean: Boolean, errorCode: WebsocketErrorCode, reason: String) { | ||
RealmInterop.realm_sync_socket_websocket_closed( | ||
webSocketObserverPointer, | ||
wasClean, | ||
errorCode, | ||
reason | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,9 @@ import io.realm.kotlin.internal.interop.sync.NetworkTransport | |
import io.realm.kotlin.internal.interop.sync.ProgressDirection | ||
import io.realm.kotlin.internal.interop.sync.SyncSessionResyncMode | ||
import io.realm.kotlin.internal.interop.sync.SyncUserIdentity | ||
import io.realm.kotlin.internal.interop.sync.WebSocketTransport | ||
import io.realm.kotlin.internal.interop.sync.WebsocketCallbackResult | ||
import io.realm.kotlin.internal.interop.sync.WebsocketErrorCode | ||
import kotlinx.coroutines.CoroutineDispatcher | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.launch | ||
|
@@ -1115,7 +1118,8 @@ actual object RealmInterop { | |
} | ||
|
||
actual fun realm_user_get_auth_provider(user: RealmUserPointer): AuthProvider { | ||
return AuthProvider.of(realmc.realm_user_get_auth_provider(user.cptr())) | ||
TODO("No longer valid") | ||
// return AuthProvider.of(realmc.realm_user_get_auth_provider(user.cptr())) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably upgrade Core in a separate PR from this one...there is quite a few things in here only related to that. |
||
} | ||
|
||
actual fun realm_user_get_access_token(user: RealmUserPointer): String { | ||
|
@@ -1157,7 +1161,6 @@ actual object RealmInterop { | |
} | ||
|
||
actual fun realm_app_sync_client_get_default_file_path_for_realm( | ||
app: RealmAppPointer, | ||
syncConfig: RealmSyncConfigurationPointer, | ||
overriddenName: String? | ||
): String { | ||
|
@@ -1977,6 +1980,36 @@ actual object RealmInterop { | |
return LongPointerWrapper(realmc.realm_sync_subscription_set_commit(mutableSubscriptionSet.cptr())) | ||
} | ||
|
||
actual fun realm_sync_set_websocket_transport( | ||
syncClientConfig: RealmSyncClientConfigurationPointer, | ||
webSocketTransport: WebSocketTransport | ||
) { | ||
realmc.realm_sync_websocket_new(syncClientConfig.cptr(), webSocketTransport) | ||
} | ||
|
||
actual fun realm_sync_socket_callback_complete(nativePointer: RealmWebsocketHandlerCallbackPointer, cancelled: Boolean, status: WebsocketCallbackResult, reason: String) { | ||
realmc.realm_sync_websocket_callback_complete(cancelled, nativePointer.cptr(), status.nativeValue, reason) | ||
} | ||
|
||
actual fun realm_sync_socket_websocket_connected(nativePointer: RealmWebsocketProviderPointer, protocol: String) { | ||
realmc.realm_sync_websocket_connected(nativePointer.cptr(), protocol) | ||
} | ||
|
||
actual fun realm_sync_socket_websocket_error(nativePointer: RealmWebsocketProviderPointer) { | ||
realmc.realm_sync_websocket_error(nativePointer.cptr()) | ||
} | ||
|
||
actual fun realm_sync_socket_websocket_message( | ||
nativePointer: RealmWebsocketProviderPointer, | ||
data: ByteArray | ||
): Boolean { | ||
return realmc.realm_sync_websocket_message(nativePointer.cptr(), data, data.size.toLong()) | ||
} | ||
|
||
actual fun realm_sync_socket_websocket_closed(nativePointer: RealmWebsocketProviderPointer, wasClean: Boolean, errorCode: WebsocketErrorCode, reason: String) { | ||
realmc.realm_sync_websocket_closed(nativePointer.cptr(), wasClean, errorCode.nativeValue, reason) | ||
} | ||
|
||
fun <T : CapiT> NativePointer<T>.cptr(): Long { | ||
return (this as LongPointerWrapper).ptr | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great description 💯