Cleanup web clients

This commit is contained in:
Luck 2019-08-26 20:37:33 +01:00
parent 8b970c21fc
commit 419707aa5f
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
14 changed files with 274 additions and 673 deletions

View File

@ -41,7 +41,6 @@ import me.lucko.luckperms.common.commands.migration.MigrationMainCommand;
import me.lucko.luckperms.common.commands.misc.ApplyEditsCommand;
import me.lucko.luckperms.common.commands.misc.BulkUpdateCommand;
import me.lucko.luckperms.common.commands.misc.CheckCommand;
import me.lucko.luckperms.common.commands.misc.DebugCommand;
import me.lucko.luckperms.common.commands.misc.EditorCommand;
import me.lucko.luckperms.common.commands.misc.ExportCommand;
import me.lucko.luckperms.common.commands.misc.ImportCommand;
@ -111,7 +110,6 @@ public class CommandManager {
.add(new SyncCommand(locale))
.add(new InfoCommand(locale))
.add(new EditorCommand(locale))
.add(new DebugCommand(locale))
.add(new VerboseCommand(locale))
.add(new TreeCommand(locale))
.add(new SearchCommand(locale))

View File

@ -39,6 +39,8 @@ import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.Predicates;
import me.lucko.luckperms.common.util.gson.GsonProvider;
import me.lucko.luckperms.common.web.AbstractHttpClient;
import me.lucko.luckperms.common.web.WebEditor;
import net.kyori.text.Component;
@ -48,8 +50,14 @@ import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor;
import net.luckperms.api.context.ImmutableContextSet;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.zip.GZIPOutputStream;
public class HolderEditor<T extends PermissionHolder> extends SubCommand<T> {
public HolderEditor(LocaleManager locale, boolean user) {
@ -69,8 +77,17 @@ public class HolderEditor<T extends PermissionHolder> extends SubCommand<T> {
JsonObject payload = WebEditor.formPayload(Collections.singletonList(holder), Collections.emptyList(), sender, label, plugin);
// upload the payload data to gist
String pasteId = plugin.getBytebin().postJson(payload, true).id();
if (pasteId == null) {
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
try (Writer writer = new OutputStreamWriter(new GZIPOutputStream(bytesOut), StandardCharsets.UTF_8)) {
GsonProvider.prettyPrinting().toJson(payload, writer);
} catch (IOException e) {
e.printStackTrace();
}
String pasteId;
try {
pasteId = plugin.getBytebin().postContent(bytesOut.toByteArray(), AbstractHttpClient.JSON_TYPE, false).key();
} catch (IOException e) {
Message.EDITOR_UPLOAD_FAILURE.send(sender);
return CommandResult.STATE_ERROR;
}

View File

@ -1,299 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.lucko.luckperms.common.commands.misc;
import me.lucko.luckperms.common.cacheddata.type.MetaCache;
import me.lucko.luckperms.common.cacheddata.type.PermissionCache;
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
import me.lucko.luckperms.common.command.CommandResult;
import me.lucko.luckperms.common.command.abstraction.SingleCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.context.ContextSetJsonSerializer;
import me.lucko.luckperms.common.context.ProxiedContextCalculator;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.command.CommandSpec;
import me.lucko.luckperms.common.locale.message.Message;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.Predicates;
import me.lucko.luckperms.common.util.gson.GsonProvider;
import me.lucko.luckperms.common.util.gson.JArray;
import me.lucko.luckperms.common.util.gson.JObject;
import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
import me.lucko.luckperms.common.web.Hastebin;
import net.kyori.text.Component;
import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor;
import net.luckperms.api.context.ContextCalculator;
import net.luckperms.api.context.StaticContextCalculator;
import net.luckperms.api.metastacking.MetaStackDefinition;
import net.luckperms.api.metastacking.MetaStackElement;
import net.luckperms.api.query.Flag;
import net.luckperms.api.query.QueryOptions;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
public class DebugCommand extends SingleCommand {
public DebugCommand(LocaleManager locale) {
super(CommandSpec.DEBUG.localize(locale), "Debug", CommandPermission.DEBUG, Predicates.alwaysFalse());
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, List<String> args, String label) {
Message.DEBUG_START.send(sender);
StringBuilder sb = new StringBuilder();
sb.append("LuckPerms Debug Output\n\n\n");
BiConsumer<String, JObject> builder = (name, content) -> {
sb.append("-- ").append(name).append(" --\n");
sb.append(GsonProvider.prettyPrinting().toJson(content.toJson()));
sb.append("\n\n");
};
builder.accept("platform.json", getPlatformData(plugin));
builder.accept("storage.json", getStorageData(plugin));
builder.accept("context.json", getContextData(plugin));
builder.accept("players.json", getPlayersData(plugin));
String pasteUrl = Hastebin.INSTANCE.postPlain(sb.toString()).url();
Message.DEBUG_URL.send(sender);
Component message = TextComponent.builder(pasteUrl).color(TextColor.AQUA)
.clickEvent(ClickEvent.openUrl(pasteUrl))
.hoverEvent(HoverEvent.showText(TextComponent.of("Click to open the debugging data.").color(TextColor.GRAY)))
.build();
sender.sendMessage(message);
return CommandResult.SUCCESS;
}
private static JObject getPlatformData(LuckPermsPlugin plugin) {
return new JObject()
.add("type", plugin.getBootstrap().getType().name())
.add("version", new JObject()
.add("api", plugin.getApiProvider().getPluginMetadata().getApiVersion())
.add("plugin", plugin.getBootstrap().getVersion())
)
.add("server", new JObject()
.add("brand", plugin.getBootstrap().getServerBrand())
.add("version", plugin.getBootstrap().getServerVersion())
);
}
private static JObject getStorageData(LuckPermsPlugin plugin) {
return new JObject()
.add("storage", new JObject()
.add("name", plugin.getStorage().getName())
.add("type", plugin.getStorage().getImplementation().getClass().getName())
.add("meta", () -> {
JObject metaObject = new JObject();
Map<String, String> meta = plugin.getStorage().getMeta();
for (Map.Entry<String, String> entry : meta.entrySet()) {
metaObject.add(entry.getKey(), entry.getValue());
}
return metaObject;
}))
.add("messaging", () -> {
JObject messaging = new JObject();
plugin.getMessagingService().ifPresent(ms -> {
messaging.add("name", ms.getName());
messaging.add("implementation", new JObject()
.add("messenger", ms.getMessenger().getClass().getName())
.add("provider", ms.getMessengerProvider().getClass().getName())
);
});
return messaging;
});
}
private static JObject getContextData(LuckPermsPlugin plugin) {
return new JObject()
.add("staticContext", ContextSetJsonSerializer.serializeContextSet(plugin.getContextManager().getStaticContext()))
.add("calculators", () -> {
JArray calculators = new JArray();
for (ContextCalculator<?> calculator : plugin.getContextManager().getCalculators()) {
String name = calculator.getClass().getName();
if (calculator instanceof ProxiedContextCalculator) {
name = ((ProxiedContextCalculator) calculator).getDelegate().getClass().getName();
}
calculators.add(name);
}
return calculators;
})
.add("staticCalculators", () -> {
JArray staticCalculators = new JArray();
for (StaticContextCalculator calculator : plugin.getContextManager().getStaticCalculators()) {
staticCalculators.add(calculator.getClass().getName());
}
return staticCalculators;
});
}
private static JObject getPlayersData(LuckPermsPlugin plugin) {
JObject ret = new JObject();
Set<UUID> onlinePlayers = plugin.getBootstrap().getOnlinePlayers().collect(Collectors.toSet());
ret.add("count", onlinePlayers.size());
JArray playerArray = new JArray();
for (UUID uuid : onlinePlayers) {
User user = plugin.getUserManager().getIfLoaded(uuid);
if (user == null) {
playerArray.add(new JObject()
.add("uniqueId", uuid.toString())
.add("loaded", false)
);
continue;
}
playerArray.add(new JObject()
.add("uniqueId", uuid.toString())
.add("loaded", true)
.add("username", user.getName().orElse("null"))
.add("primaryGroup", new JObject()
.add("type", user.getPrimaryGroup().getClass().getName())
.add("value", user.getPrimaryGroup().getValue())
.add("storedValue", user.getPrimaryGroup().getStoredValue().orElse("null"))
)
.add("activeContext", () -> {
JObject obj = new JObject();
QueryOptions queryOptions = plugin.getQueryOptionsForUser(user).orElse(null);
if (queryOptions != null) {
obj.add("data", new JObject()
.add("permissions", serializePermissionsData(user.getCachedData().getPermissionData(queryOptions)))
.add("meta", serializeMetaData(user.getCachedData().getMetaData(queryOptions)))
)
.add("contextSet", ContextSetJsonSerializer.serializeContextSet(queryOptions.context()))
.add("queryOptions", serializeQueryOptions(queryOptions))
.add("metaSettings", serializeMetaContextsSettings(queryOptions));
}
return obj;
})
);
}
ret.add("players", playerArray);
return ret;
}
private static JArray serializeQueryOptions(QueryOptions queryOptions) {
JArray array = new JArray();
for (Flag setting : queryOptions.flags()) {
array.add(setting.name());
}
return array;
}
private static JObject serializeMetaContextsSettings(QueryOptions queryOptions) {
return new JObject()
.consume(obj -> {
Optional<MetaStackDefinition> prefixStack = queryOptions.option(MetaStackDefinition.PREFIX_STACK_KEY);
prefixStack.ifPresent(metaStackDefinition -> obj.add("prefixStack", serializeMetaStackData(metaStackDefinition)));
})
.consume(obj -> {
Optional<MetaStackDefinition> suffixStack = queryOptions.option(MetaStackDefinition.SUFFIX_STACK_KEY);
suffixStack.ifPresent(metaStackDefinition -> obj.add("suffixStack", serializeMetaStackData(metaStackDefinition)));
});
}
private static JObject serializePermissionsData(PermissionCache permissionData) {
return new JObject()
.add("processors", () -> {
JArray processors = new JArray();
for (PermissionProcessor processor : permissionData.getCalculator().getProcessors()) {
processors.add(processor.getClass().getName());
}
return processors;
});
}
private static JObject serializeMetaData(MetaCache metaData) {
return new JObject()
.add("prefix", metaData.getPrefix(MetaCheckEvent.Origin.INTERNAL))
.add("suffix", metaData.getSuffix(MetaCheckEvent.Origin.INTERNAL))
.add("prefixes", () -> {
JArray prefixes = new JArray();
for (Map.Entry<Integer, String> entry : metaData.getPrefixes().entrySet()) {
prefixes.add(new JObject()
.add("weight", entry.getKey())
.add("value", entry.getValue())
);
}
return prefixes;
})
.add("suffixes", () -> {
JArray suffixes = new JArray();
for (Map.Entry<Integer, String> entry : metaData.getSuffixes().entrySet()) {
suffixes.add(new JObject()
.add("weight", entry.getKey())
.add("value", entry.getValue())
);
}
return suffixes;
})
.add("meta", () -> {
JObject metaMultimap = new JObject();
for (Map.Entry<String, List<String>> entry : metaData.getMeta().entrySet()) {
JArray values = new JArray();
for (String v : entry.getValue()) {
values.add(v);
}
metaMultimap.add(entry.getKey(), values);
}
return metaMultimap;
});
}
private static JObject serializeMetaStackData(MetaStackDefinition definition) {
return new JObject()
.add("type", definition.getClass().getName())
.add("startSpacer", definition.getStartSpacer())
.add("middleSpacer", definition.getMiddleSpacer())
.add("endSpacer", definition.getEndSpacer())
.add("elements", () -> {
JArray elements = new JArray();
for (MetaStackElement element : definition.getElements()) {
elements.add(new JObject()
.add("type", element.getClass().getName())
.add("info", element.toString())
);
}
return elements;
});
}
}

View File

@ -41,6 +41,8 @@ import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.Predicates;
import me.lucko.luckperms.common.util.gson.GsonProvider;
import me.lucko.luckperms.common.web.AbstractHttpClient;
import me.lucko.luckperms.common.web.WebEditor;
import net.kyori.text.Component;
@ -49,8 +51,14 @@ import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPOutputStream;
public class EditorCommand extends SingleCommand {
public EditorCommand(LocaleManager locale) {
@ -110,8 +118,17 @@ public class EditorCommand extends SingleCommand {
JsonObject payload = WebEditor.formPayload(holders, tracks, sender, label, plugin);
// upload the payload data to gist
String pasteId = plugin.getBytebin().postJson(payload, true).id();
if (pasteId == null) {
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
try (Writer writer = new OutputStreamWriter(new GZIPOutputStream(bytesOut), StandardCharsets.UTF_8)) {
GsonProvider.prettyPrinting().toJson(payload, writer);
} catch (IOException e) {
e.printStackTrace();
}
String pasteId;
try {
pasteId = plugin.getBytebin().postContent(bytesOut.toByteArray(), AbstractHttpClient.JSON_TYPE, false).key();
} catch (IOException e) {
Message.EDITOR_UPLOAD_FAILURE.send(sender);
return CommandResult.STATE_ERROR;
}

View File

@ -53,10 +53,12 @@ import me.lucko.luckperms.common.storage.implementation.file.FileWatcher;
import me.lucko.luckperms.common.tasks.SyncTask;
import me.lucko.luckperms.common.treeview.PermissionRegistry;
import me.lucko.luckperms.common.verbose.VerboseHandler;
import me.lucko.luckperms.common.web.Bytebin;
import me.lucko.luckperms.common.web.BytebinClient;
import net.luckperms.api.LuckPerms;
import okhttp3.OkHttpClient;
import java.io.IOException;
import java.util.EnumSet;
import java.util.Optional;
@ -74,7 +76,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
private LogDispatcher logDispatcher;
private LuckPermsConfiguration configuration;
private LocaleManager localeManager;
private Bytebin bytebin;
private BytebinClient bytebin;
private FileWatcher fileWatcher = null;
private Storage storage;
private InternalMessagingService messagingService = null;
@ -115,7 +117,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
this.localeManager.tryLoad(this, getBootstrap().getConfigDirectory().resolve("lang.yml"));
// setup a bytebin instance
this.bytebin = new Bytebin(getConfiguration().get(ConfigKeys.BYTEBIN_URL));
this.bytebin = new BytebinClient(new OkHttpClient(), getConfiguration().get(ConfigKeys.BYTEBIN_URL), "luckperms");
// now the configuration is loaded, we can create a storage factory and load initial dependencies
StorageFactory storageFactory = new StorageFactory(this);
@ -302,7 +304,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
}
@Override
public Bytebin getBytebin() {
public BytebinClient getBytebin() {
return this.bytebin;
}

View File

@ -53,7 +53,7 @@ import me.lucko.luckperms.common.storage.implementation.file.FileWatcher;
import me.lucko.luckperms.common.tasks.SyncTask;
import me.lucko.luckperms.common.treeview.PermissionRegistry;
import me.lucko.luckperms.common.verbose.VerboseHandler;
import me.lucko.luckperms.common.web.Bytebin;
import me.lucko.luckperms.common.web.BytebinClient;
import net.luckperms.api.query.QueryOptions;
@ -237,7 +237,7 @@ public interface LuckPermsPlugin {
*
* @return the bytebin instance
*/
Bytebin getBytebin();
BytebinClient getBytebin();
/**
* Gets a calculated context instance for the user using the rules of the platform.

View File

@ -31,15 +31,23 @@ import com.google.gson.JsonObject;
import me.lucko.luckperms.common.cacheddata.type.PermissionCache;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.gson.GsonProvider;
import me.lucko.luckperms.common.util.gson.JObject;
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
import me.lucko.luckperms.common.web.Bytebin;
import me.lucko.luckperms.common.web.AbstractHttpClient;
import me.lucko.luckperms.common.web.BytebinClient;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.zip.GZIPOutputStream;
/**
* A readable view of a branch of {@link TreeNode}s.
@ -122,7 +130,7 @@ public class TreeView {
* @param checker the permission data instance to check against, or null
* @return the id, or null
*/
public String uploadPasteData(Bytebin bytebin, Sender sender, User user, PermissionCache checker) {
public String uploadPasteData(BytebinClient bytebin, Sender sender, User user, PermissionCache checker) {
// only paste if there is actually data here
if (!hasData()) {
throw new IllegalStateException();
@ -169,7 +177,19 @@ public class TreeView {
)
.toJson();
return bytebin.postJson(payload, true).id();
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
try (Writer writer = new OutputStreamWriter(new GZIPOutputStream(bytesOut), StandardCharsets.UTF_8)) {
GsonProvider.prettyPrinting().toJson(payload, writer);
} catch (IOException e) {
e.printStackTrace();
}
try {
return bytebin.postContent(bytesOut.toByteArray(), AbstractHttpClient.JSON_TYPE, false).key();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}

View File

@ -35,24 +35,32 @@ import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.DurationFormatter;
import me.lucko.luckperms.common.util.StackTracePrinter;
import me.lucko.luckperms.common.util.TextUtils;
import me.lucko.luckperms.common.util.gson.GsonProvider;
import me.lucko.luckperms.common.util.gson.JArray;
import me.lucko.luckperms.common.util.gson.JObject;
import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
import me.lucko.luckperms.common.verbose.event.VerboseEvent;
import me.lucko.luckperms.common.web.Bytebin;
import me.lucko.luckperms.common.web.AbstractHttpClient;
import me.lucko.luckperms.common.web.BytebinClient;
import net.kyori.text.TextComponent;
import net.kyori.text.event.HoverEvent;
import net.luckperms.api.node.Tristate;
import net.luckperms.api.query.QueryMode;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.zip.GZIPOutputStream;
/**
* Accepts and processes {@link VerboseEvent}, passed from the {@link VerboseHandler}.
@ -244,7 +252,7 @@ public class VerboseListener {
* @param bytebin the bytebin instance to upload with
* @return the url
*/
public String uploadPasteData(Bytebin bytebin) {
public String uploadPasteData(BytebinClient bytebin) {
// retrieve variables
long now = System.currentTimeMillis();
String startDate = DATE_FORMAT.format(new Date(this.startTime));
@ -287,7 +295,19 @@ public class VerboseListener {
.add("data", data)
.toJson();
return bytebin.postJson(payload, true).id();
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
try (Writer writer = new OutputStreamWriter(new GZIPOutputStream(bytesOut), StandardCharsets.UTF_8)) {
GsonProvider.prettyPrinting().toJson(payload, writer);
} catch (IOException e) {
e.printStackTrace();
}
try {
return bytebin.postContent(bytesOut.toByteArray(), AbstractHttpClient.JSON_TYPE, false).key();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private static String getTristateColor(Tristate tristate) {

View File

@ -25,40 +25,29 @@
package me.lucko.luckperms.common.web;
import com.google.gson.JsonObject;
import me.lucko.luckperms.common.util.gson.GsonProvider;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import java.io.BufferedReader;
import java.io.IOException;
public class Bytebin extends AbstractPastebin {
private final String url;
private final String postUrl;
public class AbstractHttpClient {
public Bytebin(String url) {
if (!url.endsWith("/")) {
url += "/";
}
this.url = url;
this.postUrl = url + "post";
public static final MediaType JSON_TYPE = MediaType.parse("application/json; charset=utf-8");
/** The http client */
protected final OkHttpClient okHttp;
public AbstractHttpClient(OkHttpClient okHttp) {
this.okHttp = okHttp;
}
@Override
protected String getPostUrl() {
return this.postUrl;
protected Response makeHttpRequest(Request request) throws IOException {
Response response = this.okHttp.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException("Request was unsuccessful: " + response.code() + " - " + response.message());
}
@Override
protected String parseIdFromResult(Response response, ResponseBody responseBody, BufferedReader responseBodyReader) {
JsonObject object = GsonProvider.prettyPrinting().fromJson(responseBodyReader, JsonObject.class);
return object.get("key").getAsString();
}
@Override
public String getPasteUrl(String id) {
return this.url + id;
return response;
}
}

View File

@ -1,182 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.lucko.luckperms.common.web;
import com.google.gson.JsonElement;
import me.lucko.luckperms.common.util.gson.GsonProvider;
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.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.zip.GZIPOutputStream;
/**
* Represents a pastebin service
*/
public abstract class AbstractPastebin {
private static final MediaType JSON_TYPE = MediaType.parse("application/json; charset=utf-8");
private static final MediaType PLAIN_TYPE = MediaType.parse("text/plain; charset=utf-8");
/**
* Gets the URL that post requests should be made to.
*
* @return the post URL
*/
protected abstract String getPostUrl();
/**
* Gets the id of the resultant post from the response of an upload request
*
* @param response the response
* @param responseBody the response body
* @param responseBodyReader the response body content
* @return
*/
protected abstract String parseIdFromResult(Response response, ResponseBody responseBody, BufferedReader responseBodyReader);
/**
* Gets the raw url of a paste's data from an id
*
* @param id the id
* @return a url
*/
public abstract String getPasteUrl(String id);
/**
* Posts the given json to the pastebin
*
* @param content the json element to post
* @param compress whether to compress and post the data using gzip
* @return a paste
*/
public Paste postJson(JsonElement content, boolean compress) {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
OutputStream outputStream;
if (compress) {
try {
outputStream = new GZIPOutputStream(byteOut);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
outputStream = byteOut;
}
try (Writer writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
GsonProvider.prettyPrinting().toJson(content, writer);
} catch (IOException e) {
throw new RuntimeException(e);
}
return post(RequestBody.create(JSON_TYPE, byteOut.toByteArray()), compress);
}
/**
* Posts "plain" content to the pastebin
*
* @param content the content
* @return a paste
*/
public Paste postPlain(String content) {
return post(RequestBody.create(PLAIN_TYPE, content), false);
}
private Paste post(RequestBody body, boolean compressed) {
Request.Builder requestBuilder = new Request.Builder()
.url(getPostUrl())
.post(body);
if (compressed) {
requestBuilder.header("Content-Encoding", "gzip");
}
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))) {
String id = parseIdFromResult(response, responseBody, reader);
String url = getPasteUrl(id);
return new Paste(url, id);
}
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Encapsulates the properties of a specific "paste" entry
*/
public static final class Paste {
private final String url;
private final String id;
Paste(String url, String id) {
this.url = url;
this.id = id;
}
/**
* Gets the url of the paste
*
* @return the url
*/
public String url() {
return this.url;
}
/**
* Gets the unique id of the paste
*
* @return the id
*/
public String id() {
return this.id;
}
}
}

View File

@ -0,0 +1,159 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.lucko.luckperms.common.web;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
public class BytebinClient extends AbstractHttpClient {
/** The bytebin URL */
private final String url;
/** The client user agent */
private final String userAgent;
/**
* Creates a new bytebin instance
*
* @param url the bytebin url
* @param userAgent the client user agent string
*/
public BytebinClient(OkHttpClient okHttpClient, String url, String userAgent) {
super(okHttpClient);
if (url.endsWith("/")) {
this.url = url;
} else {
this.url = url + "/";
}
this.userAgent = userAgent;
}
public String getUrl() {
return this.url;
}
public String getUserAgent() {
return this.userAgent;
}
@Override
public Response makeHttpRequest(Request request) throws IOException {
return super.makeHttpRequest(request);
}
/**
* POSTs GZIP compressed content to bytebin.
*
* @param buf the compressed content
* @param contentType the type of the content
* @param allowModification if the paste should be modifiable
* @return the key of the resultant content
* @throws IOException if an error occurs
*/
public Content postContent(byte[] buf, MediaType contentType, boolean allowModification) throws IOException {
RequestBody body = RequestBody.create(contentType, buf);
Request.Builder requestBuilder = new Request.Builder()
.url(this.url + "post")
.header("User-Agent", this.userAgent)
.header("Content-Encoding", "gzip");
if (allowModification) {
requestBuilder.header("Allow-Modification", "true");
}
Request request = requestBuilder.post(body).build();
try (Response response = makeHttpRequest(request)) {
String key = response.header("Location");
if (key == null) {
throw new IllegalStateException("Key not returned");
}
if (allowModification) {
String modificationKey = response.header("Modification-Key");
if (modificationKey == null) {
throw new IllegalStateException("Modification key not returned");
}
return new Content(key, modificationKey);
} else {
return new Content(key);
}
}
}
/**
* PUTs modified GZIP compressed content to bytebin in place of existing content.
*
* @param existingContent the existing content
* @param buf the compressed content to put
* @param contentType the type of the content
* @throws IOException if an error occurs
*/
public void modifyContent(Content existingContent, byte[] buf, MediaType contentType) throws IOException {
if (!existingContent.modifiable) {
throw new IllegalArgumentException("Existing content is not modifiable");
}
RequestBody body = RequestBody.create(contentType, buf);
Request.Builder requestBuilder = new Request.Builder()
.url(this.url + existingContent.key())
.header("User-Agent", this.userAgent)
.header("Content-Encoding", "gzip")
.header("Modification-Key", existingContent.modificationKey);
Request request = requestBuilder.put(body).build();
makeHttpRequest(request).close();
}
public static final class Content {
private final String key;
private final boolean modifiable;
private final String modificationKey;
Content(String key) {
this.key = key;
this.modifiable = false;
this.modificationKey = null;
}
Content(String key, String modificationKey) {
this.key = key;
this.modifiable = true;
this.modificationKey = modificationKey;
}
public String key() {
return this.key;
}
}
}

View File

@ -1,63 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.lucko.luckperms.common.web;
import com.google.gson.JsonObject;
import me.lucko.luckperms.common.util.gson.GsonProvider;
import okhttp3.Response;
import okhttp3.ResponseBody;
import java.io.BufferedReader;
public class Hastebin extends AbstractPastebin {
public static final Hastebin INSTANCE = new Hastebin();
private static final String URL = "https://hastebin.com/";
private static final String RAW_URL = URL + "raw/";
private static final String POST_URL = URL + "documents";
private Hastebin() {
}
@Override
protected String getPostUrl() {
return POST_URL;
}
@Override
protected String parseIdFromResult(Response response, ResponseBody responseBody, BufferedReader responseBodyReader) {
JsonObject object = GsonProvider.prettyPrinting().fromJson(responseBodyReader, JsonObject.class);
return object.get("key").getAsString();
}
@Override
public String getPasteUrl(String id) {
return RAW_URL + id;
}
}

View File

@ -1,78 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.lucko.luckperms.common.web;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import java.io.IOException;
/**
* Utilities for the OkHttp client
*/
public final class HttpClient {
private HttpClient() {}
private static final OkHttpClient CLIENT = new OkHttpClient.Builder()
.addInterceptor(new LuckPermsUserAgentInterceptor())
.build();
public static Response makeCall(Request request) throws IOException {
Response response = CLIENT.newCall(request).execute();
if (!response.isSuccessful()) {
throw exceptionForUnsuccessfulResponse(response);
}
return response;
}
private static RuntimeException exceptionForUnsuccessfulResponse(Response response) {
String msg = "";
try (ResponseBody responseBody = response.body()) {
if (responseBody != null) {
msg = responseBody.string();
}
} catch (IOException e) {
// ignore
}
return new RuntimeException("Got response: " + response.code() + " - " + response.message() + " - " + msg);
}
private static final class LuckPermsUserAgentInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request orig = chain.request();
Request modified = orig.newBuilder()
.header("User-Agent", "luckperms")
.build();
return chain.proceed(modified);
}
}
}

View File

@ -116,12 +116,13 @@ public final class WebEditor {
).toJson();
}
public static JsonObject readDataFromBytebin(Bytebin bytebin, String id) {
public static JsonObject readDataFromBytebin(BytebinClient bytebin, String id) {
Request request = new Request.Builder()
.url(bytebin.getPasteUrl(id))
.header("User-Agent", bytebin.getUserAgent())
.url(bytebin.getUrl() + id)
.build();
try (Response response = HttpClient.makeCall(request)) {
try (Response response = bytebin.makeHttpRequest(request)) {
try (ResponseBody responseBody = response.body()) {
if (responseBody == null) {
throw new RuntimeException("No response");