From f3866d5f6f7e763ebd19201fff94badc1c10a46d Mon Sep 17 00:00:00 2001 From: JoshiCodes <55353244+JoshiCodes@users.noreply.github.com> Date: Sun, 11 Jun 2023 19:31:19 +0200 Subject: [PATCH] Improved the RestAction Implementation - Added RequestHandler#processQueue and RequestHandler#queueRequest - Modified RestAction#queue - Added the usage of caching back to RJA#retrieve... - Added some extra Null-Checks --- src/main/java/de/joshicodes/rja/RJA.java | 40 +++++++++++--- .../rja/event/message/MessageUpdateEvent.java | 8 ++- .../rja/object/message/Message.java | 1 + .../rja/requests/RequestHandler.java | 39 ++++++++++++- .../de/joshicodes/rja/rest/RestAction.java | 55 +++---------------- 5 files changed, 86 insertions(+), 57 deletions(-) diff --git a/src/main/java/de/joshicodes/rja/RJA.java b/src/main/java/de/joshicodes/rja/RJA.java index 6c36eb7..1b58604 100644 --- a/src/main/java/de/joshicodes/rja/RJA.java +++ b/src/main/java/de/joshicodes/rja/RJA.java @@ -162,7 +162,11 @@ public void shutdownNow() { * */ public RestAction retrieveUser(String id) { - return new RestAction<>(this, () -> new FetchUserRequest(id)); + final RJA rja = this; + return new SimpleRestAction<>(this, () -> { + if(userCache.containsKey(id)) return userCache.get(id); + else return new RestAction<>(rja, () -> new FetchUserRequest(id)).complete(); + }); } public RestAction retrieveMember(final Server server, final User user) { @@ -186,15 +190,30 @@ public RestAction retrieveMessage(String channel, String id) { } public RestAction retrieveMessage(String channel, String id, boolean forceFetch) { - return new RestAction<>(this, () -> new FetchMessageRequest(channel, id)); + if(channel == null || channel.isEmpty() || id == null || id.isEmpty()) { + throw new IllegalArgumentException("Channel and ID cannot be null or empty"); + } + final RJA rja = this; + return new SimpleRestAction<>(this, () -> { + if(messageCache.containsKey(id) && !forceFetch) return messageCache.get(id); + else return new RestAction<>(rja, () -> new FetchMessageRequest(channel, id)).complete(); + }); } public RestAction retrieveEmoji(String id) { - return new RestAction<>(this, () -> new FetchEmojiRequest(id)); + final RJA rja = this; + return new SimpleRestAction<>(this, () -> { + if(emojiCache.containsKey(id)) return emojiCache.get(id); + else return new RestAction<>(rja, () -> new FetchEmojiRequest(id)).complete(); + }); } public RestAction retrieveDirectChannel(String id) { - return new RestAction<>(this, () -> new OpenDirectMessageRequest(id)); + final RJA rja = this; + return new SimpleRestAction<>(this, () -> { + if(channelCache.containsKey(id) && channelCache.get(id) instanceof DirectChannel direct) return direct; + else return new RestAction<>(rja, () -> new OpenDirectMessageRequest(id)).complete(); + }); } /** @@ -204,10 +223,14 @@ public RestAction retrieveDirectChannel(String id) { * @return The RestAction containing the channel. Use {@link RestAction#complete()} or {@link RestAction#queue} to get the channel. Channel can be null. */ public RestAction retrieveChannel(String id) { - return new RestAction(this, () -> new FetchChannelRequest(id)); + final RJA rja = this; + return new SimpleRestAction<>(this, () -> { + if(channelCache.containsKey(id)) return channelCache.get(id); + else return new RestAction<>(rja, () -> new FetchChannelRequest(id)).complete(); + }); } - public TextChannel retrieveTextChannel(String id) { + public TextChannel getTextChannel(String id) { GenericChannel c = retrieveChannel(id).complete(); if(c instanceof TextChannel tc) return tc; else throw new InvalidChannelTypeException(id, ChannelType.TEXT_CHANNEL, c.getType()); @@ -215,7 +238,10 @@ public TextChannel retrieveTextChannel(String id) { public RestAction retrieveServer(String serverId) { final RJA rja = this; - return new RestAction<>(this, () -> new FetchServerRequest(serverId)); + return new SimpleRestAction<>(this, () -> { + if(serverCache.containsKey(serverId)) return serverCache.get(serverId); + else return new RestAction<>(rja, () -> new FetchServerRequest(serverId)).complete(); + }); } public void cacheMessage(Message message) { diff --git a/src/main/java/de/joshicodes/rja/event/message/MessageUpdateEvent.java b/src/main/java/de/joshicodes/rja/event/message/MessageUpdateEvent.java index 6e25996..405a336 100644 --- a/src/main/java/de/joshicodes/rja/event/message/MessageUpdateEvent.java +++ b/src/main/java/de/joshicodes/rja/event/message/MessageUpdateEvent.java @@ -56,9 +56,11 @@ public IncomingEvent handle(RJA rja, JsonObject object) { Message message; if(!inCache) { // Message not in cache, cannot update with partial data -> fetch full message - RestResponse response = rja.getRequestHandler().fetchRequest(rja, new FetchMessageRequest(channel, id)); - if(response.isOk()) { - message = response.object(); + if(channel != null && id != null) { + RestResponse response = rja.getRequestHandler().fetchRequest(rja, new FetchMessageRequest(channel, id)); + if(response.isOk()) { + message = response.object(); + } else return null; } else return null; } else message = rja.getMessageCache().getIf(m -> m.equals(id)); Message updated = Message.from(rja, object.get("data").getAsJsonObject(), message); diff --git a/src/main/java/de/joshicodes/rja/object/message/Message.java b/src/main/java/de/joshicodes/rja/object/message/Message.java index 3a58916..48dc1d2 100644 --- a/src/main/java/de/joshicodes/rja/object/message/Message.java +++ b/src/main/java/de/joshicodes/rja/object/message/Message.java @@ -373,6 +373,7 @@ public RestAction react(String emoji) { AddReactionRequest request = new AddReactionRequest(getChannelId(), getId(), emoji); getRJA().getRequestHandler().fetchRequest(getRJA(), request); MessageReaction reaction = getReaction(emoji); + if(reaction == null) return null; reaction.addReaction(getRJA().retrieveSelfUser().complete().getId()); return reaction; }); diff --git a/src/main/java/de/joshicodes/rja/requests/RequestHandler.java b/src/main/java/de/joshicodes/rja/requests/RequestHandler.java index b78d814..74540b5 100644 --- a/src/main/java/de/joshicodes/rja/requests/RequestHandler.java +++ b/src/main/java/de/joshicodes/rja/requests/RequestHandler.java @@ -12,6 +12,7 @@ import de.joshicodes.rja.requests.packet.PingRequest; import de.joshicodes.rja.requests.rest.RestRequest; import de.joshicodes.rja.requests.rest.RestResponse; +import de.joshicodes.rja.rest.RestAction; import de.joshicodes.rja.util.Pair; import org.java_websocket.exceptions.WebsocketNotConnectedException; import org.java_websocket.framing.CloseFrame; @@ -22,6 +23,7 @@ import java.net.URISyntaxException; import java.util.*; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; public class RequestHandler { @@ -33,10 +35,14 @@ public class RequestHandler { private final List listeners; private final List events; + private final HashMap, Pair, Consumer>> actionQueue; + private boolean processingQueue = false; + public RequestHandler(RJABuilder rja, List listeners, List events) throws URISyntaxException { this.rja = rja; this.listeners = listeners; this.events = events; + this.actionQueue = new HashMap<>(); rja.getLogger().info("Connecting..."); this.socket = new RequestSocket(this); } @@ -68,7 +74,7 @@ public void run() { * * @deprecated Use {@link #fetchRequest(RJA, RestRequest)} instead */ - @Deprecated(forRemoval = true) + @Deprecated(forRemoval = true, since = "1.1-alpha.1") public T sendRequest(final RJA rja, RestRequest request) { final RJABuilder builder = this.rja; Pair multi = builder.makeRequest(request); @@ -80,6 +86,37 @@ public T sendRequest(final RJA rja, RestRequest request) { return request.fetch(rja, multi.getFirst(), e); } + private void processQueue() { + if(processingQueue || actionQueue.isEmpty()) + return; + processingQueue = true; + new Thread(() -> { + Iterator> iterator = actionQueue.keySet().iterator(); + while(iterator.hasNext()) { + final RestAction action = iterator.next(); + final Pair, Consumer> pair = actionQueue.get(action); + try { + Object result = action.complete(); + if(pair.getFirst() != null) { + pair.getFirst().accept(result); + } + } catch (Exception e) { + e.printStackTrace(); + if(pair.getSecond() != null) { + pair.getSecond().accept(e); + } + } + iterator.remove(); + } + processingQueue = false; + }).start(); + } + + public void queueRequest(RestAction action, Consumer success, Consumer failure) { + actionQueue.put(action, new Pair<>(success, failure)); + processQueue(); + } + public RestResponse fetchRequest(final RJA rja, RestRequest request) { final RJABuilder builder = this.rja; Pair multi = builder.makeRequest(request); diff --git a/src/main/java/de/joshicodes/rja/rest/RestAction.java b/src/main/java/de/joshicodes/rja/rest/RestAction.java index 4cef3cd..7cc19da 100644 --- a/src/main/java/de/joshicodes/rja/rest/RestAction.java +++ b/src/main/java/de/joshicodes/rja/rest/RestAction.java @@ -7,9 +7,7 @@ import de.joshicodes.rja.requests.rest.RestResponse; import de.joshicodes.rja.util.Pair; -import javax.annotation.Nullable; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.Supplier; public class RestAction { @@ -36,7 +34,7 @@ protected Pair execute() throws Exception { public R complete() { int attempts = 0; long retryAfter = 0; - while (attempts < MAX_ATTEMPTS) { + while (retryAfter != -1 && attempts < MAX_ATTEMPTS) { try { Pair result = execute(); if(result == null) { @@ -48,18 +46,18 @@ public R complete() { // Successfully got a result, call the success consumer and return return result.getSecond(); } - // Got ratelimited, wait and try again - try { - Thread.sleep(retryAfter); - } catch (InterruptedException e) { - e.printStackTrace(); - } - attempts++; } catch (Exception e) { // Failed to get a result e.printStackTrace(); continue; } + // Got ratelimited, wait and try again + try { + Thread.sleep(retryAfter); + } catch (InterruptedException e) { + e.printStackTrace(); + } + attempts++; } throw new RatelimitException(this, request.get()); } @@ -73,42 +71,7 @@ public void queue(Consumer success) { } public void queue(Consumer success, Consumer failure) { - final RestAction action = this; - new Thread(() -> { - int attempts = 0; - long retryAfter = 0; - while (attempts < MAX_ATTEMPTS) { - try { - Pair result = execute(); - if(result == null) { - // Failed to get a result, throw an exception - throw new RatelimitException(action, request.get()); - } - retryAfter = result.getFirst(); - if(retryAfter == -1) { - // Successfully got a result, call the success consumer and return - if(success != null) { - success.accept(result.getSecond()); - } - return; - } - // Got ratelimited, wait and try again - try { - Thread.sleep(retryAfter + 100); // Add 100ms to the ratelimit to make sure it's over - } catch (InterruptedException e) { - e.printStackTrace(); - } - attempts++; - } catch (Exception e) { - // Failed to get a result - e.printStackTrace(); - continue; - } - } - if(failure != null) { - failure.accept(new RatelimitException(action, request.get())); - } - }).start(); + rja.getRequestHandler().queueRequest(this, (Consumer) success, failure); } public RJA getRJA() {