Skip to content

Commit 93caa55

Browse files
authored
Merge pull request #165 from botblock/feature/add-javacord-support
v6.1.0: Javacord support
2 parents 9f7c4dc + b300565 commit 93caa55

File tree

12 files changed

+391
-54
lines changed

12 files changed

+391
-54
lines changed

build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,19 @@ allprojects {
5757
def opt = it as StandardJavadocDocletOptions
5858

5959
opt.links(
60+
// JSON Lib
6061
"https://stleary.github.io/JSON-java/",
62+
63+
// Discord Libs
6164
"https://ci.dv8tion.net/job/JDA/javadoc/",
65+
66+
// Java 8
6267
"https://docs.oracle.com/javase/8/docs/api/",
68+
69+
// BotBlock Docs
6370
"https://docs.botblock.org/JavaBotBlockAPI/core/",
6471
"https://docs.botblock.org/JavaBotBlockAPI/jda/",
72+
//"https://docs.botblock.org/JavaBotBlockAPI/javacord/",
6573
"https://docs.botblock.org/JavaBotBlockAPI/request/"
6674
)
6775

core/src/main/java/org/botblock/javabotblockapi/core/CheckUtil.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,47 @@
2020

2121
import java.util.Map;
2222

23+
/**
24+
* Util class to perform basic checks.
25+
*/
2326
public class CheckUtil{
2427

28+
/**
29+
* Will throw a {@link java.lang.NullPointerException NullPointerException} when the provided String is empty.
30+
*
31+
* @param value
32+
* The String to check.
33+
* @param name
34+
* The name of the parameter checked.
35+
*/
2536
public static void notEmpty(String value, String name){
2637
if(value.isEmpty())
2738
throw new NullPointerException(name + " may not be empty.");
2839
}
2940

41+
/**
42+
* Will throw a {@link java.lang.NullPointerException NullPointerException} when the provided Map is empty.
43+
*
44+
* @param value
45+
* The Map to check.
46+
* @param name
47+
* The name of the parameter checked.
48+
*/
3049
public static void notEmpty(Map<?, ?> value, String name){
3150
if(value.isEmpty())
3251
throw new NullPointerException(name + " may not be empty.");
3352
}
3453

35-
public static void condition(boolean check, String message){
36-
if(check)
54+
/**
55+
* Will throw a {@link java.lang.IllegalStateException IllegalStateException} when the provided expression returns true.
56+
*
57+
* @param expression
58+
* The expression to check against.
59+
* @param message
60+
* The message to print in the Exception when thrown.
61+
*/
62+
public static void condition(boolean expression, String message){
63+
if(expression)
3764
throw new IllegalStateException(message);
3865
}
3966
}

core/src/main/java/org/botblock/javabotblockapi/core/annotations/PlannedRemoval.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
/**
2424
* Annotation to mark an Object to be planned for removal.
25-
* <br>This is often paired with the {@link java.lang.Deprecated Deprecated} and
25+
* <br>This is paired with the {@link java.lang.Deprecated Deprecated} and
2626
* {@link org.botblock.javabotblockapi.core.annotations.DeprecatedSince DeprecatedSince} annotations.
2727
*
2828
* <p>This annotation will always contain {@link #version() the version} in which the annotated Object will be removed.

core/src/main/java/org/botblock/javabotblockapi/core/exceptions/RatelimitedException.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,13 @@ public String toString(){
9191
}
9292

9393
/**
94-
* Returns a formatted message displaying the various information returned in this exception.
95-
* <br>This essentially returns the same value as {@link #toString() toString()} does.
94+
* Returns a message informing us about {@link #getRoute() where} we got rate limited, {@link #getDelay() for how long} and
95+
* on what {@link #getBotId() bot id} and {@link #getIp() ip}.
9696
*
97-
* @return Formatted String containing the provided information from the response. Same format as {@link #toString() toString()}.
97+
* @return String containing a message with route, delay, bot id and IP.
9898
*/
9999
@Override
100100
public String getMessage(){
101-
return toString();
101+
return "Got rate limited on route" + route + " for " + delay + "ms with bot id " + botId + " (ip: " + ip + ")";
102102
}
103103
}

javacord/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
dependencies {
2+
api group: 'org.javacord', name: 'javacord', version: '3.0.7'
3+
implementation project(":core")
4+
implementation project(":request")
5+
}
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/*
2+
* Copyright 2019 - 2020 Andre601
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
6+
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
7+
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8+
*
9+
* The above copyright notice and this permission notice shall be included in all copies or substantial
10+
* portions of the Software.
11+
*
12+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13+
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
14+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
15+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
16+
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17+
*/
18+
19+
package org.botblock.javabotblockapi.javacord;
20+
21+
import org.botblock.javabotblockapi.core.BotBlockAPI;
22+
import org.botblock.javabotblockapi.core.exceptions.RatelimitedException;
23+
import org.botblock.javabotblockapi.requests.handler.RequestHandler;
24+
import org.javacord.api.DiscordApi;
25+
import org.json.JSONArray;
26+
import org.json.JSONObject;
27+
28+
import javax.annotation.Nonnull;
29+
import javax.annotation.Nullable;
30+
import java.io.IOException;
31+
import java.util.ArrayList;
32+
import java.util.Arrays;
33+
import java.util.Collection;
34+
import java.util.List;
35+
import java.util.concurrent.ScheduledExecutorService;
36+
import java.util.concurrent.TimeUnit;
37+
38+
/**
39+
* Class used to perform POST requests towards the <a href="https://botblock.org/api/docs#count" target="_blank">/api/count</a>
40+
* endpoint of BotBlock.
41+
*
42+
* <p>The class offers options to post either
43+
*/
44+
public class PostAction{
45+
private final RequestHandler requestHandler;
46+
private final ScheduledExecutorService scheduler;
47+
48+
/**
49+
* Creates a new instance of this class.
50+
* <br>This will set the UserAgent used for POST request to {@code <botname>-<discriminator>/<api-version> (Javacord) DBots/<id>}
51+
* using the provided {@link org.javacord.api.DiscordApi DiscordApi instance}.
52+
*
53+
* @param api
54+
* The {@link org.javacord.api.DiscordApi DiscordApi instance} used to set the UserAgent.
55+
*/
56+
public PostAction(DiscordApi api){
57+
this.requestHandler = new RequestHandler(String.format(
58+
"%s-%s/API_VERSION (Javacord) DBots/%s",
59+
api.getYourself().getName(),
60+
api.getYourself().getDiscriminator(),
61+
api.getYourself().getId()
62+
));
63+
this.scheduler = requestHandler.getScheduler();
64+
}
65+
66+
/**
67+
* Disables the automatic posting of Stats.
68+
* <br>This essentially just performs a {@link java.util.concurrent.ScheduledExecutorService#shutdown() ScheduledExecutorService.shutdown()}
69+
* by calling the {@link #disableAutoPost(BotBlockAPI) disableAutoPost(null)} method.
70+
*
71+
* <p>Note that using this method will NOT make the scheduler wait for previously scheduled tasks to complete.
72+
* <br>If you want to wait for the tasks to complete use {@link #disableAutoPost(BotBlockAPI) disableAutoPost(BotBlockAPI)} or
73+
* {@link #disableAutoPost(long, TimeUnit) disableAutoPost(long, TimeUnit)} instead.
74+
*
75+
* @see java.util.concurrent.ScheduledExecutorService#shutdown()
76+
*/
77+
public void disableAutoPost(){
78+
disableAutoPost(null);
79+
}
80+
81+
/**
82+
* Disables the automatic posting of Stats.
83+
* <br>Unlike {@link #disableAutoPost() disableAutoPost()} can you make the scheduler wait for all scheduled tasks to
84+
* finish, or to time out after n minutes by providing the {@link org.botblock.javabotblockapi.core.BotBlockAPI BotBlock instance}.
85+
*
86+
* <p>Passing null as argument will just perform a {@link java.util.concurrent.ScheduledExecutorService#shutdown() ScheduledExecutorService.shutdown()}
87+
* similar to what the disableAutoPost() method does.
88+
*
89+
* <p>If you want to use a different delay than what you've set in the BotBlockAPI instance, can you use
90+
* {@link #disableAutoPost(long, TimeUnit) disableAutoPost(long, TimeUnit)} instead.
91+
*
92+
* <p>This method may throw a {@link java.lang.InterruptedException InterruptedException} in the terminal.
93+
*
94+
* @param botBlockAPI
95+
* The {@link org.botblock.javabotblockapi.core.BotBlockAPI BotBlockAPI instance} or null to just perform a shutdown.
96+
*
97+
* @see java.util.concurrent.ScheduledExecutorService#shutdown()
98+
* @see java.util.concurrent.ScheduledExecutorService#awaitTermination(long, TimeUnit)
99+
*/
100+
public void disableAutoPost(@Nullable BotBlockAPI botBlockAPI){
101+
if(botBlockAPI != null){
102+
disableAutoPost(botBlockAPI.getUpdateDelay(), TimeUnit.MINUTES);
103+
return;
104+
}
105+
106+
scheduler.shutdown();
107+
}
108+
109+
/**
110+
* Disables the automatic posting of Stats.
111+
* <br>Unlike {@link #disableAutoPost() disableAutoPost()} can you make the scheduler wait for all scheduled tasks to
112+
* finish, or to time out after a specified time frame.
113+
*
114+
* <p>This method may throw a {@link java.lang.InterruptedException InterruptedException} in the terminal.
115+
*
116+
* @param time
117+
* The amount of time to wait for scheduled executions to finish before the Scheduler would time out.
118+
* @param timeUnit
119+
* The {@link java.util.concurrent.TimeUnit TimeUnit} to use.
120+
*
121+
* @see java.util.concurrent.ScheduledExecutorService#awaitTermination(long, TimeUnit)
122+
*/
123+
public void disableAutoPost(long time, @Nonnull TimeUnit timeUnit){
124+
try{
125+
scheduler.shutdown();
126+
scheduler.awaitTermination(time, timeUnit);
127+
}catch(InterruptedException ex){
128+
ex.printStackTrace();
129+
}
130+
}
131+
132+
/**
133+
* Starts a {@link java.util.concurrent.ScheduledExecutorService#scheduleAtFixedRate(Runnable, long, long, TimeUnit) scheduleAtFixedRate}
134+
* task, which will post the statistics of the provided {@link org.javacord.api.DiscordApi DiscordApi instance} every n minutes.
135+
*
136+
* <p>If the post can't be performed - either by getting a {@link org.botblock.javabotblockapi.core.exceptions.RatelimitedException RateLimitedException}
137+
* or by getting an {@link java.io.IOException IOException} - will the exception be caught and a Stacktrace printed.
138+
*
139+
* <p>The scheduler will wait an initial delay of 1 minute and then performs a task every n minutes, where n is the
140+
* time set in {@link org.botblock.javabotblockapi.core.BotBlockAPI.Builder#setUpdateDelay(Integer) BotBlockAPI.Builder.setUpdateDelay(Integer)}
141+
* (default is 30 minutes).
142+
*
143+
* @param apis
144+
* The {@link org.javacord.api.DiscordApi DiscordApi instances} to post stats from.
145+
* @param botBlockAPI
146+
* The {@link org.botblock.javabotblockapi.core.BotBlockAPI BotBlockAPI instance} to use.
147+
*/
148+
public void enableAutoPost(@Nonnull BotBlockAPI botBlockAPI, @Nonnull DiscordApi... apis){
149+
scheduler.scheduleAtFixedRate(() -> {
150+
try{
151+
postGuilds(botBlockAPI, apis);
152+
}catch(IOException | RatelimitedException ex){
153+
ex.printStackTrace();
154+
}
155+
}, 1, botBlockAPI.getUpdateDelay(), TimeUnit.MINUTES);
156+
}
157+
158+
/**
159+
* Performs a POST request towards the BotBlock API using the information from the provided
160+
* {@link org.javacord.api.DiscordApi DiscordApi} and {@link org.botblock.javabotblockapi.core.BotBlockAPI BotBlock} instances.
161+
*
162+
* <p>If the provided DiscordApi instance is a sharded Bot (Amount of shards is larger than 1) will the request
163+
* contain the {@code shards} array alongside a {@code shard_count} field.
164+
*
165+
* @param apis
166+
* The {@link org.javacord.api.DiscordApi DiscordApi instances} to post stats from.
167+
* @param botBlockAPI
168+
* The {@link org.botblock.javabotblockapi.core.BotBlockAPI BotBlockAPI instance} to use.
169+
*
170+
* @throws java.io.IOException
171+
* When the POST request wasn't successful.
172+
* @throws org.botblock.javabotblockapi.core.exceptions.RatelimitedException
173+
* When we get rate limited by the BotBlock API (returns error code 429).
174+
*/
175+
public void postGuilds(@Nonnull BotBlockAPI botBlockAPI, @Nonnull DiscordApi... apis) throws IOException, RatelimitedException{
176+
JSONObject json = new JSONObject()
177+
.put("bot_id", apis[0].getYourself().getId());
178+
179+
if(apis.length > 1){
180+
int guilds = Arrays.stream(apis).map(DiscordApi::getServers).mapToInt(Collection::size).sum();
181+
json.put("server_count", guilds)
182+
.put("shard_count", apis.length);
183+
184+
List<Integer> shards = new ArrayList<>();
185+
for(DiscordApi api : apis)
186+
shards.add(api.getServers().size());
187+
188+
json.put("shards", new JSONArray(Arrays.deepToString(shards.toArray())));
189+
}else{
190+
json.put("server_count", apis[0].getServers().size());
191+
}
192+
193+
botBlockAPI.getTokens().forEach(json::put);
194+
195+
requestHandler.performPOST(json, botBlockAPI.getTokens().size());
196+
}
197+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright 2019 - 2020 Andre601
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
6+
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
7+
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8+
*
9+
* The above copyright notice and this permission notice shall be included in all copies or substantial
10+
* portions of the Software.
11+
*
12+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13+
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
14+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
15+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
16+
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17+
*/
18+
19+
/**
20+
* This is the Javacord module which is used to provide support for the Javacord Library.
21+
* <br>Make sure to install both the request library and the core library for this one to work!
22+
*
23+
* <h1>Installation</h1>
24+
* Please replace {@code API_VERSION} with the latest release on Bintray.
25+
*
26+
* <h2>Gradle (recommended)</h2>
27+
*
28+
* <pre><code>
29+
* repositories{
30+
* maven{ url = 'https://dl.bintray.com/andre601/maven' }
31+
* }
32+
*
33+
* dependencies{
34+
* // Those two are required
35+
* compile 'org.botblock:JavaBotBlockAPI-core:API_VERSION'
36+
* compile 'org.botblock:JavaBotBlockAPI-request:API_VERSION'
37+
*
38+
* compile 'org.botblock:JavaBotBlockAPI-javacord:API_VERSION'
39+
* }
40+
* </code></pre>
41+
*
42+
* <h2>Maven</h2>
43+
*
44+
* <pre><code>{@literal
45+
* <repositories>
46+
* <repository>
47+
* <id>jcenter</id>
48+
* <name>jcenter-bintray</name>
49+
* <url>https://dl.bintray.com/andre601/maven</url>
50+
* </repository>
51+
* </repositories>
52+
*
53+
* <dependencies>
54+
* <!-- Those two are required -->
55+
* <dependency>
56+
* <groupId>org.botblock</groupId>
57+
* <artifactId>JavaBotBlockAPI-core</artifactId>
58+
* <version>API_VERSION</version>
59+
* </dependency>
60+
* <dependency>
61+
* <groupId>org.botblock</groupId>
62+
* <artifactId>JavaBotBlockAPI-request</artifactId>
63+
* <version>API_VERSION</version>
64+
* </dependency>
65+
*
66+
* <dependency>
67+
* <groupId>org.botblock</groupId>
68+
* <artifactId>JavaBotBlockAPI-javacord</artifactId>
69+
* <version>API_VERSION</version>
70+
* </dependency>
71+
* </dependencies>
72+
* }</code></pre>
73+
*
74+
* <h2>Manual</h2>
75+
* We do not recommend using jar files directly and instead use one of the above dependency management systems.
76+
*
77+
* <p>If you still want to do it manually, or can't use one of the other option, head over to the
78+
* <a target="_blank" href="https://github.com/botblock/JavaBotBlockAPI/releases/latest">GitHub releases page</a> or to
79+
* the <a target="_blank" href="https://bintray.com/beta/#/andre601/maven/JavaBotBlockAPI?tab=overview">Bintray release page</a>
80+
* and download the jar files from there.
81+
*
82+
* <p>Note that you will not receive any support when using this method.
83+
*/
84+
package org.botblock.javabotblockapi.javacord;

0 commit comments

Comments
 (0)