001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.core.command; 020 021import com.google.gson.JsonObject; 022import com.google.gson.JsonParser; 023import com.google.inject.Inject; 024import com.intellectualsites.paster.IncendoPaster; 025import com.plotsquared.core.PlotSquared; 026import com.plotsquared.core.configuration.Settings; 027import com.plotsquared.core.configuration.Storage; 028import com.plotsquared.core.configuration.caption.TranslatableCaption; 029import com.plotsquared.core.inject.annotations.ConfigFile; 030import com.plotsquared.core.inject.annotations.WorldFile; 031import com.plotsquared.core.player.PlotPlayer; 032import com.plotsquared.core.util.PremiumVerification; 033import com.plotsquared.core.util.task.TaskManager; 034import net.kyori.adventure.text.Component; 035import net.kyori.adventure.text.minimessage.tag.Tag; 036import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 037import org.checkerframework.checker.nullness.qual.NonNull; 038 039import java.io.File; 040import java.io.IOException; 041import java.lang.management.ManagementFactory; 042import java.lang.management.RuntimeMXBean; 043import java.nio.file.Files; 044import java.util.concurrent.TimeUnit; 045 046@CommandDeclaration(command = "debugpaste", 047 aliases = "dp", 048 usage = "/plot debugpaste", 049 permission = "plots.debugpaste", 050 category = CommandCategory.DEBUG, 051 confirmation = true, 052 requiredType = RequiredType.NONE) 053public class DebugPaste extends SubCommand { 054 055 private final File configFile; 056 private final File worldfile; 057 058 @Inject 059 public DebugPaste( 060 @ConfigFile final @NonNull File configFile, 061 @WorldFile final @NonNull File worldFile 062 ) { 063 this.configFile = configFile; 064 this.worldfile = worldFile; 065 } 066 067 @Override 068 public boolean onCommand(final PlotPlayer<?> player, String[] args) { 069 TaskManager.runTaskAsync(() -> { 070 try { 071 StringBuilder b = new StringBuilder(); 072 b.append( 073 """ 074 # Welcome to this paste 075 # It is meant to provide us at IntellectualSites with better information about your problem 076 """ 077 ); 078 b.append("# PlotSquared Information\n"); 079 b.append("PlotSquared Version: ").append(PlotSquared.get().getVersion()) 080 .append("\n"); 081 b.append("Database Type: ").append(Storage.MySQL.USE ? "MySQL" : "SQLite").append("\n"); 082 b.append("Resource ID: ").append(PremiumVerification.getResourceID()).append("\n"); 083 b.append("Download ID: ").append(PremiumVerification.getDownloadID()).append("\n"); 084 b.append("This PlotSquared version is licensed to the spigot user ") 085 .append(PremiumVerification.getUserID()).append("\n\n"); 086 b.append("# WorldEdit implementation:\n"); 087 b.append(PlotSquared.platform().worldEditImplementations()).append("\n\n"); 088 b.append("# Server Information\n"); 089 b.append("Server Version: ").append(PlotSquared.platform().serverImplementation()) 090 .append("\n"); 091 b.append("online_mode: ").append(!Settings.UUID.OFFLINE).append(';') 092 .append(!Settings.UUID.OFFLINE).append('\n'); 093 b.append(PlotSquared.platform().pluginsFormatted()); 094 b.append("\n\n# YAY! Now, let's see what we can find in your JVM\n"); 095 Runtime runtime = Runtime.getRuntime(); 096 RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean(); 097 b.append("Uptime: ") 098 .append(TimeUnit.MINUTES.convert(rb.getUptime(), TimeUnit.MILLISECONDS)) 099 .append(" minutes") 100 .append('\n'); 101 b.append("JVM Flags: ").append(rb.getInputArguments()).append('\n'); 102 b.append("Free Memory: ").append(runtime.freeMemory() / 1024 / 1024).append(" MB") 103 .append('\n'); 104 b.append("Max Memory: ").append(runtime.maxMemory() / 1024 / 1024).append(" MB") 105 .append('\n'); 106 b.append("Total Memory: ").append(runtime.totalMemory() / 1024 / 1024).append(" MB") 107 .append('\n'); 108 b.append("Available Processors: ").append(runtime.availableProcessors()).append('\n'); 109 b.append("Java Name: ").append(rb.getVmName()).append('\n'); 110 b.append("Java Version: '").append(System.getProperty("java.version")) 111 .append("'\n"); 112 b.append("Java Vendor: '").append(System.getProperty("java.vendor")).append("'\n"); 113 b.append("Operating System: '").append(System.getProperty("os.name")).append("'\n"); 114 b.append("OS Version: ").append(System.getProperty("os.version")).append('\n'); 115 b.append("OS Arch: ").append(System.getProperty("os.arch")).append('\n'); 116 b.append("# Okay :D Great. You are now ready to create your bug report!"); 117 b.append( 118 "\n# You can do so at https://github.com/IntellectualSites/PlotSquared/issues"); 119 b.append("\n# or via our Discord at https://discord.gg/intellectualsites"); 120 121 final IncendoPaster incendoPaster = new IncendoPaster("plotsquared"); 122 incendoPaster.addFile(new IncendoPaster.PasteFile("information", b.toString())); 123 124 try { 125 final File logFile = 126 new File("logs/latest.log"); 127 if (Files.size(logFile.toPath()) > 14_000_000) { 128 throw new IOException( 129 "The latest.log is larger than 14MB. Please reboot your server and submit a new paste."); 130 } 131 incendoPaster 132 .addFile(logFile); 133 } catch (IOException ignored) { 134 player.sendMessage( 135 TranslatableCaption.of("debugpaste.latest_log"), 136 TagResolver.builder() 137 .tag("file", Tag.inserting(Component.text("latest.log"))) 138 .tag("size", Tag.inserting(Component.text("14MB"))) 139 .build() 140 ); 141 } 142 143 try { 144 incendoPaster.addFile(this.configFile); 145 } catch (final IllegalArgumentException ignored) { 146 player.sendMessage( 147 TranslatableCaption.of("debugpaste.empty_file"), 148 TagResolver.resolver("file", Tag.inserting(Component.text("settings.yml"))) 149 ); 150 } 151 try { 152 incendoPaster.addFile(this.worldfile); 153 } catch (final IllegalArgumentException ignored) { 154 player.sendMessage( 155 TranslatableCaption.of("debugpaste.empty_file"), 156 TagResolver.resolver("file", Tag.inserting(Component.text("worlds.yml"))) 157 ); 158 } 159 160 try { 161 final File MultiverseWorlds = new File( 162 PlotSquared.platform().getDirectory(), 163 "../Multiverse-Core/worlds.yml" 164 ); 165 incendoPaster.addFile(MultiverseWorlds, "Multiverse-Core/worlds.yml"); 166 } catch (final IOException ignored) { 167 player.sendMessage( 168 TranslatableCaption.of("debugpaste.skip_multiverse"), 169 TagResolver.resolver("file", Tag.inserting(Component.text("worlds.yml"))) 170 ); 171 } 172 173 try { 174 final String rawResponse = incendoPaster.upload(); 175 final JsonObject jsonObject = 176 new JsonParser().parse(rawResponse).getAsJsonObject(); 177 178 if (jsonObject.has("created")) { 179 final String pasteId = jsonObject.get("paste_id").getAsString(); 180 final String link = 181 String.format("https://athion.net/ISPaster/paste/view/%s", pasteId); 182 player.sendMessage( 183 TranslatableCaption.of("debugpaste.debug_report_created"), 184 TagResolver.resolver("url", Tag.preProcessParsed(link)) 185 ); 186 } else { 187 final String responseMessage = jsonObject.get("response").getAsString(); 188 player.sendMessage( 189 TranslatableCaption.of("debugpaste.creation_failed"), 190 TagResolver.resolver("value", Tag.inserting(Component.text(responseMessage))) 191 ); 192 } 193 } catch (final Throwable throwable) { 194 throwable.printStackTrace(); 195 player.sendMessage( 196 TranslatableCaption.of("debugpaste.creation_failed"), 197 TagResolver.resolver("value", Tag.inserting(Component.text(throwable.getMessage()))) 198 ); 199 } 200 } catch (IOException e) { 201 e.printStackTrace(); 202 } 203 }); 204 return true; 205 } 206 207}