Simplify threading and networking in download suggester (#1512)

* Simplify threading in download suggester
This also makes it more robust against race conditions

* Simplify network requests around app store
This commit is contained in:
altrisi authored and GitHub committed 2022-07-25 21:59:50 +02:00
1 parent c08d857821
commit 97c4cc9c7d
1 file changed
+7 -58
@@ -18,14 +18,9 @@ import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.commands.CommandRuntimeException; import net.minecraft.commands.CommandRuntimeException;
import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.CommandSourceStack;
import net.minecraft.world.level.storage.LevelResource; import net.minecraft.world.level.storage.LevelResource;
import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URL; import java.net.URL;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@@ -36,9 +31,10 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.io.IOUtils;
/** /**
* A class used to save scarpet app store scripts to disk * A class used to save scarpet app store scripts to disk
*/ */
@@ -85,7 +81,6 @@ public class AppStoreManager
public Map<String, StoreNode> children; public Map<String, StoreNode> children;
public boolean sealed; public boolean sealed;
public String value; public String value;
private CountDownLatch childrenProgress;
public static StoreNode folder(StoreNode parent, String name) public static StoreNode folder(StoreNode parent, String name)
{ {
StoreNode node = new StoreNode(parent, name); StoreNode node = new StoreNode(parent, name);
@@ -127,38 +122,23 @@ public class AppStoreManager
this.sealed = false; this.sealed = false;
} }
public void fillChildren() throws IOException public synchronized void fillChildren() throws IOException
{ {
if (sealed) return; if (sealed) return;
if (scarpetRepoLink == null) throw new IOException("Accessing scarpet app repo is disabled"); if (scarpetRepoLink == null) throw new IOException("Accessing scarpet app repo is disabled");
try
{
if (childrenProgress != null)
{
childrenProgress.await();
if (sealed) return;
else throw new IOException("Problems fetching suggestions. Check more details in previous exceptions.");
}
}
catch (InterruptedException e)
{
throw new IOException("Suggestion provider thread was interrupted, unexpected!", e);
}
childrenProgress = new CountDownLatch(1);
String queryPath = scarpetRepoLink + getPath(); String queryPath = scarpetRepoLink + getPath();
String response; String response;
try try
{ {
response = AppStoreManager.getStringFromStream(queryPath); response = IOUtils.toString(new URL(queryPath), StandardCharsets.UTF_8);
} }
catch (IOException e) catch (IOException e)
{ {
childrenProgress.countDown(); // Not sealing to allow retrying
childrenProgress = null; // Reset to allow retrying
throw new IOException("Problems fetching " + queryPath, e); throw new IOException("Problems fetching " + queryPath, e);
} }
JsonArray files = new JsonParser().parse(response).getAsJsonArray(); JsonArray files = JsonParser.parseString(response).getAsJsonArray();
for(JsonElement je : files) for(JsonElement je : files)
{ {
JsonObject jo = je.getAsJsonObject(); JsonObject jo = je.getAsJsonObject();
@@ -174,7 +154,6 @@ public class AppStoreManager
} }
} }
sealed = true; sealed = true;
childrenProgress.countDown();
} }
/** /**
@@ -265,7 +244,7 @@ public class AppStoreManager
String code; String code;
try try
{ {
code = getStringFromStream(nodeInfo.url()); code = IOUtils.toString(new URL(nodeInfo.url()), StandardCharsets.UTF_8);
} }
catch (IOException e) catch (IOException e)
{ {
@@ -350,36 +329,6 @@ public class AppStoreManager
return true; return true;
} }
/** Returns the string from the inputstream gotten from the html request.
* Thanks to App Shah in <a href="https://crunchify.com/in-java-how-to-read-github-file-contents-using-httpurlconnection-convert-stream-to-string-utility/">this post</a>
* for this code.
*
* @return the string input from the InputStream
* @throws IOException if an I/O error occurs
*/
public static String getStringFromStream(String url) throws IOException
{
InputStream inputStream = new URL(url).openStream();
if (inputStream == null)
throw new IOException("No app to be found on the appstore");
Writer stringWriter = new StringWriter();
char[] charBuffer = new char[2048];
try
{
Reader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
int counter;
while ((counter = reader.read(charBuffer)) != -1)
stringWriter.write(charBuffer, 0, counter);
}
finally
{
inputStream.close();
}
return stringWriter.toString();
}
public static void writeUrlToFile(String url, Path destination) throws IOException public static void writeUrlToFile(String url, Path destination) throws IOException
{ {
try (final InputStream in = new URL(url).openStream()) try (final InputStream in = new URL(url).openStream())