/* * This file is part of GriefPrevention, licensed under the MIT License (MIT). * * Copyright (c) bloodmc * Copyright (c) contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package me.ryanhamshire.griefprevention; import com.google.gson.Gson; import com.google.gson.JsonObject; import me.ryanhamshire.griefprevention.util.HttpClient; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.plugin.PluginContainer; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.util.Tristate; import okhttp3.MediaType; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.zip.GZIPOutputStream; public class GPDebugData { private static final String BYTEBIN_ENDPOINT = "https://bytebin.lucko.me/post"; private static final String DEBUG_VIEWER_URL = "https://griefprevention.github.io/debug/?"; private static final MediaType PLAIN_TYPE = MediaType.parse("text/plain; charset=utf-8"); private static final int MAX_LINES = 5000; private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); private static final Text GP_TEXT = Text.of(TextColors.RESET, "[", TextColors.AQUA, "GP", TextColors.WHITE, "] "); private final CommandSource source; private final List<String> header; private final List<String> records; private final long startTime = System.currentTimeMillis(); private boolean verbose; private User target; public GPDebugData(CommandSource source, User target, boolean verbose) { this.source = source; this.target = target; this.verbose = verbose; this.records = new ArrayList<>(); this.header = new ArrayList<>(); this.header.add("# GriefPrevention Debug Log"); this.header.add("#### This file was automatically generated by [GriefPrevention](https://github.com/MinecraftPortCentral/GriefPrevention) "); this.header.add(""); this.header.add("### Metadata"); this.header.add("| Key | Value |"); this.header.add("|-----|-------|"); this.header.add("| GP Version | " + GriefPreventionPlugin.IMPLEMENTATION_VERSION + "|"); this.header.add("| Sponge Version | " + GriefPreventionPlugin.SPONGE_VERSION + "|"); final PluginContainer lpContainer = Sponge.getPluginManager().getPlugin("luckperms").orElse(null); if (lpContainer != null) { final String version = lpContainer.getVersion().orElse(null); if (version != null) { this.header.add("| LuckPerms Version | " + version); } } this.header.add("| User | " + (this.target == null ? "ALL" : this.target.getName()) + "|"); this.header.add("| Record start | " + DATE_FORMAT.format(new Date(this.startTime)) + "|"); } public void addRecord(String flag, String trust, String source, String target, String location, String user, Tristate result) { if (this.records.size() < MAX_LINES) { this.records.add("| " + flag + " | " + trust + " | " + source + " | " + target + " | " + location + " | " + user + " | " + result + " | "); } else { this.source.sendMessage(Text.of("MAX DEBUG LIMIT REACHED!", "\n", TextColors.GREEN, "Pasting output...")); this.pasteRecords(); this.records.clear(); GriefPreventionPlugin.debugActive = false; this.source.sendMessage(Text.of(GP_TEXT, TextColors.GRAY, "Debug ", TextColors.RED, "OFF")); } } public CommandSource getSource() { return this.source; } public User getTarget() { return this.target; } public boolean isRecording() { return !this.verbose; } public void setTarget(User user) { this.target = user; } public void setVerbose(boolean verbose) { this.verbose = verbose; } public void pasteRecords() { if (this.records.isEmpty()) { this.source.sendMessage(Text.of(TextColors.RED, "No debug records to paste!")); return; } final long endTime = System.currentTimeMillis(); List<String> debugOutput = new ArrayList<>(this.header); debugOutput.add("| Record end | " + DATE_FORMAT.format(new Date(endTime)) + "|"); long elapsed = (endTime - startTime) / 1000L; debugOutput.add("| Time elapsed | " + elapsed + " seconds" + "|"); debugOutput.add(""); debugOutput.add("### Output") ; debugOutput.add("| Flag | Trust | Source | Target | Location | User | Result |"); debugOutput.add("|------|-------|--------|--------|----------|------|--------|"); debugOutput.addAll(this.records); String content = String.join("\n", debugOutput); String pasteId; try { pasteId = postContent(content); } catch (Exception e) { this.source.sendMessage(Text.of(TextColors.RED, "Error uploading content : ", TextColors.WHITE, e.getMessage())); return; } String url = DEBUG_VIEWER_URL + pasteId; URL jUrl; try { jUrl = new URL(url); } catch (MalformedURLException e) { throw new RuntimeException(e); } this.source.sendMessage(Text.builder().append(Text.of(TextColors.GREEN, "Paste success! : " + url)) .onClick(TextActions.openUrl(jUrl)).build()); } private static String postContent(String content) throws IOException { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); try (GZIPOutputStream writer = new GZIPOutputStream(byteOut)) { writer.write(content.getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { throw new RuntimeException(e); } RequestBody body = RequestBody.create(PLAIN_TYPE, byteOut.toByteArray()); Request.Builder requestBuilder = new Request.Builder() .url(BYTEBIN_ENDPOINT) .header("Content-Encoding", "gzip") .post(body); Request request = requestBuilder.build(); try (Response response = HttpClient.makeCall(request)) { try (ResponseBody responseBody = response.body()) { if (responseBody == null) { throw new RuntimeException("No response"); } try (InputStream inputStream = responseBody.byteStream()) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { JsonObject object = new Gson().fromJson(reader, JsonObject.class); return object.get("key").getAsString(); } } } } } }