321 lines
13 KiB
Java
321 lines
13 KiB
Java
package world.bentobox.bentobox.managers;
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.ArrayList;
|
|
import java.util.Base64;
|
|
import java.util.HashMap;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
import java.util.stream.Collectors;
|
|
|
|
import io.github.TheBusyBiscuit.GitHubWebAPI4Java.objects.users.GitHubOrganization;
|
|
import org.eclipse.jdt.annotation.NonNull;
|
|
import org.eclipse.jdt.annotation.Nullable;
|
|
|
|
import com.google.gson.JsonElement;
|
|
import com.google.gson.JsonObject;
|
|
import com.google.gson.JsonParseException;
|
|
import com.google.gson.JsonParser;
|
|
|
|
import io.github.TheBusyBiscuit.GitHubWebAPI4Java.GitHubWebAPI;
|
|
import io.github.TheBusyBiscuit.GitHubWebAPI4Java.objects.repositories.GitHubContributor;
|
|
import io.github.TheBusyBiscuit.GitHubWebAPI4Java.objects.repositories.GitHubRepository;
|
|
import world.bentobox.bentobox.BentoBox;
|
|
import world.bentobox.bentobox.Settings;
|
|
import world.bentobox.bentobox.versions.UpdateChecker;
|
|
import world.bentobox.bentobox.web.catalog.CatalogEntry;
|
|
import world.bentobox.bentobox.web.credits.Contributor;
|
|
|
|
/**
|
|
* Handles web-related stuff.
|
|
* Should be instantiated after all addons are loaded.
|
|
* @author Poslovitch
|
|
* @since 1.3.0
|
|
*/
|
|
public class WebManager {
|
|
|
|
private @NonNull final BentoBox plugin;
|
|
private @Nullable GitHubWebAPI gitHub;
|
|
private @NonNull final List<CatalogEntry> addonsCatalog;
|
|
private @NonNull final List<CatalogEntry> gamemodesCatalog;
|
|
private @NonNull final Map<String, List<Contributor>> contributors;
|
|
|
|
@NonNull
|
|
private final List<UpdateChecker> updateCheckers;
|
|
|
|
public WebManager(@NonNull BentoBox plugin) {
|
|
this.plugin = plugin;
|
|
this.addonsCatalog = new ArrayList<>();
|
|
this.gamemodesCatalog = new ArrayList<>();
|
|
this.contributors = new HashMap<>();
|
|
this.updateCheckers = new ArrayList<>();
|
|
|
|
// Setup the GitHub connection
|
|
if (plugin.getSettings().isGithubDownloadData()) {
|
|
this.gitHub = new GitHubWebAPI();
|
|
|
|
long connectionInterval = plugin.getSettings().getGithubConnectionInterval() * 20L * 60L;
|
|
if (connectionInterval <= 0) {
|
|
// If below 0, it means we shouldn't run this as a repeating task.
|
|
plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, this::requestGitHubData, 20L);
|
|
} else {
|
|
// Set connection interval to be at least 60 minutes.
|
|
connectionInterval = Math.max(connectionInterval, 60 * 20 * 60L);
|
|
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this::requestGitHubData, 20L, connectionInterval);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void requestGitHubData() {
|
|
getGitHub().ifPresent(gh -> {
|
|
if (plugin.getSettings().isLogGithubDownloadData()) {
|
|
plugin.log("Downloading data from GitHub...");
|
|
plugin.log("Updating the Catalog...");
|
|
}
|
|
GitHubRepository weblinkRepo;
|
|
try {
|
|
weblinkRepo = new GitHubRepository(gh, "BentoBoxWorld/weblink");
|
|
} catch (Exception e) {
|
|
if (plugin.getSettings().isLogGithubDownloadData()) {
|
|
plugin.logError("An unhandled exception occurred when connecting to the GitHub weblink..");
|
|
plugin.logStacktrace(e);
|
|
}
|
|
weblinkRepo = null;
|
|
}
|
|
|
|
if (weblinkRepo != null) {
|
|
// Downloading the data
|
|
String tagsContent = getContent(weblinkRepo, "catalog/tags.json");
|
|
String topicsContent = getContent(weblinkRepo, "catalog/topics.json");
|
|
String catalogContent = getContent(weblinkRepo, "catalog/catalog.json");
|
|
|
|
/* Parsing the data */
|
|
parseCatalogContent(tagsContent, topicsContent, catalogContent);
|
|
}
|
|
|
|
if (plugin.getSettings().isLogGithubDownloadData()) {
|
|
plugin.log("Updating Contributors information...");
|
|
}
|
|
|
|
List<String> repositories = new ArrayList<>();
|
|
// Gather all the repositories of installed addons and or catalog entries.
|
|
repositories.add("BentoBoxWorld/BentoBox");
|
|
repositories.addAll(plugin.getAddonsManager().getEnabledAddons()
|
|
.stream().map(addon -> addon.getDescription().getRepository())
|
|
.filter(repo -> !repo.isEmpty())
|
|
.collect(Collectors.toList()));
|
|
/*
|
|
repositories.addAll(addonsCatalog.stream().map(CatalogEntry::getRepository)
|
|
.filter(repo -> !repositories.contains(repo))
|
|
.collect(Collectors.toList()));
|
|
repositories.addAll(gamemodesCatalog.stream().map(CatalogEntry::getRepository)
|
|
.filter(repo -> !repositories.contains(repo))
|
|
.collect(Collectors.toList()));
|
|
*/
|
|
|
|
/* Download the contributors */
|
|
if (plugin.getSettings().isLogGithubDownloadData()) {
|
|
plugin.log("Gathering contribution data for: " + String.join(", ", repositories));
|
|
}
|
|
|
|
for (String repository : repositories) {
|
|
GitHubRepository repo;
|
|
try {
|
|
repo = new GitHubRepository(gh, repository);
|
|
} catch (Exception e) {
|
|
if (plugin.getSettings().isLogGithubDownloadData()) {
|
|
plugin.logError("An unhandled exception occurred when gathering contributors data from the '" + repository + "' repository...");
|
|
plugin.logStacktrace(e);
|
|
}
|
|
repo = null;
|
|
}
|
|
if (repo != null) {
|
|
gatherContributors(repo);
|
|
}
|
|
}
|
|
|
|
/* Check for updates */
|
|
if (plugin.getSettings().isLogGithubDownloadData()) {
|
|
plugin.log("Checking for updates...");
|
|
}
|
|
|
|
checkUpdates(gh);
|
|
|
|
// People were concerned that the download took ages, so we need to tell them it's over now.
|
|
if (plugin.getSettings().isLogGithubDownloadData()) {
|
|
plugin.log("Successfully downloaded data from GitHub.");
|
|
}
|
|
});
|
|
}
|
|
|
|
private void parseCatalogContent(String tagsContent, String topicsContent, String catalogContent) {
|
|
// Register the tags translations in the locales
|
|
if (!tagsContent.isEmpty()) {
|
|
try {
|
|
JsonObject tags = new JsonParser().parse(tagsContent).getAsJsonObject();
|
|
tags.entrySet().forEach(entry -> plugin.getLocalesManager().getLanguages().values().forEach(locale -> {
|
|
JsonElement translation = entry.getValue().getAsJsonObject().get(locale.toLanguageTag());
|
|
if (translation != null) {
|
|
locale.set("catalog.tags." + entry.getKey(), translation.getAsString());
|
|
}
|
|
}));
|
|
} catch (JsonParseException e) {
|
|
if (plugin.getSettings().isLogGithubDownloadData()) {
|
|
plugin.log("Could not update the Catalog Tags: the gathered JSON data is malformed.");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Register the topics translations in the locales
|
|
if (!topicsContent.isEmpty()) {
|
|
try {
|
|
JsonObject topics = new JsonParser().parse(topicsContent).getAsJsonObject();
|
|
topics.entrySet().forEach(entry -> plugin.getLocalesManager().getLanguages().values().forEach(locale -> {
|
|
JsonElement translation = entry.getValue().getAsJsonObject().get(locale.toLanguageTag());
|
|
if (translation != null) {
|
|
locale.set("catalog.topics." + entry.getKey(), translation.getAsString());
|
|
}
|
|
}));
|
|
} catch (JsonParseException e) {
|
|
if (plugin.getSettings().isLogGithubDownloadData()) {
|
|
plugin.log("Could not update the Catalog Topics: the gathered JSON data is malformed.");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Register the catalog data
|
|
if (!catalogContent.isEmpty()) {
|
|
try {
|
|
JsonObject catalog = new JsonParser().parse(catalogContent).getAsJsonObject();
|
|
|
|
this.addonsCatalog.clear();
|
|
this.gamemodesCatalog.clear();
|
|
|
|
catalog.getAsJsonArray("gamemodes").forEach(gamemode -> gamemodesCatalog.add(new CatalogEntry(gamemode.getAsJsonObject())));
|
|
catalog.getAsJsonArray("addons").forEach(addon -> addonsCatalog.add(new CatalogEntry(addon.getAsJsonObject())));
|
|
} catch (JsonParseException e) {
|
|
if (plugin.getSettings().isLogGithubDownloadData()) {
|
|
plugin.log("Could not update the Catalog content: the gathered JSON data is malformed.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param repo - Github repository
|
|
* @param fileName - file name
|
|
* @return content or nothing
|
|
* @since 1.8.0
|
|
*/
|
|
@NonNull
|
|
private String getContent(@NonNull GitHubRepository repo, String fileName) {
|
|
try {
|
|
String content = repo.getContent(fileName).getContent().replaceAll("\\n", "");
|
|
return new String(Base64.getDecoder().decode(content), StandardCharsets.UTF_8);
|
|
} catch (IllegalAccessException e) {
|
|
// Fail silently
|
|
} catch (Exception e) {
|
|
if (plugin.getSettings().isLogGithubDownloadData()) {
|
|
plugin.logError("An unhandled exception occurred when downloading '" + fileName + "' from GitHub...");
|
|
plugin.logStacktrace(e);
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
private void gatherContributors(@NonNull GitHubRepository repo) {
|
|
try {
|
|
List<Contributor> addonContributors = new LinkedList<>();
|
|
for (GitHubContributor gitHubContributor : repo.getContributors()) {
|
|
addonContributors.add(new Contributor(gitHubContributor.getUsername(), gitHubContributor.getContributionsAmount()));
|
|
}
|
|
contributors.put(repo.getFullName(), addonContributors);
|
|
} catch (IllegalAccessException e) {
|
|
// Silently fail
|
|
}
|
|
}
|
|
|
|
private void checkUpdates(@NonNull GitHubWebAPI gh) {
|
|
if (updateCheckers.isEmpty()) {
|
|
// Grab the repositories we will have to go through
|
|
Map<String, String> repositories = new HashMap<>();
|
|
|
|
if (plugin.getSettings().isCheckBentoBoxUpdates()) {
|
|
repositories.put("BentoBoxWorld/BentoBox", plugin.getDescription().getVersion());
|
|
}
|
|
if (plugin.getSettings().isCheckAddonsUpdates()) {
|
|
repositories.putAll(plugin.getAddonsManager().getEnabledAddons()
|
|
.stream()
|
|
.filter(addon -> !addon.getDescription().getRepository().isEmpty())
|
|
.collect(Collectors.toMap(addon -> addon.getDescription().getRepository(), addon -> addon.getDescription().getVersion())));
|
|
}
|
|
|
|
for (Map.Entry<String, String> repo : repositories.entrySet()) {
|
|
UpdateChecker updateChecker = new UpdateChecker(gh, repo.getKey(), repo.getValue());
|
|
updateCheckers.add(updateChecker);
|
|
}
|
|
}
|
|
|
|
for (UpdateChecker updateChecker : updateCheckers) {
|
|
try {
|
|
updateChecker.checkUpdates();
|
|
} catch (IllegalAccessException e) {
|
|
// Fail silently
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the contents of the addons catalog (may be an empty list).
|
|
* @return the contents of the addons catalog.
|
|
* @since 1.5.0
|
|
*/
|
|
@NonNull
|
|
public List<CatalogEntry> getAddonsCatalog() {
|
|
return addonsCatalog;
|
|
}
|
|
|
|
/**
|
|
* Returns the contents of the gamemodes catalog (may be an empty list).
|
|
* @return the contents of the gamemodes catalog.
|
|
* @since 1.5.0
|
|
*/
|
|
@NonNull
|
|
public List<CatalogEntry> getGamemodesCatalog() {
|
|
return gamemodesCatalog;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param repository
|
|
* @return list of contributors
|
|
* @since 1.9.0
|
|
*/
|
|
@NonNull
|
|
public List<Contributor> getContributors(String repository) {
|
|
return contributors.getOrDefault(repository, new ArrayList<>());
|
|
}
|
|
|
|
/**
|
|
* Returns an optional that may contain the {@link GitHubWebAPI} instance only and only if {@link Settings#isGithubDownloadData()} is {@code true}.
|
|
* @return the GitHub instance.
|
|
* @since 1.5.0
|
|
*/
|
|
@NonNull
|
|
public Optional<GitHubWebAPI> getGitHub() {
|
|
return Optional.ofNullable(gitHub);
|
|
}
|
|
|
|
/**
|
|
* Returns the list of update checkers.
|
|
* @return the list of update checkers.
|
|
* @since 1.14.0
|
|
*/
|
|
public List<UpdateChecker> getUpdateCheckers() {
|
|
return updateCheckers;
|
|
}
|
|
}
|