diff --git a/src/main/java/net/ornithemc/meta/data/VersionDatabase.java b/src/main/java/net/ornithemc/meta/data/VersionDatabase.java index e0d1c3a..b294ea5 100644 --- a/src/main/java/net/ornithemc/meta/data/VersionDatabase.java +++ b/src/main/java/net/ornithemc/meta/data/VersionDatabase.java @@ -29,6 +29,8 @@ import net.ornithemc.meta.utils.PomDependencyParser; import net.ornithemc.meta.utils.PomParser; import net.ornithemc.meta.utils.VersionManifest; +import net.ornithemc.meta.web.LibraryUpgradesV3; +import net.ornithemc.meta.web.LibraryUpgradesV3.LibraryUpgrade; import net.ornithemc.meta.web.models.*; import javax.xml.stream.XMLStreamException; @@ -73,6 +75,7 @@ public class VersionDatabase { public List nests; public List installer; public List osl; + public List libraryUpgrades; private VersionDatabase() { this.game = new Int2ObjectOpenHashMap<>(); this.intermediary = new Int2ObjectOpenHashMap<>(); @@ -176,6 +179,7 @@ public static VersionDatabase generate() throws IOException, XMLStreamException database.oslModules.put(module, parser.getMeta(MavenVersion::new, "net.ornithemc.osl:" + module + ":")); } + database.libraryUpgrades = LibraryUpgradesV3.get(); database.loadMcData(); OrnitheMeta.LOGGER.info("DB update took {}ms", System.currentTimeMillis() - start); return database; diff --git a/src/main/java/net/ornithemc/meta/utils/VersionManifest.java b/src/main/java/net/ornithemc/meta/utils/VersionManifest.java index beb74e9..4ade280 100644 --- a/src/main/java/net/ornithemc/meta/utils/VersionManifest.java +++ b/src/main/java/net/ornithemc/meta/utils/VersionManifest.java @@ -27,7 +27,6 @@ import java.net.URL; import java.util.HashMap; import java.util.Map; -import java.util.NoSuchElementException; public class VersionManifest { @@ -39,7 +38,7 @@ public VersionManifest() { this.versions = new HashMap<>(); } - public Semver get(String id) { + public Semver getVersion(String id) { return versions.computeIfAbsent(id, key -> { try (InputStreamReader input = new InputStreamReader(new URL(String.format(DETAILS_URL, id)).openStream())) { JsonNode details = OrnitheMeta.MAPPER.readTree(input); @@ -47,7 +46,7 @@ public Semver get(String id) { return new Semver(normalized); } catch (IOException e) { - throw new NoSuchElementException("no version with id " + id + " exists!"); + return null; } }); } diff --git a/src/main/java/net/ornithemc/meta/web/EndpointsV3.java b/src/main/java/net/ornithemc/meta/web/EndpointsV3.java index 30819af..f06a32f 100644 --- a/src/main/java/net/ornithemc/meta/web/EndpointsV3.java +++ b/src/main/java/net/ornithemc/meta/web/EndpointsV3.java @@ -23,7 +23,9 @@ import io.javalin.http.Handler; import net.ornithemc.meta.OrnitheMeta; import net.ornithemc.meta.data.VersionDatabase; +import net.ornithemc.meta.web.LibraryUpgradesV3.LibraryUpgrade; import net.ornithemc.meta.web.models.BaseVersion; +import net.ornithemc.meta.web.models.Library; import net.ornithemc.meta.web.models.LoaderInfoV3; import net.ornithemc.meta.web.models.LoaderType; import net.ornithemc.meta.web.models.MavenBuildGameVersion; @@ -71,6 +73,8 @@ public static void setup() { jsonGet("/nests", context -> withLimitSkip(context, OrnitheMeta.database.nests)); jsonGet("/nests/:game_version", context -> withLimitSkip(context, filter(context, OrnitheMeta.database.nests))); + jsonGetF("/libraries/:game_version", generation -> context -> withLimitSkip(context, getLibraries(context, generation))); + jsonGet("/fabric-loader", context -> withLimitSkip(context, OrnitheMeta.database.getLoader(LoaderType.FABRIC))); jsonGetF("/fabric-loader/:game_version", generation -> context -> withLimitSkip(context, getLoaderInfoAll(context, generation, LoaderType.FABRIC))); jsonGetF("/fabric-loader/:game_version/:loader_version", generation -> context -> getLoaderInfo(context, generation, LoaderType.FABRIC)); @@ -149,7 +153,24 @@ private static > List filter(Context context, Lis return Collections.emptyList(); } return versionList.stream().filter(t -> t.test(context.pathParam("game_version"))).collect(Collectors.toList()); + } + + private static List getLibraries(Context context, int generation) { + if (!context.pathParamMap().containsKey("game_version")) { + return null; + } + + String gameVersion = context.pathParam("game_version"); + Semver version = OrnitheMeta.database.manifest.getVersion(gameVersion); + if (version == null) { + return null; + } + + return OrnitheMeta.database.libraryUpgrades.stream() + .filter(l -> l.test(generation, gameVersion)) + .map(LibraryUpgrade::asLibrary) + .collect(Collectors.toList()); } private static Object getLoaderInfo(Context context, int generation, LoaderType type) { @@ -238,6 +259,12 @@ private static List getOslModuleInfo(Context context) { String module = context.pathParam("module"); String gameVersion = context.pathParam("game_version"); + Semver version = OrnitheMeta.database.manifest.getVersion(gameVersion); + + if (version == null) { + return null; + } + List versions = OrnitheMeta.database.getOslModule(module); if (context.pathParamMap().containsKey("base_version")) { @@ -249,11 +276,11 @@ private static List getOslModuleInfo(Context context) { } versions = versions.stream() - .filter(version -> { + .filter(v -> { String minGameVersion = null; String maxGameVersion = null; - String buildVersion = version.getVersion(); + String buildVersion = v.getVersion(); String[] parts = buildVersion.split("mc"); if (parts.length == 2) { // old format: +mc# @@ -271,11 +298,10 @@ private static List getOslModuleInfo(Context context) { } try { - Semver v = OrnitheMeta.database.manifest.get(gameVersion); - Semver vmin = OrnitheMeta.database.manifest.get(minGameVersion); - Semver vmax = OrnitheMeta.database.manifest.get(maxGameVersion); + Semver vmin = OrnitheMeta.database.manifest.getVersion(minGameVersion); + Semver vmax = OrnitheMeta.database.manifest.getVersion(maxGameVersion); - return v.compareTo(vmin) >= 0 && v.compareTo(vmax) <= 0; + return version.compareTo(vmin) >= 0 && version.compareTo(vmax) <= 0; } catch (NoSuchElementException e) { return false; } diff --git a/src/main/java/net/ornithemc/meta/web/LibraryUpgradesV3.java b/src/main/java/net/ornithemc/meta/web/LibraryUpgradesV3.java new file mode 100644 index 0000000..37d18d0 --- /dev/null +++ b/src/main/java/net/ornithemc/meta/web/LibraryUpgradesV3.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2019 FabricMC + * + * Modifications copyright (c) 2022 OrnitheMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.ornithemc.meta.web; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.vdurmont.semver4j.Semver; + +import net.ornithemc.meta.OrnitheMeta; +import net.ornithemc.meta.data.VersionDatabase; +import net.ornithemc.meta.web.models.Library; + +public class LibraryUpgradesV3 { + + private static final Path FILE_PATH = Paths.get("library-upgrades-v3.json"); + + private static List cache; + + public static List get() { + reload(); + validate(); + + return cache; + } + + private static void reload() { + if (Files.exists(FILE_PATH)) { + try (InputStream is = Files.newInputStream(FILE_PATH);) { + cache = OrnitheMeta.MAPPER.readValue(is, new TypeReference>() { }); + } catch (IOException e) { + OrnitheMeta.LOGGER.warn("unable to load library upgrades from file", e); + } + } + } + + private static void validate() { + if (cache == null) { + throw new RuntimeException("library upgrades v3 could not be read from file: file does not exist or is badly formatted"); + } + + for (LibraryUpgrade lib : cache) { + String name = lib.name; + String[] parts = name.split("[:]"); + + if (parts.length < 3 || parts.length > 4) { + throw new RuntimeException("invalid maven notation for library upgrade: " + name); + } + + Integer minGeneration = lib.minIntermediaryGeneration; + Integer maxGeneration = lib.maxIntermediaryGeneration; + + if (minGeneration != null && maxGeneration != null && minGeneration > maxGeneration) { + throw new RuntimeException("invalid intermediary generation bounds for library upgrade: " + name + " (" + minGeneration + " > " + maxGeneration + ")"); + } + + String minGameVersion = lib.minGameVersion; + String maxGameVersion = lib.maxGameVersion; + + if (minGameVersion != null && maxGameVersion != null) { + Semver min = OrnitheMeta.database.manifest.getVersion(minGameVersion); + Semver max = OrnitheMeta.database.manifest.getVersion(maxGameVersion); + + if (min == null) { + throw new RuntimeException("unknown minimum game version for library upgrade: " + name + " (" + minGameVersion + ")"); + } + if (max == null) { + throw new RuntimeException("unknown maximum game version for library upgrade: " + name + " (" + maxGameVersion + ")"); + } + + if (min.compareTo(max) > 0) { + throw new RuntimeException("invalid game version bounds for library upgrade: " + name + " (" + minGameVersion + " > " + maxGameVersion + ")"); + } + } + } + } + + public static class LibraryUpgrade { + + public String name; + public String url = VersionDatabase.MINECRAFT_LIBRARIES_URL; + + public Integer minIntermediaryGeneration; + public Integer maxIntermediaryGeneration; + public String minGameVersion; + public String maxGameVersion; + + public boolean test(int generation, String gameVersion) { + if (this.minIntermediaryGeneration != null && generation < this.minIntermediaryGeneration) { + return false; + } + if (this.maxIntermediaryGeneration != null && generation > this.maxIntermediaryGeneration) { + return false; + } + + Semver v = OrnitheMeta.database.manifest.getVersion(gameVersion); + + if (this.minGameVersion != null) { + Semver vmin = OrnitheMeta.database.manifest.getVersion(this.minGameVersion); + + if (v.compareTo(vmin) < 0) { + return false; + } + } + if (this.maxGameVersion != null) { + Semver vmax = OrnitheMeta.database.manifest.getVersion(this.maxGameVersion); + + if (v.compareTo(vmax) > 0) { + return false; + } + } + + return true; + } + + public Library asLibrary() { + return new Library(this.name, this.url); + } + } +} diff --git a/src/main/java/net/ornithemc/meta/web/ProfileHandlerV3.java b/src/main/java/net/ornithemc/meta/web/ProfileHandlerV3.java index 0dc21d0..c55f746 100644 --- a/src/main/java/net/ornithemc/meta/web/ProfileHandlerV3.java +++ b/src/main/java/net/ornithemc/meta/web/ProfileHandlerV3.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import net.ornithemc.meta.OrnitheMeta; +import net.ornithemc.meta.data.VersionDatabase; import net.ornithemc.meta.web.models.LoaderInfoV3; import net.ornithemc.meta.web.models.LoaderType; import org.apache.commons.io.IOUtils; @@ -130,7 +131,15 @@ private static JsonNode buildProfileJson(int generation, LoaderInfoV3 info, Stri info.getGame(side), generation); - ArrayNode libraries = ProfileLibraryManager.getLibraries(info, side); + JsonNode librariesNode = launcherMeta.get("libraries"); + // Build the libraries array with the existing libs + loader and intermediary + ArrayNode libraries = (ArrayNode) librariesNode.get("common"); + libraries.add(getLibrary(info.getIntermediary().getMaven(), VersionDatabase.ORNITHE_MAVEN_URL)); + libraries.add(getLibrary(info.getLoader().getMaven(), info.getLoaderType().getMavenUrl())); + + if (librariesNode.has(side)) { + libraries.addAll((ArrayNode) librariesNode.get(side)); + } String currentTime = ISO_8601.format(new Date()); @@ -168,4 +177,11 @@ private static JsonNode buildProfileJson(int generation, LoaderInfoV3 info, Stri return profile; } + + private static JsonNode getLibrary(String mavenPath, String url) { + ObjectNode objectNode = OrnitheMeta.MAPPER.createObjectNode(); + objectNode.put("name", mavenPath); + objectNode.put("url", url); + return objectNode; + } } diff --git a/src/main/java/net/ornithemc/meta/web/ProfileLibraryManager.java b/src/main/java/net/ornithemc/meta/web/ProfileLibraryManager.java deleted file mode 100644 index 93eafe3..0000000 --- a/src/main/java/net/ornithemc/meta/web/ProfileLibraryManager.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2019 FabricMC - * - * Modifications copyright (c) 2022 OrnitheMC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.ornithemc.meta.web; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.vdurmont.semver4j.Semver; -import net.ornithemc.meta.OrnitheMeta; -import net.ornithemc.meta.data.VersionDatabase; -import net.ornithemc.meta.web.models.LoaderInfoV3; - -import java.util.LinkedHashSet; -import java.util.Set; - -public class ProfileLibraryManager { - - private static final Set LIBRARIES; - - static { - LIBRARIES = new LinkedHashSet<>(); - - // the slf4j binding for log4j - this version has been tested to work on 1.6, 1.11, 1.12 - // lower versions of mc not tested because they did not yet ship log4j to begin with - LIBRARIES.add(Library.library("org.slf4j:slf4j-api:2.0.1")); - LIBRARIES.add(Library.library("org.apache.logging.log4j:log4j-slf4j2-impl:2.19.0")); - LIBRARIES.add(Library.library("org.apache.logging.log4j:log4j-api:2.19.0")); - LIBRARIES.add(Library.library("org.apache.logging.log4j:log4j-core:2.19.0")); - LIBRARIES.add(Library.library("it.unimi.dsi:fastutil:8.5.9")); - LIBRARIES.add(Library.library("com.google.code.gson:gson:2.10")); - - // logger-config is needed to make log4j work in versions prior to 13w39a - LIBRARIES.add(Library.library("net.ornithemc:logger-config:1.0.0").withUrl(VersionDatabase.ORNITHE_MAVEN_URL).upTo("1.7.0-alpha.13.38.c")); - LIBRARIES.add(Library.library("com.google.guava:guava:14.0").upTo("1.5.2")); - LIBRARIES.add(Library.library("commons-codec:commons-codec:1.9").upTo("1.7.5")); - LIBRARIES.add(Library.library("org.apache.commons:commons-compress:1.8.1").upTo("1.7.10")); - LIBRARIES.add(Library.library("commons-io:commons-io:2.4").upTo("1.5.2")); - LIBRARIES.add(Library.library("org.apache.commons:commons-lang3:3.1").upTo("1.5.2")); - LIBRARIES.add(Library.library("commons-logging:commons-logging:1.1.3").upTo("1.7.10")); - LIBRARIES.add(Library.library("org.apache.httpcomponents:httpcore:4.3.2").upTo("1.7.9")); - LIBRARIES.add(Library.library("org.apache.httpcomponents:httpclient:4.3.3").upTo("1.7.9")); - } - - public static ArrayNode getLibraries(LoaderInfoV3 info, String side) { - JsonNode launcherMeta = info.getLauncherMeta(); - - JsonNode librariesNode = launcherMeta.get("libraries"); - // Build the libraries array with the existing libs + loader and intermediary - ArrayNode libraries = (ArrayNode) librariesNode.get("common"); - libraries.add(getLibrary(info.getIntermediary().getMaven(), VersionDatabase.ORNITHE_MAVEN_URL)); - libraries.add(getLibrary(info.getLoader().getMaven(), info.getLoaderType().getMavenUrl())); - - Semver mcVersion = OrnitheMeta.database.manifest.get(info.getGame(side)); - - if (librariesNode.has(side)) { - libraries.addAll((ArrayNode) librariesNode.get(side)); - } - for (Library library : LIBRARIES) { - boolean minSatisfied = (library.minVersion == null || mcVersion.compareTo(library.minVersion) >= 0); - boolean maxSatisfied = (library.maxVersion == null || mcVersion.compareTo(library.maxVersion) <= 0); - - if (minSatisfied && maxSatisfied) { - libraries.add(getLibrary(library.name, library.url)); - } - } - - return libraries; - } - - private static JsonNode getLibrary(String mavenPath, String url) { - ObjectNode objectNode = OrnitheMeta.MAPPER.createObjectNode(); - objectNode.put("name", mavenPath); - objectNode.put("url", url); - return objectNode; - } - - private static class Library { - - private final Semver minVersion; - private final Semver maxVersion; - private final String name; - private final String url; - - private Library(Semver minVersion, Semver maxVersion, String name, String url) { - this.minVersion = minVersion; - this.maxVersion = maxVersion; - this.name = name; - this.url = url; - } - - public static Library library(String name) { - return new Library(null, null, name, VersionDatabase.MINECRAFT_LIBRARIES_URL); - } - - public Library from(String minVersion) { - return new Library(new Semver(minVersion), maxVersion, name, url); - } - - public Library upTo(String maxVersion) { - return new Library(minVersion, new Semver(maxVersion), name, url); - } - - public Library between(String minVersion, String maxVersion) { - return new Library(new Semver(minVersion), new Semver(maxVersion), name, url); - } - - public Library withUrl(String url) { - return new Library(minVersion, maxVersion, name, url); - } - } -} diff --git a/src/main/java/net/ornithemc/meta/web/models/BaseVersion.java b/src/main/java/net/ornithemc/meta/web/models/BaseVersion.java index 9a0224f..be9bdb7 100644 --- a/src/main/java/net/ornithemc/meta/web/models/BaseVersion.java +++ b/src/main/java/net/ornithemc/meta/web/models/BaseVersion.java @@ -20,10 +20,13 @@ import java.util.function.Predicate; +import com.fasterxml.jackson.annotation.JsonIgnore; + public class BaseVersion implements Predicate { String version; - transient String versionNoSide; + @JsonIgnore + String versionNoSide; boolean stable = false; public BaseVersion(String version, boolean stable) { diff --git a/src/main/java/net/ornithemc/meta/web/models/Library.java b/src/main/java/net/ornithemc/meta/web/models/Library.java new file mode 100644 index 0000000..6277c9e --- /dev/null +++ b/src/main/java/net/ornithemc/meta/web/models/Library.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019 FabricMC + * + * Modifications copyright (c) 2022 OrnitheMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.ornithemc.meta.web.models; + +public class Library { + + String name; + String url; + + public Library(String name, String url) { + this.name = name; + this.url = url; + } + + public String getName() { + return this.name; + } + + public String getUrl() { + return this.url; + } +}