diff --git a/fxgl-core/src/main/kotlin/com/almasb/fxgl/core/util/ResourceExtractor.kt b/fxgl-core/src/main/kotlin/com/almasb/fxgl/core/util/ResourceExtractor.kt new file mode 100644 index 000000000..01319b844 --- /dev/null +++ b/fxgl-core/src/main/kotlin/com/almasb/fxgl/core/util/ResourceExtractor.kt @@ -0,0 +1,54 @@ +/* + * FXGL - JavaFX Game Library. The MIT License (MIT). + * Copyright (c) AlmasB (almaslvl@gmail.com). + * See LICENSE for details. + */ + +package com.almasb.fxgl.core.util + +import com.almasb.fxgl.logging.Logger +import java.net.URL +import java.nio.file.Files +import java.nio.file.Paths + +/** + * Extracts resources from the deployed jar to the local file system. + * + * @author Almas Baim (https://github.com/AlmasB) + */ +class ResourceExtractor { + + companion object { + + private val log = Logger.get(ResourceExtractor::class.java) + + /** + * Extracts the file at jar [url] as a [relativeFilePath]. + * + * @return the url on the local file system of the extracted file + */ + @JvmStatic fun extract(url: URL, relativeFilePath: String): URL { + log.debug("Extracting $url as $relativeFilePath") + + val file = Paths.get(System.getProperty("user.home")) + .resolve(".openjfx") + .resolve("cache") + .resolve("fxgl-21") + .resolve(relativeFilePath) + + val fileParentDir = file.parent + + if (Files.notExists(fileParentDir)) { + log.debug("Creating directories: $fileParentDir") + + Files.createDirectories(fileParentDir) + } + + url.openStream().use { + Files.copy(it, file) + } + + return file.toUri().toURL() + } + } +} \ No newline at end of file diff --git a/fxgl-intelligence/src/main/java/com/almasb/fxgl/intelligence/WebAPI.java b/fxgl-intelligence/src/main/java/com/almasb/fxgl/intelligence/WebAPI.java index 435703701..84b3644eb 100644 --- a/fxgl-intelligence/src/main/java/com/almasb/fxgl/intelligence/WebAPI.java +++ b/fxgl-intelligence/src/main/java/com/almasb/fxgl/intelligence/WebAPI.java @@ -6,8 +6,14 @@ package com.almasb.fxgl.intelligence; +import com.almasb.fxgl.core.util.ResourceExtractor; import com.almasb.fxgl.logging.Logger; +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * Stores constants related to web-api projects. * Changes to these values must be synchronized with the web-api project (https://github.com/AlmasB/web-api). @@ -18,7 +24,13 @@ public final class WebAPI { private static final Logger log = Logger.get(WebAPI.class); - public static final String TEXT_TO_SPEECH_API = getURL("tts/index.html"); + /** + * K - URL relative to resources/com.almasb.fxgl.intelligence in jar. + * V - absolute URL on the file system. + */ + private static final Map URLS = extractURLs(); + + public static final URL TEXT_TO_SPEECH_API = URLS.get("tts/index.html"); public static final String SPEECH_RECOGNITION_API = "https://almasb.github.io/web-api/speech-recog-v1/"; public static final String GESTURE_RECOGNITION_API = "https://almasb.github.io/web-api/gesture-recog-v1/"; @@ -26,21 +38,35 @@ public final class WebAPI { public static final int SPEECH_RECOGNITION_PORT = 55555; public static final int GESTURE_RECOGNITION_PORT = 55560; - static { - log.debug("TTS API: " + TEXT_TO_SPEECH_API + ":" + TEXT_TO_SPEECH_PORT); + private static Map extractURLs() { + var map = new HashMap(); + + List.of( + "rpc-common.js", + "tts/index.html", + "tts/script.js" + ).forEach(relativeURL -> { + map.put(relativeURL, extractURL(relativeURL, "intelligence/" + relativeURL)); + }); + + return map; } - private static String getURL(String relativeURL) { + private static URL extractURL(String relativeURL, String relateFilePath) { try { - var url = WebAPI.class.getResource(relativeURL).toExternalForm(); + var url = WebAPI.class.getResource(relativeURL); + + if (url == null) { + throw new IllegalArgumentException("URL is null: " + relativeURL); + } - if (url != null) - return url; + return ResourceExtractor.extract(url, relateFilePath); } catch (Exception e) { log.warning("Failed to get url: " + relativeURL, e); } - return "DUMMY_URL"; + // TODO: github URLs, e.g. https://raw.githubusercontent.com/AlmasB/FXGL/dev/fxgl-intelligence/src/main/resources/com/almasb/fxgl/intelligence/rpc-common.js + throw new IllegalArgumentException("Failed to extract URL: " + relativeURL); } }