[FEATURE] Вывод человекочитаемой ошибки при исключении в Response

This commit is contained in:
Gravit 2019-04-20 03:51:27 +07:00
parent 4de0891dcc
commit b55e6f1f40
6 changed files with 38 additions and 160 deletions

View file

@ -245,6 +245,7 @@ public class LauncherConf
public class NettyConfig { public class NettyConfig {
public boolean clientEnabled; public boolean clientEnabled;
public boolean sendExcptionEnabled;
public String launcherURL; public String launcherURL;
public String downloadURL; public String downloadURL;
public String launcherEXEURL; public String launcherEXEURL;

View file

@ -1,82 +0,0 @@
package ru.gravit.launchserver.websocket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.CharsetUtil;
import static io.netty.handler.codec.http.HttpMethod.GET;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import static io.netty.handler.codec.rtsp.RtspResponseStatuses.NOT_FOUND;
public class WebSocketIndexPageHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
private final String websocketPath;
public WebSocketIndexPageHandler(String websocketPath) {
this.websocketPath = websocketPath;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) {
// Handle a bad request.
if (!req.decoderResult().isSuccess()) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
return;
}
// Allow only GET methods.
if (req.method() != GET) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
return;
}
// Send the index page
if ("/".equals(req.uri()) || "/index.html".equals(req.uri())) {
String webSocketLocation = getWebSocketLocation(ctx.pipeline(), req, websocketPath);
ByteBuf content = WebSocketServerIndexPage.getContent(webSocketLocation);
FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
res.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
HttpUtil.setContentLength(res, content.readableBytes());
sendHttpResponse(ctx, req, res);
} else {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND));
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
// Generate an error page if response getStatus code is not OK (200).
if (res.status().code() != 200) {
ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);
res.content().writeBytes(buf);
buf.release();
HttpUtil.setContentLength(res, res.content().readableBytes());
}
// Send the response and close the connection if necessary.
ChannelFuture f = ctx.channel().writeAndFlush(res);
if (!HttpUtil.isKeepAlive(req) || res.status().code() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
}
private static String getWebSocketLocation(ChannelPipeline cp, HttpRequest req, String path) {
String protocol = "ws";
if (cp.get(SslHandler.class) != null) {
// SSL in use so use Secure WebSockets
protocol = "wss";
}
return protocol + "://" + req.headers().get(HttpHeaderNames.HOST) + path;
}
}

View file

@ -1,61 +0,0 @@
package ru.gravit.launchserver.websocket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.CharsetUtil;
public final class WebSocketServerIndexPage {
private static final String NEWLINE = "\r\n";
public static ByteBuf getContent(String webSocketLocation) {
return Unpooled.copiedBuffer(
"<html><head><title>Web Socket Test</title></head>" + NEWLINE +
"<body>" + NEWLINE +
"<script type=\"text/javascript\">" + NEWLINE +
"var socket;" + NEWLINE +
"if (!window.WebSocket) {" + NEWLINE +
" window.WebSocket = window.MozWebSocket;" + NEWLINE +
'}' + NEWLINE +
"if (window.WebSocket) {" + NEWLINE +
" socket = new WebSocket(\"" + webSocketLocation + "\");" + NEWLINE +
" socket.onmessage = function(event) {" + NEWLINE +
" var ta = document.getElementById('responseText');" + NEWLINE +
" ta.value = ta.value + '\\n' + event.data" + NEWLINE +
" };" + NEWLINE +
" socket.onopen = function(event) {" + NEWLINE +
" var ta = document.getElementById('responseText');" + NEWLINE +
" ta.value = \"Web Socket opened!\";" + NEWLINE +
" };" + NEWLINE +
" socket.onclose = function(event) {" + NEWLINE +
" var ta = document.getElementById('responseText');" + NEWLINE +
" ta.value = ta.value + \"Web Socket closed\"; " + NEWLINE +
" };" + NEWLINE +
"} else {" + NEWLINE +
" alert(\"Your browser does not support Web Socket.\");" + NEWLINE +
'}' + NEWLINE +
NEWLINE +
"function send(message) {" + NEWLINE +
" if (!window.WebSocket) { return; }" + NEWLINE +
" if (socket.readyState == WebSocket.OPEN) {" + NEWLINE +
" socket.send(message);" + NEWLINE +
" } else {" + NEWLINE +
" alert(\"The socket is not open.\");" + NEWLINE +
" }" + NEWLINE +
'}' + NEWLINE +
"</script>" + NEWLINE +
"<form onsubmit=\"return false;\">" + NEWLINE +
"<input type=\"text\" name=\"message\" value=\"Hello, World!\"/>" +
"<input type=\"button\" value=\"Send Web Socket Data\"" + NEWLINE +
" onclick=\"send(this.form.message.value)\" />" + NEWLINE +
"<h3>Output</h3>" + NEWLINE +
"<textarea id=\"responseText\" style=\"width:500px;height:300px;\"></textarea>" + NEWLINE +
"</form>" + NEWLINE +
"</body>" + NEWLINE +
"</html>" + NEWLINE, CharsetUtil.US_ASCII);
}
private WebSocketServerIndexPage() {
// Unused
}
}

