Skip to content

Commit 2aa48b2

Browse files
committed
Obtain latest release version dynamically and use where appropriate
1 parent 4b20fa9 commit 2aa48b2

File tree

6 files changed

+127
-14
lines changed

6 files changed

+127
-14
lines changed

src/main/java/org/javacord/bot/Constants.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ public final class Constants {
2222
*/
2323
public static final long DAPI_JAVACORD_CHANNEL_ID = 381889796785831936L;
2424

25+
/**
26+
* The API URL where to obtain the latest release version for Javacord.
27+
*/
28+
public static final String LATEST_VERSION_URL = "https://docs.javacord.org/rest/latest-version/release";
29+
2530
private Constants() { /* nope */ }
2631

2732
}

src/main/java/org/javacord/bot/Main.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.javacord.bot.commands.SetupCommand;
1717
import org.javacord.bot.commands.WikiCommand;
1818
import org.javacord.bot.listeners.CommandCleanupListener;
19+
import org.javacord.bot.util.LatestVersionFinder;
1920

2021
import java.io.BufferedReader;
2122
import java.io.IOException;
@@ -60,15 +61,18 @@ public static void main(String[] args) throws IOException {
6061
.setWaitForServersOnStartup(false)
6162
.login().join();
6263

64+
// Tool for finding the latest version.
65+
LatestVersionFinder versionFinder = new LatestVersionFinder(api);
66+
6367
// Register commands
6468
CommandHandler handler = new JavacordHandler(api);
6569
handler.registerCommand(new DocsCommand());
6670
handler.registerCommand(new ExampleCommand());
6771
handler.registerCommand(new GitHubCommand());
68-
handler.registerCommand(new GradleCommand());
72+
handler.registerCommand(new GradleCommand(versionFinder));
6973
handler.registerCommand(new InviteCommand());
70-
handler.registerCommand(new MavenCommand());
71-
handler.registerCommand(new SetupCommand());
74+
handler.registerCommand(new MavenCommand(versionFinder));
75+
handler.registerCommand(new SetupCommand(versionFinder));
7276
handler.registerCommand(new WikiCommand());
7377
handler.registerCommand(new Sdcf4jCommand());
7478
handler.registerCommand(new InfoCommand());

src/main/java/org/javacord/bot/commands/GradleCommand.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,29 @@
22

33
import de.btobastian.sdcf4j.Command;
44
import de.btobastian.sdcf4j.CommandExecutor;
5-
import org.javacord.api.Javacord;
65
import org.javacord.api.entity.channel.TextChannel;
76
import org.javacord.api.entity.message.Message;
87
import org.javacord.api.entity.message.embed.EmbedBuilder;
98
import org.javacord.api.entity.server.Server;
109
import org.javacord.bot.Constants;
1110
import org.javacord.bot.listeners.CommandCleanupListener;
11+
import org.javacord.bot.util.LatestVersionFinder;
1212

1313
/**
1414
* The !gradle command which is used to get information about Javacord with Gradle.
1515
*/
1616
public class GradleCommand implements CommandExecutor {
1717

18+
private final LatestVersionFinder versionFinder;
19+
20+
/**
21+
* Initializes the command.
22+
* @param versionFinder The version finder to use to determine the latest javacord version.
23+
*/
24+
public GradleCommand(LatestVersionFinder versionFinder) {
25+
this.versionFinder = versionFinder;
26+
}
27+
1828
/**
1929
* Executes the {@code !gradle} command.
2030
*
@@ -29,6 +39,7 @@ public void onCommand(Server server, TextChannel channel, Message message) {
2939
return;
3040
}
3141

42+
String latestVersion = versionFinder.findLatestVersion().join();
3243
EmbedBuilder embed = new EmbedBuilder()
3344
.setColor(Constants.JAVACORD_ORANGE)
3445
.addField("Dependency",
@@ -37,8 +48,7 @@ public void onCommand(Server server, TextChannel channel, Message message) {
3748
+ " mavenCentral()\n"
3849
+ "}\n"
3950
+ "dependencies { \n"
40-
// TODO Always use the latest version
41-
+ " implementation 'org.javacord:javacord:" + Javacord.VERSION + "'\n"
51+
+ " implementation 'org.javacord:javacord:" + latestVersion + "'\n"
4252
+ "}\n"
4353
+ "```")
4454
.addField("Setup Guide", "• [IntelliJ](https://javacord.org/wiki/getting-started/intellij-gradle/)");

src/main/java/org/javacord/bot/commands/MavenCommand.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,29 @@
22

33
import de.btobastian.sdcf4j.Command;
44
import de.btobastian.sdcf4j.CommandExecutor;
5-
import org.javacord.api.Javacord;
65
import org.javacord.api.entity.channel.TextChannel;
76
import org.javacord.api.entity.message.Message;
87
import org.javacord.api.entity.message.embed.EmbedBuilder;
98
import org.javacord.api.entity.server.Server;
109
import org.javacord.bot.Constants;
1110
import org.javacord.bot.listeners.CommandCleanupListener;
11+
import org.javacord.bot.util.LatestVersionFinder;
1212

1313
/**
1414
* The !maven command which is used to get information about Javacord with Maven.
1515
*/
1616
public class MavenCommand implements CommandExecutor {
1717

18+
private final LatestVersionFinder versionFinder;
19+
20+
/**
21+
* Initializes the Command.
22+
* @param versionFinder The version finder to use to determine the latest javacord version.
23+
*/
24+
public MavenCommand(LatestVersionFinder versionFinder) {
25+
this.versionFinder = versionFinder;
26+
}
27+
1828
/**
1929
* Executes the {@code !maven} command.
2030
*
@@ -29,15 +39,15 @@ public void onCommand(Server server, TextChannel channel, Message message) {
2939
return;
3040
}
3141

42+
String latestVersion = versionFinder.findLatestVersion().join();
3243
EmbedBuilder embed = new EmbedBuilder()
3344
.setColor(Constants.JAVACORD_ORANGE)
3445
.addField("Dependency",
3546
"```xml\n"
3647
+ "<dependency>\n"
3748
+ " <groupId>org.javacord</groupId>\n"
3849
+ " <artifactId>javacord</artifactId>\n"
39-
// TODO Always use the latest version
40-
+ " <version>" + Javacord.VERSION + "</version>\n"
50+
+ " <version>" + latestVersion + "</version>\n"
4151
+ " <type>pom</type>\n"
4252
+ "</dependency>\n"
4353
+ "```")

src/main/java/org/javacord/bot/commands/SetupCommand.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,23 @@
88
import org.javacord.api.entity.server.Server;
99
import org.javacord.bot.Constants;
1010
import org.javacord.bot.listeners.CommandCleanupListener;
11+
import org.javacord.bot.util.LatestVersionFinder;
1112

1213
/**
1314
* The !setup command which is used to get information useful for first setup.
1415
*/
1516
public class SetupCommand implements CommandExecutor {
1617

18+
private final LatestVersionFinder versionFinder;
19+
20+
/**
21+
* Initializes the Command.
22+
* @param versionFinder The version finder to use to determine the latest javacord version.
23+
*/
24+
public SetupCommand(LatestVersionFinder versionFinder) {
25+
this.versionFinder = versionFinder;
26+
}
27+
1728
/**
1829
* Executes the {@code !setup} command.
1930
*
@@ -27,7 +38,7 @@ public void onCommand(Server server, TextChannel channel, Message message) {
2738
if ((server.getId() == Constants.DAPI_SERVER_ID) && (channel.getId() != Constants.DAPI_JAVACORD_CHANNEL_ID)) {
2839
return;
2940
}
30-
41+
String latestVersion = versionFinder.findLatestVersion().join();
3142
EmbedBuilder embed = new EmbedBuilder()
3243
.setColor(Constants.JAVACORD_ORANGE)
3344
.addField("Gradle Dependency",
@@ -36,17 +47,15 @@ public void onCommand(Server server, TextChannel channel, Message message) {
3647
+ " mavenCentral()\n"
3748
+ "}\n"
3849
+ "dependencies { \n"
39-
// TODO Always use the latest version
40-
+ " implementation 'org.javacord:javacord:3.0.0'\n"
50+
+ " implementation 'org.javacord:javacord:" + latestVersion + "'\n"
4151
+ "}\n"
4252
+ "```")
4353
.addField("Maven Dependency",
4454
"```xml\n"
4555
+ "<dependency>\n"
4656
+ " <groupId>org.javacord</groupId>\n"
4757
+ " <artifactId>javacord</artifactId>\n"
48-
// TODO Always use the latest version
49-
+ " <version>3.0.0</version>\n"
58+
+ " <version>" + latestVersion + "</version>\n"
5059
+ " <type>pom</type>\n"
5160
+ "</dependency>\n"
5261
+ "```")
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package org.javacord.bot.util;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import okhttp3.OkHttpClient;
6+
import okhttp3.Request;
7+
import okhttp3.ResponseBody;
8+
import org.javacord.api.DiscordApi;
9+
import org.javacord.api.util.logging.ExceptionLogger;
10+
import org.javacord.bot.Constants;
11+
12+
import java.io.IOException;
13+
import java.util.concurrent.CompletableFuture;
14+
import java.util.concurrent.ExecutorService;
15+
16+
public class LatestVersionFinder {
17+
18+
private final DiscordApi api;
19+
20+
private static final OkHttpClient client = new OkHttpClient();
21+
private static final ObjectMapper mapper = new ObjectMapper();
22+
23+
private volatile String latestVersion = "";
24+
25+
/**
26+
* Initialize the Version finder.
27+
* @param api The api object of which to obtain the Scheduler.
28+
*/
29+
public LatestVersionFinder(DiscordApi api) {
30+
this.api = api;
31+
// Populate with latest version
32+
CompletableFuture.supplyAsync(this::getAndUpdateVersionSync, api.getThreadPool().getExecutorService())
33+
.exceptionally(ExceptionLogger.get());
34+
}
35+
36+
/**
37+
* Obtain the latest release version of Javacord.
38+
*
39+
* <p>If the version cannot be obtained, the last successfully retrieved version will be used instead.
40+
*
41+
* @return The most recent release version.
42+
*/
43+
public CompletableFuture<String> findLatestVersion() {
44+
ExecutorService executorService = api.getThreadPool().getExecutorService();
45+
return CompletableFuture.supplyAsync(this::getAndUpdateVersionSync, executorService)
46+
.exceptionally(ExceptionLogger.get().andThen(value -> latestVersion));
47+
}
48+
49+
private String getAndUpdateVersionSync() {
50+
Request request = new Request.Builder()
51+
.url(Constants.LATEST_VERSION_URL)
52+
.build();
53+
try (ResponseBody body = client.newCall(request).execute().body()) {
54+
if (body == null) {
55+
throw new RuntimeException("Error while requesting the latest version: No response body.");
56+
}
57+
JsonNode response = mapper.readTree(body.charStream());
58+
// Response format is a JSON object {"version":"x.y.z"}
59+
if (!response.isObject()) {
60+
throw new AssertionError("Latest Version API result differs from expectation");
61+
}
62+
String latestVersion = response.get("version").asText();
63+
if (latestVersion == null || latestVersion.isEmpty()) {
64+
throw new AssertionError("Latest Version API result differs from expectation");
65+
}
66+
// Set cached version
67+
this.latestVersion = latestVersion;
68+
// Eventually clean up update task
69+
return latestVersion;
70+
} catch (NullPointerException | IOException e) {
71+
throw new RuntimeException("Error while requesting the latest version", e);
72+
}
73+
}
74+
75+
}

0 commit comments

Comments
 (0)