diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java index d97446052..7c7be5b90 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java @@ -47,6 +47,7 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.UUID; import java.util.logging.Level; @@ -171,6 +172,18 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { return new GeyserBungeeDumpInfo(getProxy()); } + @Override + public Path getLogsPath() { + boolean isBungeeCord = getProxy().getName().equals("BungeeCord"); + Path getFork; + if (isBungeeCord) { + getFork = Paths.get("proxy.log.0"); + } else { + getFork = Paths.get("logs/latest.log"); + } + return getFork; + } + @Nullable @Override public SocketAddress getSocketAddress() { diff --git a/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java b/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java index ef0e0068c..51b64dd7f 100644 --- a/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java +++ b/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java @@ -25,17 +25,18 @@ package org.geysermc.connector.bootstrap; -import org.geysermc.connector.dump.BootstrapDumpInfo; -import org.geysermc.connector.ping.IGeyserPingPassthrough; -import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.GeyserLogger; import org.geysermc.connector.command.CommandManager; +import org.geysermc.connector.configuration.GeyserConfiguration; +import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.network.translators.world.GeyserWorldManager; import org.geysermc.connector.network.translators.world.WorldManager; +import org.geysermc.connector.ping.IGeyserPingPassthrough; import javax.annotation.Nullable; import java.net.SocketAddress; import java.nio.file.Path; +import java.nio.file.Paths; public interface GeyserBootstrap { @@ -120,4 +121,8 @@ public interface GeyserBootstrap { default SocketAddress getSocketAddress() { return null; } + + default Path getLogsPath() { + return Paths.get("logs/latest.log"); + } } diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/DumpCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/DumpCommand.java index 05f32ae2b..07a690298 100644 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/DumpCommand.java +++ b/connector/src/main/java/org/geysermc/connector/command/defaults/DumpCommand.java @@ -65,6 +65,7 @@ public class DumpCommand extends GeyserCommand { boolean showSensitive = false; boolean offlineDump = false; + boolean addLog = false; if (args.length >= 1) { for (String arg : args) { switch (arg) { @@ -74,7 +75,9 @@ public class DumpCommand extends GeyserCommand { case "offline": offlineDump = true; break; - + case "logs": + addLog = true; + break; } } } @@ -85,9 +88,9 @@ public class DumpCommand extends GeyserCommand { String dumpData = ""; try { if (offlineDump) { - dumpData = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(new DumpInfo()); + dumpData = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(new DumpInfo(addLog)); } else { - dumpData = MAPPER.writeValueAsString(new DumpInfo()); + dumpData = MAPPER.writeValueAsString(new DumpInfo(addLog)); } } catch (IOException e) { sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.collect_error", sender.getLocale())); @@ -141,6 +144,6 @@ public class DumpCommand extends GeyserCommand { @Override public List getSubCommands() { - return Arrays.asList("offline", "full"); + return Arrays.asList("offline", "full", "logs"); } } diff --git a/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java b/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java index fee4ac7a4..123dcc3fa 100644 --- a/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java +++ b/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java @@ -41,6 +41,7 @@ import org.geysermc.connector.network.BedrockProtocol; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.utils.DockerCheck; import org.geysermc.connector.utils.FileUtils; +import org.geysermc.connector.utils.WebUtils; import org.geysermc.floodgate.util.DeviceOs; import org.geysermc.floodgate.util.FloodgateInfoHolder; @@ -64,9 +65,10 @@ public class DumpInfo { private final Object2IntMap userPlatforms; private final HashInfo hashInfo; private final RamInfo ramInfo; + private LogsInfo logsInfo; private final BootstrapDumpInfo bootstrapInfo; - public DumpInfo() { + public DumpInfo(boolean addLog) { this.versionInfo = new VersionInfo(); try { @@ -99,6 +101,10 @@ public class DumpInfo { this.ramInfo = new DumpInfo.RamInfo(); + if (addLog) { + this.logsInfo = new LogsInfo(); + } + this.userPlatforms = new Object2IntOpenHashMap<>(); for (GeyserSession session : GeyserConnector.getInstance().getPlayers()) { DeviceOs device = session.getClientData().getDeviceOs(); @@ -188,6 +194,17 @@ public class DumpInfo { } } + @Getter + public static class LogsInfo { + private String link; + + public LogsInfo() { + try { + this.link = WebUtils.postLogs(GeyserConnector.getInstance().getBootstrap().getLogsPath()); + } catch (IOException ignored) {} + } + } + @AllArgsConstructor @Getter public static class HashInfo { diff --git a/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java b/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java index cf9f0e1fb..e46f9126f 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java @@ -31,10 +31,14 @@ import org.geysermc.connector.GeyserConnector; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.util.stream.Collectors; public class WebUtils { @@ -132,4 +136,37 @@ public class WebUtils { return content.toString(); } + + /** + * Get the server log file and uploads it to mclo.gs + * + * @param log File to fetch + */ + public static String postLogs(Path log) throws IOException { + // Connect to api + URL url = new URL("https://api.mclo.gs/1/log"); + URLConnection con = url.openConnection(); + HttpURLConnection http = (HttpURLConnection) con; + http.setRequestMethod("POST"); + http.setDoOutput(true); + // Convert log to application/x-www-form-urlencoded + String content = "content=" + URLEncoder.encode(new BufferedReader(new InputStreamReader(Files.newInputStream(log.toRealPath()))).lines().collect(Collectors.joining("\n")), StandardCharsets.UTF_8.toString()); + byte[] out = content.getBytes(StandardCharsets.UTF_8); + int length = out.length; + + // Send log to api + http.setFixedLengthStreamingMode(length); + http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); + http.setRequestProperty("User-Agent", "Geyser-" + GeyserConnector.getInstance().getPlatformType().toString() + "/" + GeyserConnector.VERSION); + http.connect(); + try (OutputStream os = http.getOutputStream()) { + os.write(out); + } + String is = new BufferedReader(new InputStreamReader(http.getInputStream())) + .lines() + .collect(Collectors.joining()); + JsonNode jn = GeyserConnector.JSON_MAPPER.readTree(is); + // Handle response + return jn.get("url").textValue(); + } }