From 2486d5a9023c44192e1f7ac426b77ff15dad1cb8 Mon Sep 17 00:00:00 2001 From: sirjonasxx <36828922+sirjonasxx@users.noreply.github.com> Date: Sat, 17 Nov 2018 03:12:15 +0100 Subject: [PATCH] HarbleAPI and UIlogger bugfix in structures --- .../java/gearth/extensions/Extension.java | 2 +- .../gearth/extensions/extra/Inspector.java | 7 - .../extensions/extra/hashing/HashSupport.java | 127 +++++++++++++++++ G-Earth/src/main/java/gearth/misc/Cacher.java | 4 +- .../gearth/misc/harble_api/HarbleAPI.java | 132 ++++++++++++++++++ .../misc/harble_api/HarbleAPIFetcher.java | 47 ++++++- .../main/java/gearth/protocol/HPacket.java | 31 ++++ .../java/gearth/ui/UiLoggerController.java | 17 ++- 8 files changed, 354 insertions(+), 13 deletions(-) delete mode 100644 G-Earth/src/main/java/gearth/extensions/extra/Inspector.java create mode 100644 G-Earth/src/main/java/gearth/extensions/extra/hashing/HashSupport.java diff --git a/G-Earth/src/main/java/gearth/extensions/Extension.java b/G-Earth/src/main/java/gearth/extensions/Extension.java index ba47b17..5642b1e 100644 --- a/G-Earth/src/main/java/gearth/extensions/Extension.java +++ b/G-Earth/src/main/java/gearth/extensions/Extension.java @@ -368,7 +368,7 @@ public abstract class Extension { } - protected interface OnConnectionListener { + public interface OnConnectionListener { void act(String host, int port, String hotelversion); } private List onConnectionListeners = new ArrayList<>(); diff --git a/G-Earth/src/main/java/gearth/extensions/extra/Inspector.java b/G-Earth/src/main/java/gearth/extensions/extra/Inspector.java deleted file mode 100644 index 89acbf5..0000000 --- a/G-Earth/src/main/java/gearth/extensions/extra/Inspector.java +++ /dev/null @@ -1,7 +0,0 @@ -package gearth.extensions.extra; - -/** - * Created by Jonas on 22/09/18. - */ -public class Inspector { -} diff --git a/G-Earth/src/main/java/gearth/extensions/extra/hashing/HashSupport.java b/G-Earth/src/main/java/gearth/extensions/extra/hashing/HashSupport.java new file mode 100644 index 0000000..905dd30 --- /dev/null +++ b/G-Earth/src/main/java/gearth/extensions/extra/hashing/HashSupport.java @@ -0,0 +1,127 @@ +package gearth.extensions.extra.hashing; + +import gearth.extensions.Extension; +import gearth.misc.harble_api.HarbleAPI; +import gearth.protocol.HMessage; +import gearth.protocol.HPacket; + +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Created by Jonas on 10/11/2018. + */ +public class HashSupport { + + private final Object lock = new Object(); + + private HarbleAPI harbleAPI = new HarbleAPI(""); //empty + private Map> incomingMessageListeners = new HashMap<>(); + private Map> outgoingMessageListeners = new HashMap<>(); + private PacketSender toClientSender; + private PacketSender toServerSender; + + + public interface OnConnectRegistration { + void onConnect(Extension.OnConnectionListener listener); + } + public interface InterceptRegistration { + void intercept(HMessage.Side side, Extension.MessageListener messageListener); + } + public interface PacketSender { + boolean send(HPacket packet); + } + + public HashSupport(OnConnectRegistration onConnectRegistration, InterceptRegistration interceptRegistration, PacketSender sendToClient, PacketSender sendToServer) { + toClientSender = sendToClient; + toServerSender = sendToServer; + onConnectRegistration.onConnect((host, port, hotelversion) -> { +// synchronized (lock) { + harbleAPI = new HarbleAPI(hotelversion); +// } + }); + + interceptRegistration.intercept(HMessage.Side.TOSERVER, message -> { +// synchronized (lock) { + HarbleAPI.HarbleMessage haMessage = harbleAPI.getHarbleMessageFromHeaderId(HMessage.Side.TOSERVER, message.getPacket().headerId()); + if (haMessage != null) { + String hash = haMessage.getHash(); + List listeners = outgoingMessageListeners.get(hash); + if (listeners != null) { + for (Extension.MessageListener listener : listeners) { + listener.act(message); + message.getPacket().resetReadIndex(); + } + } + } +// } + }); + interceptRegistration.intercept(HMessage.Side.TOCLIENT, message -> { +// synchronized (lock) { + HarbleAPI.HarbleMessage haMessage = harbleAPI.getHarbleMessageFromHeaderId(HMessage.Side.TOCLIENT, message.getPacket().headerId()); + if (haMessage != null) { + String hash = haMessage.getHash(); + List listeners = incomingMessageListeners.get(hash); + if (listeners != null) { + for (Extension.MessageListener listener : listeners) { + listener.act(message); + message.getPacket().resetReadIndex(); + } + } + } +// } + }); + } + + public void intercept(HMessage.Side side, String hash, Extension.MessageListener messageListener) { + Map> messageListeners = + (side == HMessage.Side.TOSERVER + ? outgoingMessageListeners + : incomingMessageListeners); + + messageListeners.computeIfAbsent(hash, k -> new ArrayList<>()); + messageListeners.get(hash).add(messageListener); + } + + /** + * + * @return if no errors occurred (invalid hash/invalid parameters/connection error) + */ + public boolean sendToClient(String hash, Object... objects) { + List possibilities = harbleAPI.getHarbleMessagesFromHash(HMessage.Side.TOCLIENT, hash); + if (possibilities.size() == 0) return false; + int headerId = possibilities.get(0).getHeaderId(); + + try { + HPacket packetToSend = new HPacket(headerId, objects); + + return toClientSender.send(packetToSend); + } + catch (InvalidParameterException e) { + return false; + } + } + + /** + * + * @return if no errors occurred (invalid hash/invalid parameters/connection error) + */ + public boolean sendToServer(String hash, Object... objects) { + List possibilities = harbleAPI.getHarbleMessagesFromHash(HMessage.Side.TOSERVER, hash); + if (possibilities.size() == 0) return false; + int headerId = possibilities.get(0).getHeaderId(); + + try { + HPacket packetToSend = new HPacket(headerId, objects); + + return toServerSender.send(packetToSend); + } + catch (InvalidParameterException e) { + return false; + } + } + +} diff --git a/G-Earth/src/main/java/gearth/misc/Cacher.java b/G-Earth/src/main/java/gearth/misc/Cacher.java index 14d2f37..a1903f4 100644 --- a/G-Earth/src/main/java/gearth/misc/Cacher.java +++ b/G-Earth/src/main/java/gearth/misc/Cacher.java @@ -30,7 +30,7 @@ public class Cacher { - private static boolean cacheFileExists(String cache_filename) { + public static boolean cacheFileExists(String cache_filename) { File f = new File(getCacheDir(), cache_filename); return (f.exists() && !f.isDirectory()); } @@ -83,7 +83,7 @@ public class Cacher { } - private static boolean cacheFileExists() { + public static boolean cacheFileExists() { return cacheFileExists(DEFAULT_CACHE_FILENAME); } diff --git a/G-Earth/src/main/java/gearth/misc/harble_api/HarbleAPI.java b/G-Earth/src/main/java/gearth/misc/harble_api/HarbleAPI.java index e760f74..4580721 100644 --- a/G-Earth/src/main/java/gearth/misc/harble_api/HarbleAPI.java +++ b/G-Earth/src/main/java/gearth/misc/harble_api/HarbleAPI.java @@ -1,10 +1,142 @@ package gearth.misc.harble_api; +import gearth.misc.Cacher; +import gearth.protocol.HMessage; +import org.json.JSONObject; +import sun.misc.Cache; + +import javax.print.attribute.standard.Destination; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * Created by Jonas on 10/11/2018. */ public class HarbleAPI { + public class HarbleMessage { + private HMessage.Side destination; + private int headerId; + private String hash; + private String name; + + //name can be NULL + public HarbleMessage(HMessage.Side destination, int headerId, String hash, String name) { + this.destination = destination; + this.headerId = headerId; + this.hash = hash; + this.name = name; + } + public String getName() { + return name; + } + public int getHeaderId() { + return headerId; + } + public HMessage.Side getDestination() { + return destination; + } + public String getHash() { + return hash; + } + } + + private Map headerIdToMessage_incoming = new HashMap<>(); + private Map headerIdToMessage_outgoing = new HashMap<>(); + + private Map> hashToMessage_incoming = new HashMap<>(); + private Map> hashToMessage_outgoing = new HashMap<>(); + + private Map nameToMessage_incoming = new HashMap<>(); + private Map nameToMessage_outgoing = new HashMap<>(); + + /** + * cache file must be generated first within G-Earth, inb4 20 extensions requesting it at the same time + * @param hotelversion + */ + public HarbleAPI (String hotelversion) { + if (Cacher.cacheFileExists(HarbleAPIFetcher.CACHE_PREFIX + hotelversion)) { + JSONObject object = Cacher.getCacheContents(HarbleAPIFetcher.CACHE_PREFIX + hotelversion); + parse(object); + } + } + + private void addMessage(HarbleMessage message) { + Map headerIdToMessage = + message.getDestination() == HMessage.Side.TOCLIENT + ? headerIdToMessage_incoming : + headerIdToMessage_outgoing; + + Map> hashToMessage = + message.getDestination() == HMessage.Side.TOCLIENT + ? hashToMessage_incoming + : hashToMessage_outgoing; + + Map nameToMessag = + message.getDestination() == HMessage.Side.TOCLIENT + ? nameToMessage_incoming + : nameToMessage_outgoing; + + headerIdToMessage.put(message.getHeaderId(), message); + hashToMessage.computeIfAbsent(message.getHash(), k -> new ArrayList<>()); + hashToMessage.get(message.getHash()).add(message); + if (message.getName() != null && !message.getName().equals("null")) { + nameToMessag.put(message.getName(), message); + } + } + private void parse(JSONObject object) { + JSONObject incoming = object.getJSONObject("IncomingMessages"); + JSONObject outgoing = object.getJSONObject("OutgoingMessages"); + + if (incoming != null && outgoing != null) { + for (String key : incoming.keySet()) { + JSONObject inMsg = incoming.getJSONObject(key); + String name = inMsg.getString("Name"); + String hash = inMsg.getString("Hash"); + Integer headerId = Integer.parseInt(key); + HarbleMessage message = new HarbleMessage(HMessage.Side.TOCLIENT, headerId, hash, name); + + addMessage(message); + } + for (String key : outgoing.keySet()) { + JSONObject outMsg = incoming.getJSONObject(key); + String name = outMsg.getString("Name"); + String hash = outMsg.getString("Hash"); + Integer headerId = Integer.parseInt(key); + HarbleMessage message = new HarbleMessage(HMessage.Side.TOSERVER, headerId, hash, name); + + addMessage(message); + } + } + } + + public HarbleMessage getHarbleMessageFromHeaderId(HMessage.Side side, int headerId) { + Map headerIdToMessage = + (side == HMessage.Side.TOSERVER + ? headerIdToMessage_outgoing + : headerIdToMessage_incoming); + + return headerIdToMessage.get(headerId); + } + public List getHarbleMessagesFromHash(HMessage.Side side, String hash) { + Map> hashToMessage = + (side == HMessage.Side.TOSERVER + ? hashToMessage_outgoing + : hashToMessage_incoming); + + List result = hashToMessage.get(hash); + return result == null ? new ArrayList<>() : result; + } + public HarbleMessage getHarbleMessageFromName(HMessage.Side side, String name) { + Map nameToMessage = + (side == HMessage.Side.TOSERVER + ? nameToMessage_outgoing + : nameToMessage_incoming); + + return nameToMessage.get(name); + } } diff --git a/G-Earth/src/main/java/gearth/misc/harble_api/HarbleAPIFetcher.java b/G-Earth/src/main/java/gearth/misc/harble_api/HarbleAPIFetcher.java index 4af58be..c51a48f 100644 --- a/G-Earth/src/main/java/gearth/misc/harble_api/HarbleAPIFetcher.java +++ b/G-Earth/src/main/java/gearth/misc/harble_api/HarbleAPIFetcher.java @@ -1,8 +1,51 @@ package gearth.misc.harble_api; +import gearth.misc.Cacher; +import org.json.JSONObject; +import org.jsoup.Connection; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; + +import java.io.IOException; + /** - * Created by Jeunez on 10/11/2018. + * Created by Jonas on 10/11/2018. */ public class HarbleAPIFetcher { -} + public static final String CACHE_PREFIX = "HARBLE_API-"; + public static final String HARBLE_API_URL = "https://api.harble.net/revisions/$hotelversion$.json"; + + public static HarbleAPI fetch(String hotelversion) { + String cacheName = CACHE_PREFIX + hotelversion; + + if (Cacher.cacheFileExists(cacheName)) { + return new HarbleAPI(hotelversion); + } + else { + Connection connection = Jsoup.connect(HARBLE_API_URL.replace("$hotelversion$", hotelversion)).ignoreContentType(true); + try { + Document doc = connection.get(); + Connection.Response response = connection.response(); + if (response.statusCode() == 200) { + String s = doc.body().toString(); + s = s.substring(6, s.length() - 7); + JSONObject object = new JSONObject(s); + Cacher.updateCache(object, cacheName); + + return new HarbleAPI(hotelversion); + } + else { + return null; + } + } catch (IOException e) { + return null; + } + + } + } + + public static void main(String[] args) { + HarbleAPI api = fetch("PRODUCTION-201810171204-70166177"); + } +} \ No newline at end of file diff --git a/G-Earth/src/main/java/gearth/protocol/HPacket.java b/G-Earth/src/main/java/gearth/protocol/HPacket.java index f7a8ed7..b5de9c1 100644 --- a/G-Earth/src/main/java/gearth/protocol/HPacket.java +++ b/G-Earth/src/main/java/gearth/protocol/HPacket.java @@ -1,10 +1,12 @@ package gearth.protocol; +import com.sun.org.apache.xpath.internal.operations.Bool; import gearth.misc.StringifyAble; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Arrays; @@ -35,6 +37,35 @@ public class HPacket implements StringifyAble { isEdited = false; } + /** + * + * @param header headerId + * @param objects can be a byte, integer, boolean, string, no short values allowed (use 2 bytes instead) + */ + public HPacket(int header, Object... objects) throws InvalidParameterException { + this(header); + for (int i = 0; i < objects.length; i++) { + Object o = objects[i]; + if (o instanceof Byte) { + appendByte((Byte)o); + } + else if (o instanceof Integer) { + appendInt((Integer)o); + } + else if (o instanceof String) { + appendString((String)o); + } + else if (o instanceof Boolean) { + appendBoolean((Boolean) o); + } + else { + throw new InvalidParameterException(); + } + } + + isEdited = false; + } + public String toString() { String teststring = ""; for (byte x : packetInBytes) { diff --git a/G-Earth/src/main/java/gearth/ui/UiLoggerController.java b/G-Earth/src/main/java/gearth/ui/UiLoggerController.java index 8ae1a11..db9411e 100644 --- a/G-Earth/src/main/java/gearth/ui/UiLoggerController.java +++ b/G-Earth/src/main/java/gearth/ui/UiLoggerController.java @@ -60,6 +60,20 @@ public class UiLoggerController implements Initializable { } + private static String cleanTextContent(String text) + { +// // strips off all non-ASCII characters +// text = text.replaceAll("[^\\x00-\\x7F]", ""); +// +// // erases all the ASCII control characters + text = text.replaceAll("[\\p{Cntrl}&&[^\n\t]]", ""); + + // removes non-printable characters from Unicode +// text = text.replaceAll("\\p{C}", ""); + + return text.trim(); + } + public void appendMessage(HPacket packet, int types) { boolean isBlocked = (types & PacketLogger.MESSAGE_TYPE.BLOCKED.getValue()) != 0; boolean isReplaced = (types & PacketLogger.MESSAGE_TYPE.REPLACED.getValue()) != 0; @@ -103,7 +117,7 @@ public class UiLoggerController implements Initializable { } } if (!expr.equals("") && displayStructure && (!skiphugepackets || packet.length() <= 8000)) - elements.add(new Element("\n" + expr, "structure")); + elements.add(new Element("\n" + cleanTextContent(expr), "structure")); elements.add(new Element("\n--------------------\n", "")); @@ -125,6 +139,7 @@ public class UiLoggerController implements Initializable { for (Element element : elements) { sb.append(element.text); + styleSpansBuilder.add(Collections.singleton(element.className), element.text.length()); }