Skip to content

Commit c82100e

Browse files
committed
First steps towards Javacord support
1 parent 2dfdf24 commit c82100e

File tree

6 files changed

+246
-46
lines changed

6 files changed

+246
-46
lines changed

javacord/build.gradle

+5
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
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.javacord.api.Javacord;
26+
import org.json.JSONArray;
27+
import org.json.JSONObject;
28+
29+
import javax.annotation.Nonnull;
30+
import javax.annotation.Nullable;
31+
import java.io.IOException;
32+
import java.util.ArrayList;
33+
import java.util.Arrays;
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 api
144+
* The {@link org.javacord.api.DiscordApi DiscordApi instance} 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 DiscordApi api, @Nonnull BotBlockAPI botBlockAPI){
149+
scheduler.scheduleAtFixedRate(() -> {
150+
try{
151+
postGuilds(api, botBlockAPI);
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 api
166+
* The {@link org.javacord.api.DiscordApi DiscordApi instance} 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 DiscordApi api, @Nonnull BotBlockAPI botBlockAPI) throws IOException, RatelimitedException{
176+
JSONObject json = new JSONObject()
177+
.put("server_count", api.getServers().size())
178+
.put("bot_id", api.getYourself().getId());
179+
180+
List<Long> shards = new ArrayList<>();
181+
for(int i = 0; i < (api.getTotalShards() -1); i++)
182+
shards.add(1L);
183+
184+
json.put("shards", new JSONArray(Arrays.deepToString(shards.toArray())));
185+
botBlockAPI.getTokens().forEach(json::put);
186+
187+
requestHandler.performPOST(json, botBlockAPI.getTokens().size());
188+
}
189+
}

jda/src/main/java/org/botblock/javabotblockapi/jda/PostAction.java

+7-10
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import java.util.Arrays;
3535
import java.util.List;
3636
import java.util.Objects;
37-
import java.util.concurrent.Executors;
3837
import java.util.concurrent.ScheduledExecutorService;
3938
import java.util.concurrent.TimeUnit;
4039

@@ -51,7 +50,7 @@
5150
*/
5251
public class PostAction{
5352
private final RequestHandler requestHandler;
54-
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
53+
private final ScheduledExecutorService scheduler;
5554

5655
/**
5756
* Creates a new instance of this class.
@@ -74,12 +73,13 @@ public PostAction(@Nonnull ShardManager shardManager){
7473
* The {@link net.dv8tion.jda.api.JDA JDA instance} used to set the UserAgent.
7574
*/
7675
public PostAction(@Nonnull JDA jda){
77-
requestHandler = new RequestHandler(String.format(
76+
this.requestHandler = new RequestHandler(String.format(
7877
"%s-%s/API_VERSION (JDA) DBots/%s",
7978
jda.getSelfUser().getName(),
8079
jda.getSelfUser().getDiscriminator(),
8180
jda.getSelfUser().getId()
8281
));
82+
this.scheduler = requestHandler.getScheduler();
8383
}
8484

8585
/**
@@ -185,7 +185,7 @@ public void enableAutoPost(@Nonnull JDA jda, @Nonnull BotBlockAPI botBlockAPI){
185185
* task, which will post the statistics of the provided {@link net.dv8tion.jda.api.sharding.ShardManager ShardManager instance} every n minutes.
186186
*
187187
* <p>If the post can't be performed - either by getting a {@link org.botblock.javabotblockapi.core.exceptions.RatelimitedException RatelimitedException}
188-
* or by getting an {@link java.io.IOException IOException} - will the exception be catched and the stacktrace printed.
188+
* or by getting an {@link java.io.IOException IOException} - will the exception be caught and a Stacktrace printed.
189189
*
190190
* <p>The scheduler will wait an initial delay of 1 minute and then performs a task every n minutes, where n is the
191191
* time set in {@link org.botblock.javabotblockapi.core.BotBlockAPI.Builder#setUpdateDelay(Integer) BotBlockAPI.Builder.setUpdateDelay(Integer)}
@@ -219,7 +219,7 @@ public void enableAutoPost(@Nonnull ShardManager shardManager, @Nonnull BotBlock
219219
* The {@link org.botblock.javabotblockapi.core.BotBlockAPI BotBlockAPI instance} to use.
220220
*
221221
* @throws java.io.IOException
222-
* When the POST request wasn't successfull.
222+
* When the POST request wasn't successful.
223223
* @throws org.botblock.javabotblockapi.core.exceptions.RatelimitedException
224224
* When we get rate limited by the BotBlock API (returns error code 429).
225225
*/
@@ -239,10 +239,7 @@ public void postGuilds(@Nonnull JDA jda, @Nonnull BotBlockAPI botBlockAPI) throw
239239

240240
/**
241241
* Performs a POST request towards the BotBlock API using the information from the provided
242-
* {@link net.dv8tion.jda.api.JDA JDA} and {@link org.botblock.javabotblockapi.core.BotBlockAPI BotBlockAPI} instances.
243-
*
244-
* <p>If the provided JDA instance also is part of a sharded Bot (Amount of shards is larger than 1) will the request
245-
* also include {@code shard_id} and {@code shard_count}
242+
* {@link net.dv8tion.jda.api.sharding.ShardManager ShardManager} and {@link org.botblock.javabotblockapi.core.BotBlockAPI BotBlockAPI} instances.
246243
*
247244
* @param shardManager
248245
* The {@link net.dv8tion.jda.api.sharding.ShardManager ShardManager instance} to post stats from.
@@ -252,7 +249,7 @@ public void postGuilds(@Nonnull JDA jda, @Nonnull BotBlockAPI botBlockAPI) throw
252249
* @throws java.lang.IllegalStateException
253250
* When the first shard (id 0) of the provided ShardManager is null.
254251
* @throws java.io.IOException
255-
* When the POST request wasn't successfull.
252+
* When the POST request wasn't successful.
256253
* @throws org.botblock.javabotblockapi.core.exceptions.RatelimitedException
257254
* When we get rate limited by the BotBlock API (returns error code 429).
258255
*/

request/src/main/java/org/botblock/javabotblockapi/requests/PostAction.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import javax.annotation.Nonnull;
2828
import javax.annotation.Nullable;
2929
import java.io.IOException;
30-
import java.util.concurrent.Executors;
3130
import java.util.concurrent.ScheduledExecutorService;
3231
import java.util.concurrent.TimeUnit;
3332

@@ -40,8 +39,8 @@
4039
*/
4140
public class PostAction{
4241

43-
private final RequestHandler REQUEST_HANDLER;
44-
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
42+
private final RequestHandler requestHandler;
43+
private final ScheduledExecutorService scheduler;
4544

4645
/**
4746
* Constructor to get an instance of PostAction.
@@ -79,7 +78,8 @@ public PostAction(@Nonnull String userAgent, @Nonnull String id){
7978
CheckUtil.notEmpty(userAgent, "UserAgent");
8079
CheckUtil.notEmpty(id, "ID");
8180

82-
this.REQUEST_HANDLER = new RequestHandler(userAgent.replace("{id}", id));
81+
this.requestHandler = new RequestHandler(userAgent.replace("{id}", id));
82+
this.scheduler = requestHandler.getScheduler();
8383
}
8484

8585
/**
@@ -246,6 +246,6 @@ public void postGuilds(@Nonnull String botId, @Nonnull Integer guilds, @Nonnull
246246

247247
botBlockAPI.getTokens().forEach(json::put);
248248

249-
REQUEST_HANDLER.performPOST(json, botBlockAPI.getTokens().size());
249+
requestHandler.performPOST(json, botBlockAPI.getTokens().size());
250250
}
251251
}

request/src/main/java/org/botblock/javabotblockapi/requests/handler/RequestHandler.java

+39-31
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,16 @@
3030
import javax.annotation.Nonnull;
3131
import javax.annotation.Nullable;
3232
import java.io.IOException;
33+
import java.util.concurrent.Executors;
34+
import java.util.concurrent.ScheduledExecutorService;
3335
import java.util.concurrent.TimeUnit;
3436

3537
public class RequestHandler{
3638

37-
private final String BASE_URL = "https://botblock.org/api/";
3839
private final OkHttpClient CLIENT = new OkHttpClient();
40+
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
41+
42+
private final String BASE_URL = "https://botblock.org/api/";
3943
private final String userAgent;
4044

4145
private final Cache<String, JSONObject> botCache = Caffeine.newBuilder()
@@ -104,36 +108,6 @@ public JSONObject performGetList(@Nonnull String id, @Nullable String site, bool
104108

105109
}
106110

107-
private JSONObject performGET(@Nonnull String url, String header) throws IOException{
108-
Request request = new Request.Builder()
109-
.url(url)
110-
.addHeader("User-Agent", header)
111-
.build();
112-
113-
try(Response response = CLIENT.newCall(request).execute()){
114-
ResponseBody body = response.body();
115-
if(body == null)
116-
throw new NullPointerException("Received empty response body.");
117-
118-
String bodyString = body.string();
119-
if(bodyString.isEmpty())
120-
throw new NullPointerException("Received empty response body.");
121-
122-
if(!response.isSuccessful()){
123-
if(response.code() == 429)
124-
throw new RatelimitedException(bodyString);
125-
126-
throw new IOException(String.format(
127-
"Could not retrieve information. The server responded with error code %d (%s).",
128-
response.code(),
129-
response.message()
130-
));
131-
}
132-
133-
return new JSONObject(bodyString);
134-
}
135-
}
136-
137111
public void performPOST(@Nonnull JSONObject json, int sites) throws IOException{
138112
CheckUtil.condition(sites < 1, "The POST action requires at least 1 site!");
139113

@@ -196,6 +170,40 @@ public void performPOST(@Nonnull JSONObject json, int sites) throws IOException{
196170
}
197171
}
198172

173+
public ScheduledExecutorService getScheduler(){
174+
return scheduler;
175+
}
176+
177+
private JSONObject performGET(@Nonnull String url, String header) throws IOException{
178+
Request request = new Request.Builder()
179+
.url(url)
180+
.addHeader("User-Agent", header)
181+
.build();
182+
183+
try(Response response = CLIENT.newCall(request).execute()){
184+
ResponseBody body = response.body();
185+
if(body == null)
186+
throw new NullPointerException("Received empty response body.");
187+
188+
String bodyString = body.string();
189+
if(bodyString.isEmpty())
190+
throw new NullPointerException("Received empty response body.");
191+
192+
if(!response.isSuccessful()){
193+
if(response.code() == 429)
194+
throw new RatelimitedException(bodyString);
195+
196+
throw new IOException(String.format(
197+
"Could not retrieve information. The server responded with error code %d (%s).",
198+
response.code(),
199+
response.message()
200+
));
201+
}
202+
203+
return new JSONObject(bodyString);
204+
}
205+
}
206+
199207
JSONObject getJson(String key, JSONArray array){
200208
JSONObject json = new JSONObject()
201209
.put("code", array == null ? "?" : array.get(0))

0 commit comments

Comments
 (0)