added discord webhook support

This commit is contained in:
00asdf 2023-06-21 01:45:22 +02:00
parent 2a7da78acb
commit 848748c4b9
3 changed files with 125 additions and 0 deletions

View File

@ -0,0 +1,111 @@
package dev.asdf00.general.utils.discord;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public final class DiscordHook {
private static final HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.build();
private static final Map<String, DiscordHook> currentHooks = new HashMap<>();
private final String webhook;
private final Queue<String> msgQueue = new ConcurrentLinkedQueue<>();
private final Executor thread = Executors.newSingleThreadExecutor();
private final Object lockObject = new Object();
private int timeoutInMillis = 5000;
private DiscordHook(String webhook) {
this.webhook = webhook;
}
/**
* Send a message to the associated discord webhook.
*
* @param splitMessage determines if the message should be pruned or split into
* multiple messages if it is lager than 2000 characters
* @param msg the message to be sent
* @param args arguments to be formatted into the message
*/
public void sendMsg(boolean splitMessage, String msg, Object... args) {
var pmsg = String.format(msg, args);
int cnt = 1;
if (!splitMessage && pmsg.length() > 1994) {
// large message with pruning
msgQueue.add(pmsg.substring(0, 1995) + " [...]");
} else if (pmsg.length() > 2000) {
// large message with splitting
var ms = new ArrayList<String>(pmsg.length() / 2000 + 1);
for (int i = 0; i < ms.size(); i++) {
ms.add(pmsg.substring(i * 2000, Math.min(pmsg.length(), (i + 1) * 2000 + 1)));
}
msgQueue.addAll(ms);
cnt = ms.size();
} else {
// small message
msgQueue.add(pmsg);
}
// schedule all messages inserted into the queue
for (; cnt > 0; cnt--) {
thread.execute(this::scheduleMsg);
}
}
private static String wrapIntoJson(String msg) {
return String.format("{\"content\": \"%s\"}", msg);
}
private void scheduleMsg() {
try {
var json = msgQueue.remove();
synchronized (lockObject) {
var postRequest = HttpRequest.newBuilder()
.POST(HttpRequest.BodyPublishers.ofString(json))
.uri(URI.create(webhook))
.setHeader("User-Agent", "JavaCrawler")
.header("Content-Type", "application/json")
.build();
httpClient.send(postRequest, HttpResponse.BodyHandlers.ofString());
Thread.sleep(timeoutInMillis);
}
} catch (InterruptedException | IOException e) {
throw new RuntimeException(e);
}
}
/**
* Sets the timeout for rate limiting. Default is 5 seconds.
*/
public void setTimeout(int timeout) {
timeoutInMillis = timeout;
}
/**
* Gets the instance associated with this webhook or creates a new one if no instance was found.
*
* @param webhook the URI of the discord webhook
* @return instance associated with the given webhook
*/
public static synchronized DiscordHook getInstance(String webhook) {
if (!currentHooks.containsKey(webhook)) {
currentHooks.put(webhook, new DiscordHook(webhook));
}
return currentHooks.get(webhook);
}
}

View File

@ -0,0 +1,11 @@
package dev.asdf00.general.utils.extras;
public class Tuple<A, B> {
public A a;
public B b;
public Tuple() { }
public Tuple(A a, B b) {
this.a = a;
this.b = b;
}
}

View File

@ -1,4 +1,7 @@
module GeneralUtils {
requires jdk.unsupported;
requires java.net.http;
exports dev.asdf00.general.utils.discord;
exports dev.asdf00.general.utils.extras;
exports dev.asdf00.general.utils.list;
}