Fix issues with Webview logger

* Decreased left margin
* Autoscroll goes all the way until the last packet
* Clear text fixed
* Still the first crypto-related packets don't wrap properly
This commit is contained in:
XePeleato 2020-09-27 16:29:11 +02:00
parent c6f2cd75b3
commit f1fcc389c8
4 changed files with 105 additions and 108 deletions

View File

@ -144,11 +144,6 @@
<artifactId>json</artifactId> <artifactId>json</artifactId>
<version>20190722</version> <version>20190722</version>
</dependency> </dependency>
<dependency>
<groupId>org.fxmisc.richtext</groupId>
<artifactId>richtextfx</artifactId>
<version>0.10.5</version>
</dependency>
<dependency> <dependency>
<groupId>org.jsoup</groupId> <groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId> <artifactId>jsoup</artifactId>

View File

@ -1,13 +1,12 @@
package gearth.ui.extensions.logger; package gearth.ui.extensions.logger;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.concurrent.Worker;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.fxmisc.flowless.VirtualizedScrollPane;
import org.fxmisc.richtext.StyleClassedTextArea;
import org.fxmisc.richtext.model.StyleSpansBuilder;
import java.net.URL; import java.net.URL;
import java.util.*; import java.util.*;
@ -16,57 +15,42 @@ public class ExtensionLoggerController implements Initializable {
public BorderPane borderPane; public BorderPane borderPane;
private Stage stage = null; private Stage stage = null;
private StyleClassedTextArea area; private WebView webView;
private volatile boolean initialized = false; private volatile boolean initialized = false;
private final List<Element> appendOnLoad = new ArrayList<>(); private final List<String> appendOnLoad = new LinkedList<>();
@Override @Override
public void initialize(URL arg0, ResourceBundle arg1) { public void initialize(URL arg0, ResourceBundle arg1) {
area = new StyleClassedTextArea(); webView = new WebView();
area.getStyleClass().add("white");
area.setWrapText(true);
area.setEditable(false);
VirtualizedScrollPane<StyleClassedTextArea> vsPane = new VirtualizedScrollPane<>(area); borderPane.setCenter(webView);
borderPane.setCenter(vsPane);
synchronized (appendOnLoad) { webView.getEngine().getLoadWorker().stateProperty().addListener((observableValue, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
initialized = true; initialized = true;
if (!appendOnLoad.isEmpty()) { webView.prefHeightProperty().bind(stage.heightProperty());
webView.prefWidthProperty().bind(stage.widthProperty());
appendLog(appendOnLoad); appendLog(appendOnLoad);
appendOnLoad.clear();
}
} }
});
webView.getEngine().load(getClass().getResource("/gearth/ui/logger/uilogger/logger.html").toString());
} }
private synchronized void appendLog(List<Element> elements) { private synchronized void appendLog(List<String> html) {
Platform.runLater(() -> { Platform.runLater(() -> {
StringBuilder sb = new StringBuilder(); String script = "document.getElementById('output').innerHTML += '" + String.join("", html) + "';";
StyleSpansBuilder<Collection<String>> styleSpansBuilder = new StyleSpansBuilder<>(0); webView.getEngine().executeScript(script);
for (Element element : elements) { executejQuery(webView.getEngine(), "$('html, body').animate({scrollTop:$(document).height()}, 'slow');");
sb.append(element.text);
styleSpansBuilder.add(Collections.singleton(element.className), element.text.length());
}
int oldLen = area.getLength();
area.appendText(sb.toString());
// System.out.println(sb.toString());
area.setStyleSpans(oldLen, styleSpansBuilder.create());
// if (autoScroll) {
area.moveTo(area.getLength());
area.requestFollowCaret();
// }
}); });
} }
void log(String s) { void log(String s) {
s = cleanTextContent(s); s = cleanTextContent(s);
ArrayList<Element> elements = new ArrayList<>(); List<String> elements = new LinkedList<>();
String classname, text; String classname, text;
if (s.startsWith("[") && s.contains("]")) { if (s.startsWith("[") && s.contains("]")) {
@ -82,9 +66,9 @@ public class ExtensionLoggerController implements Initializable {
int index = text.indexOf(" --> ") + 5; int index = text.indexOf(" --> ") + 5;
String extensionAnnouncement = text.substring(0, index); String extensionAnnouncement = text.substring(0, index);
text = text.substring(index); text = text.substring(index);
elements.add(new Element(extensionAnnouncement, "black")); elements.add(divWithClass(extensionAnnouncement, "black"));
} }
elements.add(new Element(text + "\n", classname.toLowerCase())); elements.add(divWithClass(text, classname.toLowerCase()));
synchronized (appendOnLoad) { synchronized (appendOnLoad) {
if (initialized) { if (initialized) {
@ -114,4 +98,42 @@ public class ExtensionLoggerController implements Initializable {
return text.trim(); return text.trim();
} }
private String divWithClass(String content, String klass) {
return escapeMessage("<div class=\"" + klass + "\">" + content + "</div>");
}
private String spanWithClass(String content, String klass) {
return escapeMessage("<span class=\"" + klass + "\">" + content + "</span>");
}
private String escapeMessage(String text) {
return text
.replace("\n\r", "<br />")
.replace("\n", "<br />")
.replace("\r", "<br />")
.replace("'", "\\'");
}
private static Object executejQuery(final WebEngine engine, String script) {
return engine.executeScript(
"(function(window, document, version, callback) { "
+ "var j, d;"
+ "var loaded = false;"
+ "if (!(j = window.jQuery) || version > j.fn.jquery || callback(j, loaded)) {"
+ " var script = document.createElement(\"script\");"
+ " script.type = \"text/javascript\";"
+ " script.src = \"http://code.jquery.com/jquery-1.7.2.min.js\";"
+ " script.onload = script.onreadystatechange = function() {"
+ " if (!loaded && (!(d = this.readyState) || d == \"loaded\" || d == \"complete\")) {"
+ " callback((j = window.jQuery).noConflict(1), loaded = true);"
+ " j(script).remove();"
+ " }"
+ " };"
+ " document.documentElement.childNodes[0].appendChild(script) "
+ "} "
+ "})(window, document, \"1.7.2\", function($, jquery_loaded) {" + script + "});"
);
}
} }

View File

@ -49,7 +49,7 @@ public class UiLoggerController implements Initializable {
private boolean alwaysOnTop = false; private boolean alwaysOnTop = false;
private volatile boolean initialized = false; private volatile boolean initialized = false;
private final List<Element> appendLater = new ArrayList<>(); private final List<String> appendLater = new LinkedList<>();
@Override @Override
public void initialize(URL arg0, ResourceBundle arg1) { public void initialize(URL arg0, ResourceBundle arg1) {
@ -58,19 +58,18 @@ public class UiLoggerController implements Initializable {
borderPane.setCenter(webView); borderPane.setCenter(webView);
webView.getEngine().getLoadWorker().stateProperty().addListener((observableValue, oldState, newState) -> { webView.getEngine().getLoadWorker().stateProperty().addListener((observableValue, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) if (newState == Worker.State.SUCCEEDED) {
synchronized (appendLater) {
initialized = true; initialized = true;
if (!appendLater.isEmpty()) { webView.prefHeightProperty().bind(stage.heightProperty());
webView.prefWidthProperty().bind(stage.widthProperty());
appendLog(appendLater); appendLog(appendLater);
appendLater.clear();
}
} }
}); });
webView.getEngine().load(getClass().getResource("/gearth/ui/logger/uilogger/logger.html").toString()); webView.getEngine().load(getClass().getResource("/gearth/ui/logger/uilogger/logger.html").toString());
} }
private static String cleanTextContent(String text) { private static String cleanTextContent(String text) {
// // strips off all non-ASCII characters // // strips off all non-ASCII characters
// text = text.replaceAll("[^\\x00-\\x7F]", ""); // text = text.replaceAll("[^\\x00-\\x7F]", "");
@ -84,7 +83,7 @@ public class UiLoggerController implements Initializable {
return text.trim(); return text.trim();
} }
public void appendMessage(HPacket packet, int types) { public synchronized void appendMessage(HPacket packet, int types) {
boolean isBlocked = (types & PacketLogger.MESSAGE_TYPE.BLOCKED.getValue()) != 0; boolean isBlocked = (types & PacketLogger.MESSAGE_TYPE.BLOCKED.getValue()) != 0;
boolean isReplaced = (types & PacketLogger.MESSAGE_TYPE.REPLACED.getValue()) != 0; boolean isReplaced = (types & PacketLogger.MESSAGE_TYPE.REPLACED.getValue()) != 0;
boolean isIncoming = (types & PacketLogger.MESSAGE_TYPE.INCOMING.getValue()) != 0; boolean isIncoming = (types & PacketLogger.MESSAGE_TYPE.INCOMING.getValue()) != 0;
@ -92,7 +91,7 @@ public class UiLoggerController implements Initializable {
if (isIncoming && !viewIncoming) return; if (isIncoming && !viewIncoming) return;
if (!isIncoming && !viewOutgoing) return; if (!isIncoming && !viewOutgoing) return;
ArrayList<Element> elements = new ArrayList<>(); StringBuilder packetHtml = new StringBuilder("<div>");
String expr = packet.toExpression(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER); String expr = packet.toExpression(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER);
@ -104,84 +103,57 @@ public class UiLoggerController implements Initializable {
packet.headerId() packet.headerId()
); );
if ( message != null && !(viewMessageName && !viewMessageHash && message.getName() == null)) { if (message != null && !(viewMessageName && !viewMessageHash && message.getName() == null)) {
if (viewMessageName && message.getName() != null) { if (viewMessageName && message.getName() != null) {
elements.add(new Element("["+message.getName()+"]", "messageinfo")); packetHtml.append(divWithClass("[" + message.getName() + "]", "messageinfo"));
} }
if (viewMessageHash) { if (viewMessageHash) {
elements.add(new Element("["+message.getHash()+"]", "messageinfo")); packetHtml.append(divWithClass("[" + message.getHash() + "]", "messageinfo"));
} }
elements.add(new Element("\n", ""));
} }
} }
if (isBlocked) elements.add(new Element("[Blocked]\n", "blocked")); if (isBlocked) packetHtml.append(divWithClass("[Blocked]", "blocked"));
else if (isReplaced) elements.add(new Element("[Replaced]\n", "replaced")); else if (isReplaced) packetHtml.append(divWithClass("[Replaced]", "replaced"));
if (isIncoming) {
// handle skipped eventually
elements.add(new Element("Incoming[", "incoming"));
elements.add(new Element(String.valueOf(packet.headerId()), ""));
elements.add(new Element("]", "incoming"));
elements.add(new Element(" <- ", "")); packetHtml
if (skiphugepackets && packet.length() > 8000) { .append("<div>")
elements.add(new Element("<packet skipped>", "skipped")); .append(isIncoming ? spanWithClass("Incoming[", "incoming") :
} spanWithClass("Outgoing[", "outgoing"))
else { .append(packet.headerId())
elements.add(new Element(packet.toString(), "incoming")); .append(spanWithClass("]", isIncoming ? "incoming" : "outgoing"))
} .append(isIncoming ? " <- " : " -> ")
} else { .append(skiphugepackets && packet.length() > 8000 ?
elements.add(new Element("Outgoing[", "outgoing")); divWithClass("<packet skipped>", "skipped") :
elements.add(new Element(String.valueOf(packet.headerId()), "")); divWithClass(packet.toString(), isIncoming ? "incoming" : "outgoing"));
elements.add(new Element("]", "outgoing"));
elements.add(new Element(" -> ", ""));
if (skiphugepackets && packet.length() > 8000) {
elements.add(new Element("<packet skipped>", "skipped"));
}
else {
elements.add(new Element(packet.toString(), "outgoing"));
}
}
String cleaned = cleanTextContent(expr); String cleaned = cleanTextContent(expr);
if (cleaned.equals(expr)) { if (cleaned.equals(expr)) {
if (!expr.equals("") && displayStructure && packet.length() <= 2000) if (!expr.equals("") && displayStructure && packet.length() <= 2000)
elements.add(new Element("\n" + cleanTextContent(expr), "structure")); packetHtml.append(divWithClass(cleanTextContent(expr), "structure"));
} }
elements.add(new Element("\n--------------------\n", "")); packetHtml.append(divWithClass("--------------------", ""));
synchronized (appendLater) { synchronized (appendLater) {
if (initialized) { if (initialized) {
appendLog(elements); appendLog(Collections.singletonList(packetHtml.toString()));
} else {
appendLater.add(packetHtml.toString());
} }
else {
appendLater.addAll(elements);
} }
} }
} private synchronized void appendLog(List<String> html) {
private synchronized void appendLog(List<Element> elements) {
Platform.runLater(() -> { Platform.runLater(() -> {
String script = "document.getElementById('output').innerHTML += '" + String.join("", html) + "';";
for (Element element : elements) { webView.getEngine().executeScript(script);
String script = "$('#output').append('<span class=\"" + element.className + "\">"
+ escapeMessage(element.text) + "</span>');";
try {
executejQuery(webView.getEngine(), script);
} catch (Exception e) {
System.out.println("Malformed JS message " + script);
}
}
if (autoScroll) { if (autoScroll) {
webView.getEngine().executeScript("window.scrollTo(0, document.body.scrollHeight);"); executejQuery(webView.getEngine(), "$('html, body').animate({scrollTop:$(document).height()}, 'slow');");
} }
}); });
} }
@ -260,6 +232,14 @@ public class UiLoggerController implements Initializable {
} }
public void clearText(ActionEvent actionEvent) { public void clearText(ActionEvent actionEvent) {
webView.getEngine().executeScript("$('#output').html = \\'\\'"); executejQuery(webView.getEngine(), "$('#output').empty();");
}
private String divWithClass(String content, String klass) {
return escapeMessage("<div class=\"" + klass + "\">" + content + "</div>");
}
private String spanWithClass(String content, String klass) {
return escapeMessage("<span class=\"" + klass + "\">" + content + "</span>");
} }
} }

View File

@ -38,7 +38,7 @@
.menu-bar .text, .menu .text { .menu-bar .text, .menu .text {
color: #000000 !important; color: #000000 !important;
padding: -2px 0 -2px 0 !important; /*padding: -2px 0 -2px 0 !important;*/
} }
.scroll-bar:vertical { .scroll-bar:vertical {