Skip to content

Commit

Permalink
incubating WebSocketNetworkTransport
Browse files Browse the repository at this point in the history
  • Loading branch information
martinbonnin committed Feb 28, 2024
1 parent 9bbdd32 commit c2e7a71
Show file tree
Hide file tree
Showing 36 changed files with 2,518 additions and 36 deletions.
2 changes: 2 additions & 0 deletions gradle/libraries.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ rx-java3 = "3.1.6"
sqldelight = "2.0.1"
truth = "1.1.3"
moshix = "0.14.1"
node-ws = "8.14.2"

[libraries]
android-plugin = { group = "com.android.tools.build", name = "gradle", version.ref = "android-plugin" }
Expand Down Expand Up @@ -74,6 +75,7 @@ apollo-normalizedcache-sqlite-incubating = { group = "com.apollographql.apollo3"
apollo-rx2-support-java = { group = "com.apollographql.apollo3", name = "apollo-rx2-support-java", version.ref = "apollo" }
apollo-plugin = { group = "com.apollographql.apollo3", name = "apollo-gradle-plugin", version.ref = "apollo" }
apollo-runtime = { group = "com.apollographql.apollo3", name = "apollo-runtime", version.ref = "apollo" }
apollo-websocket-network-transport-incubating = { group = "com.apollographql.apollo3", name = "apollo-websocket-network-transport-incubating", version.ref = "apollo" }
apollo-compiler = { group = "com.apollographql.apollo3", name = "apollo-compiler", version.ref = "apollo" }
apollo-execution = { group = "com.apollographql.apollo3", name = "apollo-execution-incubating", version.ref = "apollo" }
# Used by the apollo-tooling project which uses a published version of Apollo
Expand Down
5 changes: 5 additions & 0 deletions kotlin-js-store-2.0/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,11 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==

[email protected]:
version "8.14.2"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.2.tgz#6c249a806eb2db7a20d26d51e7709eab7b2e6c7f"
integrity sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==

[email protected]:
version "8.5.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
Expand Down
5 changes: 5 additions & 0 deletions libraries/apollo-api/api/apollo-api.api
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,11 @@ public final class com/apollographql/apollo3/exception/ApolloParseException : co
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Throwable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class com/apollographql/apollo3/exception/ApolloRetryException : com/apollographql/apollo3/exception/ApolloException {
public fun <init> (JLjava/lang/Throwable;)V
public final fun getAttempt ()J
}

public final class com/apollographql/apollo3/exception/ApolloWebSocketClosedException : com/apollographql/apollo3/exception/ApolloException {
public fun <init> (ILjava/lang/String;Ljava/lang/Throwable;)V
public synthetic fun <init> (ILjava/lang/String;Ljava/lang/Throwable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,10 @@ class ApolloCompositeException : ApolloException {

class AutoPersistedQueriesNotSupported : ApolloException(message = "The server does not support auto persisted queries")
class MissingValueException : ApolloException(message = "The optional doesn't have a value")

/**
* An operation should be retried.
*
* @property attempt the number of times the operation has already been attempted without success
*/
class ApolloRetryException(val attempt: Long, cause: Throwable) : ApolloException("The operation should be retried", cause)
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ internal class MockServerImpl(
}

is ConnectionClosed -> {
println("Connection Closed (${e.message})")
// Nothing, ignore those
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import kotlinx.coroutines.flow.map
import okio.Buffer
import okio.ByteString
import okio.ByteString.Companion.toByteString
import okio.IOException

internal suspend fun readFrames(reader: Reader, onMessage: (WebSocketMessage) -> Unit) {
val currentMessage = Buffer()
Expand All @@ -19,6 +20,17 @@ internal suspend fun readFrames(reader: Reader, onMessage: (WebSocketMessage) ->
}

while (true) {
/**
* Check if the client closed the connection
*/
if (reader.buffer.size == 0L) {
try {
reader.fillBuffer()
} catch (e: IOException) {
throw ConnectionClosed(e)
}
}

require(2)

var b = reader.buffer.readByte().toInt()
Expand Down
9 changes: 0 additions & 9 deletions libraries/apollo-runtime/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,3 @@ kotlin {
}
}

tasks.register("iOSSimTest") {
dependsOn("iosSimTestBinaries")
doLast {
val binary = kotlin.targets.getByName<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget>("iosSim").binaries.getTest("DEBUG").outputFile
exec {
commandLine = listOf("xcrun", "simctl", "spawn", "iPhone 8", binary.absolutePath)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,6 @@ actual class DefaultWebSocketEngine : WebSocketEngine {
}

/*
* The function below works due to ktor being used for the HTTP engine
* and how ktor imports ws, if this changes, ws would need to be added
* as a direct dependency.
*
* The following applies for lines below
* Copyright 2014-2019 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
* Some lines have been added/modified from the original source (https://github.com/ktorio/ktor/blob/f723638afd4d36024c390c5b79108b53ab513943/ktor-client/ktor-client-core/js/src/io/ktor/client/engine/js/JsClientEngine.kt#L62)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
public final class com/apollographql/apollo3/network/websocket/AppSyncWsProtocol : com/apollographql/apollo3/network/websocket/WsProtocol {
public static final field Companion Lcom/apollographql/apollo3/network/websocket/AppSyncWsProtocol$Companion;
public fun <init> ()V
public fun <init> (Lkotlin/jvm/functions/Function1;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun connectionInit (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun getAuthorization ()Lkotlin/jvm/functions/Function1;
public fun getName ()Ljava/lang/String;
public fun operationStart (Lcom/apollographql/apollo3/api/ApolloRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun operationStop (Lcom/apollographql/apollo3/api/ApolloRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun parseServerMessage (Ljava/lang/String;)Lcom/apollographql/apollo3/network/websocket/ServerMessage;
public fun ping (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun pong (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class com/apollographql/apollo3/network/websocket/AppSyncWsProtocol$Companion {
public final fun buildUrl (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)Ljava/lang/String;
public static synthetic fun buildUrl$default (Lcom/apollographql/apollo3/network/websocket/AppSyncWsProtocol$Companion;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;ILjava/lang/Object;)Ljava/lang/String;
}

public final class com/apollographql/apollo3/network/websocket/AppSyncWsProtocol$Factory : com/apollographql/apollo3/network/websocket/WsProtocol$Factory {
public fun <init> ()V
public final fun authorization (Lkotlin/jvm/functions/Function1;)Lcom/apollographql/apollo3/network/websocket/AppSyncWsProtocol$Factory;
public fun build ()Lcom/apollographql/apollo3/network/websocket/WsProtocol;
}

public abstract interface class com/apollographql/apollo3/network/websocket/ClientMessage {
}

public final class com/apollographql/apollo3/network/websocket/CompleteServerMessage : com/apollographql/apollo3/network/websocket/ServerMessage {
public fun <init> (Ljava/lang/String;)V
public final fun getId ()Ljava/lang/String;
}

public final class com/apollographql/apollo3/network/websocket/ConnectionAckServerMessage : com/apollographql/apollo3/network/websocket/ServerMessage {
public static final field INSTANCE Lcom/apollographql/apollo3/network/websocket/ConnectionAckServerMessage;
}

public final class com/apollographql/apollo3/network/websocket/ConnectionErrorServerMessage : com/apollographql/apollo3/network/websocket/ServerMessage {
public fun <init> (Ljava/lang/Object;)V
public final fun getPayload ()Ljava/lang/Object;
}

public final class com/apollographql/apollo3/network/websocket/ConnectionKeepAliveServerMessage : com/apollographql/apollo3/network/websocket/ServerMessage {
public static final field INSTANCE Lcom/apollographql/apollo3/network/websocket/ConnectionKeepAliveServerMessage;
}

public final class com/apollographql/apollo3/network/websocket/DataClientMessage : com/apollographql/apollo3/network/websocket/ClientMessage {
public fun <init> ([B)V
public final fun getData ()[B
}

public final class com/apollographql/apollo3/network/websocket/GeneralErrorServerMessage : com/apollographql/apollo3/network/websocket/ServerMessage {
public fun <init> (Ljava/lang/Exception;)V
public final fun getException ()Ljava/lang/Exception;
}

public final class com/apollographql/apollo3/network/websocket/GraphQLWsProtocol : com/apollographql/apollo3/network/websocket/WsProtocol {
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun connectionInit (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun getConnectionParams ()Lkotlin/jvm/functions/Function1;
public fun getName ()Ljava/lang/String;
public fun operationStart (Lcom/apollographql/apollo3/api/ApolloRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun operationStop (Lcom/apollographql/apollo3/api/ApolloRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun parseServerMessage (Ljava/lang/String;)Lcom/apollographql/apollo3/network/websocket/ServerMessage;
public fun ping (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun pong (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class com/apollographql/apollo3/network/websocket/GraphQLWsProtocol$Factory : com/apollographql/apollo3/network/websocket/WsProtocol$Factory {
public fun <init> ()V
public fun build ()Lcom/apollographql/apollo3/network/websocket/WsProtocol;
public final fun connectionParams (Lkotlin/jvm/functions/Function1;)Lcom/apollographql/apollo3/network/websocket/GraphQLWsProtocol$Factory;
}

public final class com/apollographql/apollo3/network/websocket/JvmWebSocketEngine : com/apollographql/apollo3/network/websocket/WebSocketEngine {
public fun <init> (Lokhttp3/OkHttpClient;)V
public fun newWebSocket (Ljava/lang/String;Ljava/util/List;Lcom/apollographql/apollo3/network/websocket/WebSocketListener;)Lcom/apollographql/apollo3/network/websocket/WebSocket;
}

public final class com/apollographql/apollo3/network/websocket/OperationErrorServerMessage : com/apollographql/apollo3/network/websocket/ServerMessage {
public fun <init> (Ljava/lang/String;Ljava/lang/Object;)V
public final fun getId ()Ljava/lang/String;
public final fun getPayload ()Ljava/lang/Object;
}

public final class com/apollographql/apollo3/network/websocket/ParseErrorServerMessage : com/apollographql/apollo3/network/websocket/ServerMessage {
public fun <init> (Ljava/lang/String;)V
public final fun getErrorMessage ()Ljava/lang/String;
}

public final class com/apollographql/apollo3/network/websocket/PingServerMessage : com/apollographql/apollo3/network/websocket/ServerMessage {
public static final field INSTANCE Lcom/apollographql/apollo3/network/websocket/PingServerMessage;
}

public final class com/apollographql/apollo3/network/websocket/PongServerMessage : com/apollographql/apollo3/network/websocket/ServerMessage {
public static final field INSTANCE Lcom/apollographql/apollo3/network/websocket/PongServerMessage;
}

public final class com/apollographql/apollo3/network/websocket/ResponseServerMessage : com/apollographql/apollo3/network/websocket/ServerMessage {
public fun <init> (Ljava/lang/String;Ljava/lang/Object;Z)V
public final fun getComplete ()Z
public final fun getId ()Ljava/lang/String;
public final fun getResponse ()Ljava/lang/Object;
}

public abstract interface class com/apollographql/apollo3/network/websocket/ServerMessage {
}

public final class com/apollographql/apollo3/network/websocket/SubscriptionWsProtocol : com/apollographql/apollo3/network/websocket/WsProtocol {
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun connectionInit (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun getConnectionParams ()Lkotlin/jvm/functions/Function1;
public fun getName ()Ljava/lang/String;
public fun operationStart (Lcom/apollographql/apollo3/api/ApolloRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun operationStop (Lcom/apollographql/apollo3/api/ApolloRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun parseServerMessage (Ljava/lang/String;)Lcom/apollographql/apollo3/network/websocket/ServerMessage;
public fun ping (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun pong (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class com/apollographql/apollo3/network/websocket/SubscriptionWsProtocol$Factory : com/apollographql/apollo3/network/websocket/WsProtocol$Factory {
public fun <init> ()V
public fun <init> (J)V
public fun <init> (JLkotlin/jvm/functions/Function1;)V
public fun <init> (JLkotlin/jvm/functions/Function1;Lcom/apollographql/apollo3/network/ws/WsFrameType;)V
public synthetic fun <init> (JLkotlin/jvm/functions/Function1;Lcom/apollographql/apollo3/network/ws/WsFrameType;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lkotlin/jvm/functions/Function1;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun build ()Lcom/apollographql/apollo3/network/websocket/WsProtocol;
}

public final class com/apollographql/apollo3/network/websocket/TextClientMessage : com/apollographql/apollo3/network/websocket/ClientMessage {
public fun <init> (Ljava/lang/String;)V
public final fun getText ()Ljava/lang/String;
}

public abstract interface class com/apollographql/apollo3/network/websocket/WebSocket {
public abstract fun close (ILjava/lang/String;)V
public abstract fun connect ()V
public abstract fun send (Ljava/lang/String;)V
public abstract fun send ([B)V
}

public abstract interface class com/apollographql/apollo3/network/websocket/WebSocketEngine {
public abstract fun newWebSocket (Ljava/lang/String;Ljava/util/List;Lcom/apollographql/apollo3/network/websocket/WebSocketListener;)Lcom/apollographql/apollo3/network/websocket/WebSocket;
public static synthetic fun newWebSocket$default (Lcom/apollographql/apollo3/network/websocket/WebSocketEngine;Ljava/lang/String;Ljava/util/List;Lcom/apollographql/apollo3/network/websocket/WebSocketListener;ILjava/lang/Object;)Lcom/apollographql/apollo3/network/websocket/WebSocket;
}

public final class com/apollographql/apollo3/network/websocket/WebSocketEngine_jvmKt {
public static final fun WebSocketEngine ()Lcom/apollographql/apollo3/network/websocket/WebSocketEngine;
}

public abstract interface class com/apollographql/apollo3/network/websocket/WebSocketListener {
public abstract fun onClosed (Ljava/lang/Integer;Ljava/lang/String;)V
public abstract fun onError (Ljava/lang/Throwable;)V
public abstract fun onMessage (Ljava/lang/String;)V
public abstract fun onMessage ([B)V
public abstract fun onOpen ()V
}

public final class com/apollographql/apollo3/network/websocket/WebSocketNetworkTransport : com/apollographql/apollo3/network/NetworkTransport {
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;Ljava/util/List;Lcom/apollographql/apollo3/network/websocket/WebSocketEngine;JLcom/apollographql/apollo3/network/websocket/WsProtocol$Factory;Lkotlin/jvm/functions/Function3;JJZLkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun closeConnection (Ljava/lang/Throwable;)V
public fun dispose ()V
public fun execute (Lcom/apollographql/apollo3/api/ApolloRequest;)Lkotlinx/coroutines/flow/Flow;
public final fun getAttempt ()J
public final fun getSubscriptionCount ()Lkotlinx/coroutines/flow/MutableStateFlow;
public final fun setAttempt (J)V
}

public final class com/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Builder {
public fun <init> ()V
public final fun addHeader (Ljava/lang/String;Ljava/lang/String;)Lcom/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Builder;
public final fun build ()Lcom/apollographql/apollo3/network/websocket/WebSocketNetworkTransport;
public final fun connectionAcknowledgeTimeoutMillis (J)Lcom/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Builder;
public final fun enableReopen (Z)Lcom/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Builder;
public final fun headers (Ljava/util/List;)Lcom/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Builder;
public final fun idleTimeoutMillis (J)Lcom/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Builder;
public final fun pingIntervalMillis (J)Lcom/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Builder;
public final fun protocol (Lcom/apollographql/apollo3/network/websocket/WsProtocol$Factory;)Lcom/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Builder;
public final fun reopenWhen (Lkotlin/jvm/functions/Function3;)Lcom/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Builder;
public final fun serverUrl (Ljava/lang/String;)Lcom/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Builder;
public final fun serverUrl (Lkotlin/jvm/functions/Function1;)Lcom/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Builder;
public final fun webSocketEngine (Lcom/apollographql/apollo3/network/websocket/WebSocketEngine;)Lcom/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Builder;
public final fun wsProtocolFactory (Lcom/apollographql/apollo3/network/websocket/WsProtocol$Factory;)Lcom/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Builder;
}

public abstract interface class com/apollographql/apollo3/network/websocket/WebSocketNetworkTransport$Event {
}

public abstract interface class com/apollographql/apollo3/network/websocket/WsProtocol {
public abstract fun connectionInit (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun getName ()Ljava/lang/String;
public abstract fun operationStart (Lcom/apollographql/apollo3/api/ApolloRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun operationStop (Lcom/apollographql/apollo3/api/ApolloRequest;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun parseServerMessage (Ljava/lang/String;)Lcom/apollographql/apollo3/network/websocket/ServerMessage;
public abstract fun ping (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun pong (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public abstract interface class com/apollographql/apollo3/network/websocket/WsProtocol$Factory {
public abstract fun build ()Lcom/apollographql/apollo3/network/websocket/WsProtocol;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
plugins {
id("org.jetbrains.kotlin.multiplatform")
}

apolloLibrary(
javaModuleName = "com.apollographql.apollo3.network.websocket",
withLinux = false
)

kotlin {
sourceSets {
findByName("commonMain")?.apply {
dependencies {
api(project(":apollo-runtime"))
api(project(":apollo-mpp-utils"))
api(libs.atomicfu)
}
}

findByName("commonTest")?.apply {
dependencies {
implementation(project(":apollo-mockserver"))
implementation(project(":apollo-testing-support")) {
because("runTest")
}
}
}

findByName("jsMain")?.apply {
dependencies {
/**
* WebSocket implementation for node
*/
api(npm("ws", libs.versions.node.ws.get()))
/**
* Kotlin Node declarations
*
* The situation is a bit weird because jsMain has both browser and node dependencies but
* there is not much we can do about it
* See https://youtrack.jetbrains.com/issue/KT-47038
*/
implementation(libs.kotlin.node)
}
}
}
}
Loading

0 comments on commit c2e7a71

Please sign in to comment.