WebSocket API

This commit is contained in:
2023-03-14 16:22:50 +01:00
parent b6dba62fa4
commit fd828d600e
16 changed files with 910 additions and 3 deletions

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>pandalib-parent</artifactId>
<groupId>fr.pandacube.lib</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>pandalib-ws-server</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>fr.pandacube.lib</groupId>
<artifactId>pandalib-ws</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-jetty-api</artifactId>
<version>10.0.5</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,60 @@
package fr.pandacube.lib.ws.server;
import fr.pandacube.lib.ws.AbstractWS;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import java.io.IOException;
/**
* Minimal implementation of a Websocket server endpoint using the Jetty Websocket API.
*/
public abstract class AbstractServerWS extends WebSocketAdapter implements AbstractWS {
@Override
public final void onWebSocketConnect(Session sess)
{
super.onWebSocketConnect(sess);
onConnect();
}
@Override
public final void onWebSocketBinary(byte[] payload, int offset, int len) {
handleReceivedBinary();
}
@Override
public final void onWebSocketText(String message) {
handleReceivedMessage(message);
}
@Override
public final void onWebSocketClose(int statusCode, String reason) {
onClose(statusCode, reason);
}
@Override
public final void onWebSocketError(Throwable cause) {
onError(cause);
}
public final void sendString(String message) throws IOException {
getSession().getRemote().sendString(message);
}
@Override
public final void sendClose(int code, String reason) throws IOException {
getSession().close(code, reason);
}
@Override
public String getRemoteIdentifier() {
return getSession().getRemoteAddress().toString();
}
}

View File

@@ -0,0 +1,95 @@
package fr.pandacube.lib.ws.server;
import fr.pandacube.lib.ws.payloads.ErrorPayload;
import fr.pandacube.lib.ws.payloads.LoginPayload;
import fr.pandacube.lib.ws.payloads.LoginSucceedPayload;
import fr.pandacube.lib.ws.payloads.Payload;
import java.util.function.Supplier;
/**
* Websocket server endpoint that is protected with a key.
*/
public abstract class KeyProtectedServerWS extends AbstractServerWS {
private boolean loginSucceed = false;
private final Supplier<String> keySupplier;
/**
* Creates a websocket server endpoint protected by the key given by the provided {@link Supplier}.
* @param keySupplier a {@link Supplier} for the key.
*/
public KeyProtectedServerWS(Supplier<String> keySupplier) {
this.keySupplier = keySupplier;
}
@Override
public final void onConnect() {
// nothing, just wait for the client to login
}
@Override
public final void onReceivePayload(Payload payload) {
if (loginSucceed) {
onReceivePayloadLoggedIn(payload);
}
else if (payload instanceof LoginPayload login) {
if (keySupplier.get().equals(login.key)) {
loginSucceed = true;
trySendAsJson(new LoginSucceedPayload());
onLoginSucceed();
}
else {
logAndTrySendError(new ErrorPayload("Bad key"));
trySendClose();
}
}
else {
logAndTrySendError(new ErrorPayload("Please use the login packet first. Received " + payload.getClass().getSimpleName() + " instead."));
trySendClose();
}
}
@Override
public final void onClose(int code, String reason) {
if (loginSucceed) {
onCloseLoggedIn(code, reason);
}
}
@Override
public final void onError(Throwable cause) {
if (loginSucceed) {
onErrorLoggedIn(cause);
}
}
/**
* Called when the client endpoint is succesfully logged in.
*/
public abstract void onLoginSucceed();
/**
* Called on reception of a valid payload from the already logged in client.
* @param payload the received payload.
*/
public abstract void onReceivePayloadLoggedIn(Payload payload);
/**
* Called on reception of a websocket Close packet, only if the client endpoint is already logged in.
* The connection is closed after this method call.
* @param code the close code. 1000 for a normal closure.
* @param reason the close reason.
*/
public abstract void onCloseLoggedIn(int code, String reason);
/**
* Called when an error occurs with the websocket API, only if the client endpoint is already logged in.
* The connection is already closed when this method is called.
* @param cause the error cause.
*/
public abstract void onErrorLoggedIn(Throwable cause);
}