Process requests in async mode in Arch + added logs to handle bad URLs
This commit is contained in:
parent
aa52d8439f
commit
1f35e337ba
@ -2,33 +2,36 @@ package fr.packageviewer.ArchParser;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import java.net.http.*;
|
import java.net.http.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import fr.packageviewer.LoggerManager;
|
||||||
import org.json.*;
|
import org.json.*;
|
||||||
|
|
||||||
public class ArchParser {
|
public class ArchParser {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerManager.getLogger("ArchParser");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will return the String json of the package from the Arch Linux API
|
* Will return the String json of the package from the Arch Linux API
|
||||||
* @param packageName the package name to get the json from
|
* @param packageName the package name to get the json from
|
||||||
* @return json of the package
|
* @return json of the package
|
||||||
*/
|
*/
|
||||||
public String getPackageFromAPI(String packageName){
|
public CompletableFuture<HttpResponse<String>> getPackageFromAPI(String packageName) {
|
||||||
// create a new http client
|
// create a new http client
|
||||||
HttpClient client = HttpClient.newHttpClient();
|
HttpClient client = HttpClient.newHttpClient();
|
||||||
// and create its url
|
// and create its url
|
||||||
HttpRequest request = HttpRequest.newBuilder(URI.create("https://archlinux.org/packages/search/json/?name="+packageName)).build();
|
HttpRequest request = HttpRequest.newBuilder(URI.create("https://archlinux.org/packages/search/json/?name="+packageName)).build();
|
||||||
// send its url and return the string given
|
// send its url and return the string given
|
||||||
try {
|
return client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
|
||||||
return client.send(request, HttpResponse.BodyHandlers.ofString()).body();
|
|
||||||
} catch (IOException|InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
// if there's an error, return an empty string
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -79,17 +82,31 @@ public class ArchParser {
|
|||||||
* @param depth depth to search dependencies
|
* @param depth depth to search dependencies
|
||||||
* @return new Package
|
* @return new Package
|
||||||
*/
|
*/
|
||||||
public Package getPackageTree(String packageName, int depth){
|
public CompletableFuture<Package> getPackageTree(String packageName, int depth) {
|
||||||
String name, version, repo, description;
|
|
||||||
List<Package> deps = new ArrayList<>();
|
|
||||||
|
|
||||||
// parse the json
|
// parse the json
|
||||||
JSONObject json = new JSONObject(getPackageFromAPI(packageName));
|
var futurePackage = new CompletableFuture<Package>();
|
||||||
|
|
||||||
|
logger.fine("Querying package %s from API... (depth=%s)".formatted(packageName, depth));
|
||||||
|
|
||||||
|
CompletableFuture<HttpResponse<String>> futureRequest;
|
||||||
|
try{
|
||||||
|
futureRequest = getPackageFromAPI(packageName);
|
||||||
|
}catch(IllegalArgumentException e){
|
||||||
|
logger.warning("Caught exception for package %s :\n%s".formatted(packageName, e));
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
|
futureRequest.thenAccept(result->{
|
||||||
|
List<Package> deps = new ArrayList<>();
|
||||||
|
String name, version, repo, description;
|
||||||
|
|
||||||
|
JSONObject json = new JSONObject(result.body());
|
||||||
|
|
||||||
JSONArray resultsArrayJson = json.getJSONArray("results");
|
JSONArray resultsArrayJson = json.getJSONArray("results");
|
||||||
if(resultsArrayJson.length()==0){
|
if(resultsArrayJson.length()==0){
|
||||||
// unknown package, probably an abstract dependency
|
// unknown package, probably an abstract dependency
|
||||||
return null;
|
logger.fine("Completing callback INVALID for package %s (depth=%s)".formatted(packageName, depth));
|
||||||
|
futurePackage.complete(null);
|
||||||
}
|
}
|
||||||
JSONObject resultJson = json.getJSONArray("results").getJSONObject(0);
|
JSONObject resultJson = json.getJSONArray("results").getJSONObject(0);
|
||||||
|
|
||||||
@ -101,18 +118,36 @@ public class ArchParser {
|
|||||||
|
|
||||||
// if we're at the maximum depth, return the package without its dependencies
|
// if we're at the maximum depth, return the package without its dependencies
|
||||||
if(depth==0){
|
if(depth==0){
|
||||||
return new Package(name, version, repo, description, Collections.emptyList());
|
logger.fine("Completing callback NODEP for package %s (depth=%s)".formatted(packageName, depth));
|
||||||
|
futurePackage.complete(new Package(name, version, repo, description, Collections.emptyList()));
|
||||||
} else {
|
} else {
|
||||||
// iterate for every package in the list
|
// iterate for every package in the list
|
||||||
|
List<CompletableFuture<Package>> futureDeps = new ArrayList<>();
|
||||||
for (Object depPackageNameObj : resultJson.getJSONArray("depends")) {
|
for (Object depPackageNameObj : resultJson.getJSONArray("depends")) {
|
||||||
// convert object into String
|
// convert object into String
|
||||||
String depPackageName = (String) depPackageNameObj;
|
String depPackageName = (String) depPackageNameObj;
|
||||||
// add package into Package List
|
// add package into Package List
|
||||||
deps.add(getPackageTree(depPackageName, depth - 1));
|
futureDeps.add(getPackageTree(depPackageName, depth - 1));
|
||||||
|
}
|
||||||
|
for(CompletableFuture<Package> future : futureDeps){
|
||||||
|
try {
|
||||||
|
deps.add(future.get());
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this doesn't seem clean
|
// TODO this doesn't seem clean
|
||||||
return new Package(name, version, repo, description, deps);
|
logger.fine("Completing callback DEPS for package %s (depth=%s)".formatted(packageName, depth));
|
||||||
|
futurePackage.complete(new Package(name, version, repo, description, deps));
|
||||||
}
|
}
|
||||||
|
}).exceptionally((e2->{
|
||||||
|
logger.warning("Error while fetching package %s (depth=%s) from the API : \n%s".formatted(packageName, depth, e2));
|
||||||
|
e2.printStackTrace();
|
||||||
|
futurePackage.complete(null);
|
||||||
|
return null;
|
||||||
|
}));
|
||||||
|
|
||||||
|
return futurePackage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user