diff --git a/server/core/src/main/java/dev/slimevr/websocketapi/WebsocketAPI.java b/server/core/src/main/java/dev/slimevr/websocketapi/WebsocketAPI.java deleted file mode 100644 index 0e3cf870e..000000000 --- a/server/core/src/main/java/dev/slimevr/websocketapi/WebsocketAPI.java +++ /dev/null @@ -1,111 +0,0 @@ -package dev.slimevr.websocketapi; - -import dev.slimevr.VRServer; -import dev.slimevr.protocol.GenericConnection; -import dev.slimevr.protocol.ProtocolAPI; -import dev.slimevr.protocol.ProtocolAPIServer; -import io.eiren.util.logging.LogManager; -import org.java_websocket.WebSocket; -import org.java_websocket.drafts.Draft_6455; -import org.java_websocket.handshake.ClientHandshake; -import org.java_websocket.server.WebSocketServer; -import org.jetbrains.annotations.NotNull; - -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.util.Collections; -import java.util.Objects; -import java.util.stream.Stream; - - -public class WebsocketAPI extends WebSocketServer implements ProtocolAPIServer { - - public final VRServer server; - public final ProtocolAPI protocolAPI; - - public WebsocketAPI(VRServer server, ProtocolAPI protocolAPI) { - super(new InetSocketAddress(21110), Collections.singletonList(new Draft_6455())); - this.server = server; - this.protocolAPI = protocolAPI; - - this.protocolAPI.registerAPIServer(this); - setReuseAddr(true); - } - - @Override - public void onOpen(WebSocket conn, ClientHandshake handshake) { - LogManager - .info( - "[WebSocketAPI] New connection from: " - + conn.getRemoteSocketAddress().getAddress().getHostAddress() - ); - conn.setAttachment(new WebsocketConnection(conn)); - } - - /** - * Helper function to get the string of the `conn` while handling `null` - */ - protected static String connAddr(WebSocket conn) { - if (conn == null) { - return "null"; - } - var remote = conn.getRemoteSocketAddress(); - if (remote == null) { - return conn.toString(); - } - var addr = remote.getAddress(); - if (addr == null) { - return remote.toString(); - } - return addr.getHostAddress(); - } - - @Override - public void onClose(WebSocket conn, int code, String reason, boolean remote) { - LogManager - .info( - "[WebSocketAPI] Disconnected: " - + connAddr(conn) - + ", (" - + code - + ") " - + reason - + ". Remote: " - + remote - ); - } - - @Override - public void onMessage(WebSocket conn, String message) { - } - - @Override - public void onMessage(WebSocket conn, ByteBuffer message) { - var connection = conn.getAttachment(); - if (connection != null) - this.protocolAPI.onMessage(connection, message); - } - - @Override - public void onError(WebSocket conn, Exception ex) { - LogManager - .severe( - "[WebSocket] Exception on connection " + connAddr(conn), - ex - ); - } - - @Override - public void onStart() { - LogManager.info("[WebSocketAPI] Web Socket API started on port " + getPort()); - setConnectionLostTimeout(0); - } - - @Override - public @NotNull Stream getApiConnections() { - return this.getConnections().stream().map(conn -> { - var c = conn.getAttachment(); - return (GenericConnection) c; - }).filter(Objects::nonNull); - } -} diff --git a/server/core/src/main/java/dev/slimevr/websocketapi/WebsocketAPI.kt b/server/core/src/main/java/dev/slimevr/websocketapi/WebsocketAPI.kt new file mode 100644 index 000000000..06ef66605 --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/websocketapi/WebsocketAPI.kt @@ -0,0 +1,71 @@ +package dev.slimevr.websocketapi + +import dev.slimevr.VRServer +import dev.slimevr.protocol.GenericConnection +import dev.slimevr.protocol.ProtocolAPI +import dev.slimevr.protocol.ProtocolAPIServer +import io.eiren.util.logging.LogManager +import org.java_websocket.WebSocket +import org.java_websocket.drafts.Draft_6455 +import org.java_websocket.handshake.ClientHandshake +import org.java_websocket.server.WebSocketServer +import java.net.InetSocketAddress +import java.nio.ByteBuffer +import java.util.stream.Stream + +open class WebsocketAPI(val server: VRServer, val protocolAPI: ProtocolAPI) : + WebSocketServer(InetSocketAddress(21110), mutableListOf(Draft_6455())), + ProtocolAPIServer { + init { + protocolAPI.registerAPIServer(this) + isReuseAddr = true + } + + override fun onOpen(conn: WebSocket, handshake: ClientHandshake) { + LogManager.info("[WebSocketAPI] New connection from ${conn.remoteSocketAddress.address.hostAddress}") + conn.setAttachment(WebsocketConnection(conn)) + } + + override fun onClose(conn: WebSocket, code: Int, reason: String, remote: Boolean) { + LogManager.info("[WebSocketAPI] Disconnected: ${connAddr(conn)}, ($code) $reason. Remote: $remote") + } + + override fun onMessage(conn: WebSocket, message: String) { + } + + override fun onMessage(conn: WebSocket, message: ByteBuffer) { + val connection = conn.getAttachment() ?: return + protocolAPI.onMessage(connection, message) + } + + override fun onError(conn: WebSocket, ex: Exception) { + LogManager + .severe("[WebSocket] Exception on connection ${connAddr(conn)}", ex) + } + + override fun onStart() { + LogManager.info("[WebSocketAPI] Started on port ${getPort()}") + connectionLostTimeout = 0 + } + + override val apiConnections: Stream + get() = connections + .stream() + .map { conn: WebSocket -> + conn.getAttachment() as GenericConnection? + } + .filter { it != null } + .map { it!! } + + companion object { + /** + * Helper function to get the string of the `conn` while handling `null` + */ + protected fun connAddr(conn: WebSocket?): String { + if (conn == null) return "null" + + val remote = conn.remoteSocketAddress ?: return conn.toString() + return remote.address?.hostAddress ?: return remote.toString() + } + } +} diff --git a/server/core/src/main/java/dev/slimevr/websocketapi/WebsocketConnection.java b/server/core/src/main/java/dev/slimevr/websocketapi/WebsocketConnection.java deleted file mode 100644 index 73340b744..000000000 --- a/server/core/src/main/java/dev/slimevr/websocketapi/WebsocketConnection.java +++ /dev/null @@ -1,44 +0,0 @@ -package dev.slimevr.websocketapi; - -import dev.slimevr.protocol.ConnectionContext; -import dev.slimevr.protocol.GenericConnection; -import org.java_websocket.WebSocket; -import org.java_websocket.exceptions.WebsocketNotConnectedException; - -import java.nio.ByteBuffer; -import java.util.UUID; - - -public class WebsocketConnection implements GenericConnection { - - public final ConnectionContext context; - public final WebSocket conn; - public UUID id; - - public WebsocketConnection(WebSocket conn) { - this.context = new ConnectionContext(); - this.conn = conn; - this.id = UUID.randomUUID(); - } - - @Override - public ConnectionContext getContext() { - return this.context; - } - - @Override - public void send(ByteBuffer bytes) { - if (this.conn.isOpen()) { - try { - this.conn.send(bytes.slice()); - } catch (WebsocketNotConnectedException ignored) { - // Race condition if it closes between our check and sending - } - } - } - - @Override - public UUID getConnectionId() { - return id; - } -} diff --git a/server/core/src/main/java/dev/slimevr/websocketapi/WebsocketConnection.kt b/server/core/src/main/java/dev/slimevr/websocketapi/WebsocketConnection.kt new file mode 100644 index 000000000..593902f31 --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/websocketapi/WebsocketConnection.kt @@ -0,0 +1,23 @@ +package dev.slimevr.websocketapi + +import dev.slimevr.protocol.ConnectionContext +import dev.slimevr.protocol.GenericConnection +import org.java_websocket.WebSocket +import org.java_websocket.exceptions.WebsocketNotConnectedException +import java.nio.ByteBuffer +import java.util.* + +class WebsocketConnection(val conn: WebSocket) : GenericConnection { + override val context = ConnectionContext() + override val connectionId: UUID = UUID.randomUUID() + + override fun send(bytes: ByteBuffer) { + if (this.conn.isOpen) { + try { + this.conn.send(bytes.slice()) + } catch (ignored: WebsocketNotConnectedException) { + // Race condition if it closes between our check and sending + } + } + } +}