Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use new download API and jar file checksum #99

Merged
merged 9 commits into from
Oct 1, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.projectg.geyserupdater.bungee.command;

import com.projectg.geyserupdater.bungee.util.GeyserBungeeDownloader;
import com.projectg.geyserupdater.common.Messages;
import com.projectg.geyserupdater.common.logger.UpdaterLogger;
import com.projectg.geyserupdater.common.util.Constants;
import com.projectg.geyserupdater.common.util.GeyserProperties;

import net.md_5.bungee.api.ChatColor;
Expand All @@ -25,32 +25,32 @@ public void execute(CommandSender commandSender, String[] args) {

if (commandSender instanceof ProxiedPlayer player) {
try {
player.sendMessage(new TextComponent(ChatColor.GOLD + "[GeyserUpdater] " + Messages.Command.CHECK_START));
player.sendMessage(new TextComponent(ChatColor.GOLD + "[GeyserUpdater] " + Constants.CHECK_START));
boolean isLatest = GeyserProperties.isLatestBuild();
if (isLatest) {
player.sendMessage(new TextComponent(ChatColor.GOLD + "[GeyserUpdater] " + Messages.Command.LATEST));
player.sendMessage(new TextComponent(ChatColor.GOLD + "[GeyserUpdater] " + Constants.LATEST));
} else {
player.sendMessage(new TextComponent(ChatColor.GOLD + "[GeyserUpdater] " + Messages.Command.OUTDATED));
player.sendMessage(new TextComponent(ChatColor.GOLD + "[GeyserUpdater] " + Constants.OUTDATED));
GeyserBungeeDownloader.updateGeyser();
}
} catch (IOException e) {
player.sendMessage(new TextComponent(ChatColor.RED + "[GeyserUpdater] " + Messages.Command.FAIL_CHECK));
logger.error(Messages.Command.FAIL_CHECK);
player.sendMessage(new TextComponent(ChatColor.RED + "[GeyserUpdater] " + Constants.FAIL_CHECK));
logger.error(Constants.FAIL_CHECK);
e.printStackTrace();
}
} else {
// TODO: filter this against command blocks
try {
logger.info(Messages.Command.CHECK_START);
logger.info(Constants.CHECK_START);
boolean isLatest = GeyserProperties.isLatestBuild();
if (isLatest) {
logger.info(Messages.Command.LATEST);
logger.info(Constants.LATEST);
} else {
logger.info(Messages.Command.OUTDATED);
logger.info(Constants.OUTDATED);
GeyserBungeeDownloader.updateGeyser();
}
} catch (IOException e) {
logger.error(Messages.Command.FAIL_CHECK);
logger.error(Constants.FAIL_CHECK);
e.printStackTrace();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import com.projectg.geyserupdater.bungee.BungeeUpdater;
import com.projectg.geyserupdater.common.logger.UpdaterLogger;
import com.projectg.geyserupdater.common.util.Constants;
import com.projectg.geyserupdater.common.util.FileUtils;
import com.projectg.geyserupdater.common.util.GeyserProperties;

import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.TextComponent;
Expand Down Expand Up @@ -58,20 +58,12 @@ public static void updateGeyser() {
* @return true if the download was successful, false if not.
*/
private static boolean downloadGeyser() {
String fileUrl;
try {
fileUrl = "https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/" + GeyserProperties.getGeyserGitPropertiesValue("git.branch") + "/lastSuccessfulBuild/artifact/bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar";
} catch (IOException e) {
logger.error("Failed to get the current Geyser branch when attempting to download a new build of Geyser!");
e.printStackTrace();
return false;
}
String fileUrl = Constants.GEYSER_BASE_URL + Constants.GEYSER_DOWNLOAD_LINK + FileUtils.Platform.BUNGEECORD.getUrlComponent();
String outputPath = "plugins/GeyserUpdater/BuildUpdate/Geyser-BungeeCord.jar";
try {
FileUtils.downloadFile(fileUrl, outputPath);
FileUtils.downloadFile(fileUrl, outputPath, FileUtils.Platform.BUNGEECORD);
} catch (IOException e) {
logger.error("Failed to download the newest build of Geyser");
e.printStackTrace();
logger.error("Failed to download the newest build of Geyser" + e.getMessage());
return false;
}
Jens-Co marked this conversation as resolved.
Show resolved Hide resolved

Expand Down
15 changes: 0 additions & 15 deletions src/main/java/com/projectg/geyserupdater/common/Messages.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.projectg.geyserupdater.common.pojo;

public class Bungeecord {
public String name;
public String sha256;
}
Jens-Co marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.projectg.geyserupdater.common.pojo;

public class Change {
public String commit;
public String summary;
public String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.projectg.geyserupdater.common.pojo;

public class Downloads {
public Bungeecord bungeecord;
public Fabric fabric;
public Spigot spigot;
public Sponge sponge;
public Standalone standalone;
public Velocity velocity;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.projectg.geyserupdater.common.pojo;

public class Fabric {
public String name;
public String sha256;
}
16 changes: 16 additions & 0 deletions src/main/java/com/projectg/geyserupdater/common/pojo/Root.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.projectg.geyserupdater.common.pojo;

import java.util.ArrayList;
import java.util.Date;

public class Root {
Jens-Co marked this conversation as resolved.
Show resolved Hide resolved
public String project_id;
public String project_name;
public String version;
public int build;
public Date time;
public String channel;
public boolean promoted;
public ArrayList<Change> changes;
Konicai marked this conversation as resolved.
Show resolved Hide resolved
public Downloads downloads;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.projectg.geyserupdater.common.pojo;

public class Spigot {
public String name;
public String sha256;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.projectg.geyserupdater.common.pojo;

public class Sponge {
public String name;
public String sha256;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.projectg.geyserupdater.common.pojo;

public class Standalone {
public String name;
public String sha256;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.projectg.geyserupdater.common.pojo;

public class Velocity {
public String name;
public String sha256;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.projectg.geyserupdater.common.util;

public class Constants {
public static final String GEYSER_BASE_URL = "https://download.geysermc.org";
public static final String GEYSER_LATEST_MASTER_ENDPOINT = "/v2/projects/geyser/versions/latest/builds/latest";
public static final String GEYSER_DOWNLOAD_LINK = "/v2/projects/geyser/versions/latest/builds/latest/downloads/";
public static final String CHECK_START = "Checking for updates to Geyser...";
public static final String LATEST = "You are using the latest build of Geyser!";
public static final String OUTDATED = "A newer build of Geyser is available! Attempting to download the latest build now...";
public static final String FAIL_CHECK = "Failed to check for updates to Geyser! We were unable to reach the Geyser build server, or your local branch does not exist on it.";
}
81 changes: 53 additions & 28 deletions src/main/java/com/projectg/geyserupdater/common/util/FileUtils.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
package com.projectg.geyserupdater.common.util;

import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
import com.google.common.io.ByteSource;
import com.projectg.geyserupdater.common.logger.UpdaterLogger;
import org.jetbrains.annotations.NotNull;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class FileUtils {
// TODO: this whole cached thing only works if you're using checkFile for one file...

/**
* Epoch time of that last occurrence that {@link #checkFile(String, boolean)} directly checked a file. Returns a value of 0 if the check file method has never been called.
Expand Down Expand Up @@ -58,33 +59,57 @@ public static boolean checkFile(String path, boolean allowCached) {
* @param fileURL the url of the file
* @param outputPath the path of the output file to write to
*/
public static void downloadFile(String fileURL, String outputPath) throws IOException {
// TODO: better download code?
public static void downloadFile(String fileURL, String outputPath, @NotNull Platform platform) throws IOException {
UpdaterLogger logger = UpdaterLogger.getLogger();
logger.debug("Attempting to download a file with URL and output path: " + fileURL + " , " + outputPath);

UpdaterLogger.getLogger().debug("Attempting to download a file with URL and output path: " + fileURL + " , " + outputPath);
// TODO: this whole cached thing only works if you're using checkFile for one file...

Path outputDirectory = Paths.get(outputPath).getParent();
Files.createDirectories(outputDirectory);

OutputStream os;
InputStream is;
// create a url object
// Download Jar file
URL url = new URL(fileURL);
// connection to the file
URLConnection connection = url.openConnection();
// get input stream to the file
is = connection.getInputStream();
// get output stream to download file
os = new FileOutputStream(outputPath);
final byte[] b = new byte[2048];
int length;
// read from input stream and write to output stream
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
ReadableByteChannel rbc = Channels.newChannel(url.openStream());
FileOutputStream fos = new FileOutputStream(outputPath);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
Jens-Co marked this conversation as resolved.
Show resolved Hide resolved
// Checking file checksum
String sha256 = null;
switch (platform) {
case SPIGOT -> sha256 = new GeyserApi().endPoints().downloads.spigot.sha256;
case BUNGEECORD -> sha256 = new GeyserApi().endPoints().downloads.bungeecord.sha256;
case VELOCITY -> sha256 = new GeyserApi().endPoints().downloads.velocity.sha256;
}
Konicai marked this conversation as resolved.
Show resolved Hide resolved
// Manually Hash the files bytecode to match hash from Geyser API
File file = new File(outputPath);
ByteSource byteSource = com.google.common.io.Files.asByteSource(file);
HashCode hc = byteSource.hash(Hashing.sha256());
String checksum = hc.toString();

if (sha256 != null && sha256.equals(checksum)) {
logger.debug("SHA256 Checksum matches!");
} else {
// If the checksum failed we delete the broken build.
if (file.delete()) {
logger.info("Please report this to KejonaMC Staff, SHA256 did not match, deleted the defective build: " + file.getName());
}
}
Konicai marked this conversation as resolved.
Show resolved Hide resolved
// close streams
is.close();
os.close();
}
}

public enum Platform {
Jens-Co marked this conversation as resolved.
Show resolved Hide resolved
SPIGOT("spigot"),
BUNGEECORD("bungeecord"),
VELOCITY("velocity");

private final String urlComponent;

Platform(String urlComponent) {
this.urlComponent = urlComponent;
}

public String getUrlComponent() {
return urlComponent;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.projectg.geyserupdater.common.util;

import com.google.gson.Gson;
import com.projectg.geyserupdater.common.pojo.Root;

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class GeyserApi {
Jens-Co marked this conversation as resolved.
Show resolved Hide resolved
public Root endPoints() {
Jens-Co marked this conversation as resolved.
Show resolved Hide resolved
try {
URL url = new URL(Constants.GEYSER_BASE_URL + Constants.GEYSER_LATEST_MASTER_ENDPOINT);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");

int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
Jens-Co marked this conversation as resolved.
Show resolved Hide resolved
Gson gson = new Gson();
Jens-Co marked this conversation as resolved.
Show resolved Hide resolved
try (InputStreamReader reader = new InputStreamReader(connection.getInputStream())) {
return gson.fromJson(reader, Root.class);
}
} else {
return null;
}
Jens-Co marked this conversation as resolved.
Show resolved Hide resolved
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@

import com.projectg.geyserupdater.common.logger.UpdaterLogger;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.util.WebUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Properties;

public class GeyserProperties {
Expand All @@ -23,12 +19,14 @@ public class GeyserProperties {
*/
public static boolean isLatestBuild() throws IOException {
UpdaterLogger.getLogger().debug("Running isLatestBuild()");
int jenkinsBuildNumber = getLatestGeyserBuildNumberFromJenkins(getGeyserGitPropertiesValue("git.branch"));
// Removed get branch since current Geyser endpoints do not yet support it
// getLatestGeyserBuildNumberFromDownloadPage(getGeyserGitPropertiesValue("git.branch"));
int downloadPageBuildNumber = getLatestGeyserBuildNumberFromDownloadPage();
int localBuildNumber = Integer.parseInt(getGeyserGitPropertiesValue("git.build.number"));
// Compare build numbers.
// We treat higher build numbers as "out of date" here because Geyser's build numbers have been (accidentally) reset in the past.
// Self-compiled builds of Geyser simply do not have a `git.build.number` value, so it is /very/ unlikely that a user will ever have a Git build number higher than upstream anyway.
return jenkinsBuildNumber == localBuildNumber;
return downloadPageBuildNumber == localBuildNumber;
}

/** Query the git properties of Geyser
Expand All @@ -44,15 +42,12 @@ public static String getGeyserGitPropertiesValue(String propertyKey) throws IOEx
return gitProperties.getProperty(propertyKey);
}

/** Get the latest build number of a given branch of Geyser from jenkins CI
/** Get the latest build number of a given branch of Geyser from Geyser download page.
*
* @param gitBranch the branch to query
* @return the latest build number
* @throws UnsupportedEncodingException if failed to encode the given gitBranch
* @return the latest build number from Geyser API
*/
public static int getLatestGeyserBuildNumberFromJenkins(String gitBranch) throws UnsupportedEncodingException {
public static int getLatestGeyserBuildNumberFromDownloadPage() {
UpdaterLogger.getLogger().debug("Running getLatestGeyserBuildNumberFromJenkins()");
String buildXMLContents = WebUtils.getBody("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/" + URLEncoder.encode(gitBranch, StandardCharsets.UTF_8.toString()) + "/lastSuccessfulBuild/api/xml?xpath=//buildNumber");
return Integer.parseInt(buildXMLContents.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim());
return new GeyserApi().endPoints().build;
}
}
Loading