For context, the server has a certificate signed for a CA. Today I was implementing a WebSocket in Android using StompClient, but the connection opens and closes immediately and throws the following error:
java.io.EOFException
at okio.RealBufferedSource.require(RealBufferedSource.kt:199)
at okio.RealBufferedSource.readByte(RealBufferedSource.kt:209)
at okhttp3.internal.ws.WebSocketReader.readHeader(WebSocketReader.kt:119)
at okhttp3.internal.ws.WebSocketReader.processNextFrame(WebSocketReader.kt:102)
at okhttp3.internal.ws.RealWebSocket.loopReader(RealWebSocket.kt:293)
at okhttp3.internal.ws.RealWebSocket$connect$1.onResponse(RealWebSocket.kt:195)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:920)
This is my first time implementing a WebSocket in Android, so here are the dependencies and logic that I am using to achieve this:
Dependency:
com.github.NaikSoftware:StompProtocolAndroid:1.6.6
Logic code:
private fun startWebSocketConnection() {
lifecycleScope.launch( defaultDispatcher) {
compositeDisposable.clear()
// Web Socket //
val url: String = "https://url.ca/guard-ws"
val rawClient = OkHttpClient.Builder().build()
val rawRequest = Request.Builder()
.url(url)
.addHeader("Authorization", "Bearer ${tokenInterceptor.token}")
.build()
rawClient.newWebSocket(rawRequest, object : WebSocketListener() {
override fun onOpen(ws: WebSocket, response: Response) {
Log.d("MyTag", "✅ onOpen: ${response.code}")
ws.send("CONNECT\naccept-version:1.1,1.2\nheart-beat:0,0\n\n\u0000")
}
override fun onMessage(ws: WebSocket, text: String) {
Log.d("MyTag", "📨 onMessage: $text")
}
override fun onClosing(ws: WebSocket, code: Int, reason: String) {
Log.d("MyTag", "🔴 onClosing: $code / $reason")
}
override fun onFailure(ws: WebSocket, t: Throwable, response: Response?) {
Log.e("MyTag", "❌ onFailure: ${t.message}", t)
}
})
webSocketVM.stompClient = Stomp
.over(
Stomp.ConnectionProvider.OKHTTP,
url,
null,
webSocketVM.getOkHttpClient()
)
.withServerHeartbeat(30000)
.withClientHeartbeat(30000)
val list = listOf(StompHeader("Authorization", "Bearer ${tokenInterceptor.token}"))
webSocketVM.stompClient?.let {
it.connect( list)
val main: Disposable = it.lifecycle()
.subscribe({ lifecycleEvent ->
when (lifecycleEvent.type) {
Type.OPENED -> {
Log.d("MyTag", "intentando con: $url")
Log.d("MyTag", "open")
}
Type.ERROR -> {
Log.d("MyTag", "Error: ${lifecycleEvent.exception}")
}
Type.CLOSED -> {
Log.d("MyTag", "closed")
}
Type.FAILED_SERVER_HEARTBEAT -> {
Log.d("MyTag", "failed server heartbeat")
}
else -> {}
}
}){ error: Throwable? -> Log.e( "MyTag", "error: ${error?.message} : Connection")}
compositeDisposable.add( main)
}
}
}
And here is the provided OkHttpClient for the WebSocket:
fun getOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder()
.addNetworkInterceptor(
HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.HEADERS
}
).build()
}