View file

@ -7,6 +7,9 @@
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.ChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import ru.gravit.launcher.events.ExceptionEvent;
import ru.gravit.launcher.events.RequestEvent;
import ru.gravit.launcher.events.request.ErrorRequestEvent;
import ru.gravit.launcher.hasher.HashedEntry; import ru.gravit.launcher.hasher.HashedEntry;
import ru.gravit.launcher.hasher.HashedEntryAdapter; import ru.gravit.launcher.hasher.HashedEntryAdapter;
import ru.gravit.launcher.request.JsonResultSerializeAdapter; import ru.gravit.launcher.request.JsonResultSerializeAdapter;
@ -66,7 +69,20 @@ void process(ChannelHandlerContext ctx, TextWebSocketFrame frame, Client client)
response.execute(ctx, client); response.execute(ctx, client);
} catch (Exception e) { } catch (Exception e) {
LogHelper.error(e); LogHelper.error(e);
sendObject(ctx, new ExceptionResult(e)); RequestEvent event;
if(server.config.netty.sendExcptionEnabled)
{
event = new ExceptionEvent(e);
}
else
{
event = new ErrorRequestEvent("Fatal server error. Contact administrator");
}
if(response instanceof SimpleResponse)
{
event.requestUUID = ((SimpleResponse) response).requestUUID;
}
sendObject(ctx, event);
} }
} }
@ -134,20 +150,4 @@ public String getType() {
} }
} }
public static class ExceptionResult implements ResultInterface {
public ExceptionResult(Exception e) {
this.message = e.getMessage();
this.clazz = e.getClass().getName();
this.type = "exceptionError";
}
public final String message;
public final String clazz;
public final String type;
@Override
public String getType() {
return "exception";
}
}
} }

View file

@ -3,6 +3,7 @@
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import org.java_websocket.handshake.ServerHandshake; import org.java_websocket.handshake.ServerHandshake;
import ru.gravit.launcher.events.ExceptionEvent;
import ru.gravit.launcher.events.request.*; import ru.gravit.launcher.events.request.*;
import ru.gravit.launcher.hasher.HashedEntry; import ru.gravit.launcher.hasher.HashedEntry;
import ru.gravit.launcher.hasher.HashedEntryAdapter; import ru.gravit.launcher.hasher.HashedEntryAdapter;
@ -127,6 +128,7 @@ public void registerResults() {
registerResult("log", LogEvent.class); registerResult("log", LogEvent.class);
registerResult("execCmd", ExecCommandRequestEvent.class); registerResult("execCmd", ExecCommandRequestEvent.class);
registerResult("getAvailabilityAuth", GetAvailabilityAuthRequestEvent.class); registerResult("getAvailabilityAuth", GetAvailabilityAuthRequestEvent.class);
registerResult("exception", ExceptionEvent.class);
} }
public void registerHandler(EventHandler eventHandler) { public void registerHandler(EventHandler eventHandler) {

View file

@ -0,0 +1,18 @@
package ru.gravit.launcher.events;
import ru.gravit.launcher.events.RequestEvent;
public class ExceptionEvent extends RequestEvent {
public ExceptionEvent(Exception e) {
this.message = e.getMessage();
this.clazz = e.getClass().getName();
}
public final String message;
public final String clazz;
@Override
public String getType() {
return "exception";
}
}