aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrumeet <yuuta@yuuta.moe>2022-07-13 12:44:49 -0700
committerTrumeet <yuuta@yuuta.moe>2022-07-13 12:44:49 -0700
commit8af5fa7157be6bfec041cbfebb55f4503892f4ab (patch)
tree941aaa9d4c41e44122ae9ca778c5b51026bba587
parente26b8e3093c7ce17b365cfdb179e088054a3738d (diff)
downloadacron-8af5fa7157be6bfec041cbfebb55f4503892f4ab.tar
acron-8af5fa7157be6bfec041cbfebb55f4503892f4ab.tar.gz
acron-8af5fa7157be6bfec041cbfebb55f4503892f4ab.tar.bz2
acron-8af5fa7157be6bfec041cbfebb55f4503892f4ab.zip
Add error codes to distinguish invalid requests and server errors
API:ADDITION Signed-off-by: Trumeet <yuuta@yuuta.moe>
-rw-r--r--README.md6
-rw-r--r--src/main/java/moe/ymc/acron/net/WSFrameHandler.java17
-rw-r--r--src/main/java/moe/ymc/acron/s2c/response/EventError.java10
-rw-r--r--src/main/java/moe/ymc/acron/serialization/Serializer.java10
4 files changed, 35 insertions, 8 deletions
diff --git a/README.md b/README.md
index c68122f..e1284a6 100644
--- a/README.md
+++ b/README.md
@@ -219,10 +219,16 @@ codes, all faulty WebSocket requests will receive error in the following format:
{
"type": "error",
"id": 1,
+ "code": 500,
"message": "Error message. Not machine-readable."
}
```
+Parameters:
+
+* `.code` (int, HTTP status codes, always present): The machine-readable error code (e. g. 400 for Bad Request).
+* `.message` (string, any, always present): The human-readable error message.
+
**`.type` and `.id` are included in every request / response, except for further noticed. Thus,
this document excludes them from the parameter lists.**
diff --git a/src/main/java/moe/ymc/acron/net/WSFrameHandler.java b/src/main/java/moe/ymc/acron/net/WSFrameHandler.java
index c578f2e..713d433 100644
--- a/src/main/java/moe/ymc/acron/net/WSFrameHandler.java
+++ b/src/main/java/moe/ymc/acron/net/WSFrameHandler.java
@@ -1,5 +1,6 @@
package moe.ymc.acron.net;
+import com.google.gson.JsonParseException;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.*;
@@ -57,10 +58,18 @@ public class WSFrameHandler extends SimpleChannelInboundHandler<WebSocketFrame>
final ClientIdentification identification = ctx.channel().attr(Attributes.ID).get();
final ClientConfiguration configuration = ctx.channel().attr(Attributes.CONFIGURATION).get();
- int id = -2;
+ int id;
+ final Request request;
try {
- final Request request = Serializer.deserialize(frame);
+ request = Serializer.deserialize(frame);
id = request.getId();
+ } catch (JsonParseException | IllegalArgumentException | IllegalStateException e) {
+ ctx.channel().writeAndFlush(
+ Serializer.serialize(new EventError(-2, EventError.Code.BAD_REQUEST.value, e.getMessage()))
+ );
+ return;
+ }
+ try {
if (request instanceof final ReqCmd reqCmd) {
LOGGER.info("Client {} executed a command: `{}`.",
identification.client().id(),
@@ -90,7 +99,9 @@ public class WSFrameHandler extends SimpleChannelInboundHandler<WebSocketFrame>
"This may just be a malformed request. " +
"It is reported to the client.",
e);
- ctx.channel().writeAndFlush(Serializer.serialize(new EventError(id, e.getMessage())));
+ ctx.channel().writeAndFlush(
+ Serializer.serialize(new EventError(id, EventError.Code.SERVER_ERROR.value, e.getMessage()))
+ );
}
}
diff --git a/src/main/java/moe/ymc/acron/s2c/response/EventError.java b/src/main/java/moe/ymc/acron/s2c/response/EventError.java
index 48d2683..d2a03c3 100644
--- a/src/main/java/moe/ymc/acron/s2c/response/EventError.java
+++ b/src/main/java/moe/ymc/acron/s2c/response/EventError.java
@@ -5,6 +5,16 @@ import moe.ymc.acron.s2c.Event;
import org.jetbrains.annotations.Nullable;
public record EventError(@SerializedName("id") int id,
+ @SerializedName("code") int code,
@SerializedName("message") @Nullable String message)
implements Event {
+ public enum Code {
+ SERVER_ERROR(500),
+ BAD_REQUEST(400);
+
+ public final int value;
+ Code(int value) {
+ this.value = value;
+ }
+ }
}
diff --git a/src/main/java/moe/ymc/acron/serialization/Serializer.java b/src/main/java/moe/ymc/acron/serialization/Serializer.java
index 900d6fc..6d06388 100644
--- a/src/main/java/moe/ymc/acron/serialization/Serializer.java
+++ b/src/main/java/moe/ymc/acron/serialization/Serializer.java
@@ -2,6 +2,7 @@ package moe.ymc.acron.serialization;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
+import com.google.gson.JsonParseException;
import com.google.gson.typeadapters.RuntimeTypeAdapterFactory;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import moe.ymc.acron.c2s.ReqCmd;
@@ -14,13 +15,13 @@ import org.jetbrains.annotations.NotNull;
public class Serializer {
@NotNull
- public static Request deserialize(@NotNull TextWebSocketFrame frame) {
+ public static Request deserialize(@NotNull TextWebSocketFrame frame)
+ throws JsonParseException, IllegalArgumentException, IllegalStateException {
final String text = frame.text();
final RuntimeTypeAdapterFactory<Request> adapter =
RuntimeTypeAdapterFactory.of(Request.class, "type")
.registerSubtype(ReqSetConfig.class, "set_config")
- .registerSubtype(ReqCmd.class, "cmd")
- ;
+ .registerSubtype(ReqCmd.class, "cmd");
final Gson gson = new GsonBuilder()
.registerTypeAdapter(ReqSetConfig.class, new ReqSetConfig.ReqSetConfigDeserializer())
.registerTypeAdapter(ReqSetConfig.Vec3d.class, new ReqSetConfig.Vec3d.Vec3dDeserializer())
@@ -46,8 +47,7 @@ public class Serializer {
.registerSubtype(EventLagging.class, "lagging")
.registerSubtype(EventCmdDenied.class, "cmd_denied")
.registerSubtype(EventError.class, "error")
- .registerSubtype(EventOk.class, "ok")
- ;
+ .registerSubtype(EventOk.class, "ok");
final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(adapter)
.create();