-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Feature request: Simple WebSockets Support Peer Review Issue #12644
Comments
Ok. Here are my tests using package org.example
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.ClassDiscriminatorMode
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonClassDiscriminator
import org.java_websocket.client.WebSocketClient
import org.java_websocket.drafts.Draft
import org.java_websocket.handshake.ServerHandshake
import java.net.URI
@Serializable
data class GameInfoData(val gameId: String)
@Serializable
data class GameData(val gameId: String, val content: String)
@JsonClassDiscriminator("type")
@Serializable
sealed class Message
@Serializable
@SerialName("Ping")
data object PingMessage : Message()
@Serializable
@SerialName("GameInfo")
data class GameInfoMessage(val data: GameInfoData) : Message()
@Serializable
@SerialName("GameUpdate")
data class GameUpdateMessage(val data: GameData) : Message()
@Serializable
data class ErrorData(val message: String)
@JsonClassDiscriminator("type")
@Serializable
sealed class Response
@Serializable
@SerialName("Pong")
data object PongResponse : Response()
@Serializable
@SerialName("GameData")
data class GameDataResponse(val data: GameData) : Response()
@Serializable
@SerialName("Error")
data class ErrorResponse(val data: ErrorData) : Response()
@OptIn(ExperimentalSerializationApi::class)
val json = Json {
// otherwise 'type' field is not included in serialized string
classDiscriminatorMode = ClassDiscriminatorMode.ALL_JSON_OBJECTS
}
class EmptyClient : WebSocketClient {
constructor(serverURI: URI) : super(serverURI)
constructor(serverUri: URI, draft: Draft) : super(serverUri, draft)
constructor(serverURI: URI, httpHeaders: Map<String, String>) : super(serverURI, httpHeaders)
override fun onOpen(handshakedata: ServerHandshake?) {
println("new connection opened")
// try sending some messages
send(json.encodeToString(PingMessage))
send(json.encodeToString(GameInfoMessage(GameInfoData("b78948eb-452f-42ea-8425-93dab002bcdc"))))
}
override fun onClose(code: Int, reason: String, remote: Boolean) {
println("closed with exit code $code additional info: $reason")
}
override fun onMessage(message: String) {
try {
when (val response: Response = json.decodeFromString(message)) {
is PongResponse -> println("Received Pong")
is GameDataResponse -> println("GameData: ${response.data}")
is ErrorResponse -> println("Error: ${response.data.message}")
else -> println("Unknown response: $message")
}
} catch (e: SerializationException) {
println("Failed to deserialize message: $message")
e.printStackTrace()
}
}
override fun onError(ex: Exception) {
System.err.println("an error occurred: $ex")
}
}
fun main() {
val url = "wss://ws.uncivserver.xyz/ws"
val headers = mapOf("Authorization" to "Basic ZjNiMGE0OWEtMjkyMC00OTg0LWE5YmUtOTk0OWNkMmIxYzA4Cg==")
val client = EmptyClient(URI(url), headers)
client.connect()
} |
This looks fine, however I think practically it won't make much of a difference. Unciv isn't an "always open" app, turns take several minutes, and so chances are that the app is closed at the time of the update. |
You can query the statuses of existing games once when you first connect / reconnect via WebSocket. This should mitigate such issues. Maybe we should retain preview functionality for this. (GameInfo, GameUpdate & GameData accepting preview gameId requests). |
The demo code was for my testing. Any support should add functionality for reconnecting after connection close. Which may happen often in Android. |
Note: Initial connection to |
Ok, after much deliberation, I have come to several conclusions:
Thus I have included 1 more client message type, which is {
"type": "SyncGames"
"data" {
"lastUpdatedList": [
// this is an array of objects of following type
{
"gameId": "<Some UUIDv4>",
"lastUpdated": 0 // number, contains lastUpdated UTC timestamp, the time when this game was last updated by the client
]
}
} After receiving this message the server will send |
@yairm210 need review!! |
Not sure what to tell you, looks probably fine? I'm not a websockets guy |
Before creating
Problem Description
We need
WebSocket
to reduce network traffic. Everyone knows that. Now I am here to bother the devs to implement it. But fear not, I made a demo server that you can test and a demo spec sheet also!Related Issue Links
No response
Desired Solution
The design goal is simple. The initial
WebSocket
support should be something that has 0 conflict with current multiplayer API's and should be able co-exist with it. There should be no need to upgrade to a higher version of Unciv or increment save file version for it to work. Unciv should be able use it if available and fallback to files API if not. But a connection overWebSocket
should be preferred over polling over HTTP, that's all.Current Design (Theory)
Unciv
ws://${multiplayerServerURL}/ws
if the server url starts withhttp://
orwss://${multiplayerServerURL}/ws
is if the server url starts withhttps://
.Multiplayer Server
userId
from the Auth headers that Unciv already sends (This can be changed to query string if requested). Internally subscribe Unciv to a channel nameduser:${userId}
. (This can be changed togame:${gameId}
if requested)playerId
's ingameParameters.players
. This eliminates the necessity for the player to let the server know of every game it has been playing every time it makes a connection. From client side, this is received like any other message as usual.Notes: All messages exchanged should be valid in JSON format.
Current Design (Schemas)
Unciv (Client)
Multiplayer Server (Server)
UncivServer.xyz WebSocket Support PR
touhidurrr/UncivServer.xyz#53
Test Server
Endpoint: https://ws.uncivserver.xyz
WebSocket:
wss://ws.uncivserver.xyz/ws
Note: Initial connection to
wss://ws.uncivserver.xyz/ws
may take some time as Render aggressively makes the server down on inactivity.Alternative Approaches
You suggest I change the spec sheet. Peer reviewed, there you go!
Additional Context
No response
The text was updated successfully, but these errors were encountered: