package de.mc8051.arma3launcher.repo; import de.mc8051.arma3launcher.ArmA3Launcher; import de.mc8051.arma3launcher.interfaces.Observable; import de.mc8051.arma3launcher.interfaces.Observer; import de.mc8051.arma3launcher.objects.AbstractMod; import de.mc8051.arma3launcher.objects.Changelog; import de.mc8051.arma3launcher.objects.Mod; import de.mc8051.arma3launcher.objects.ModFile; import de.mc8051.arma3launcher.objects.Modset; import de.mc8051.arma3launcher.objects.Server; import de.mc8051.arma3launcher.utils.Callback; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.ini4j.Ini; import org.json.JSONArray; import org.json.JSONObject; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import static java.time.temporal.ChronoUnit.SECONDS; /** * Created by gurkengewuerz.de on 24.03.2020. */ public class RepositoryManger implements Observable { private static final Logger logger = LogManager.getLogger(RepositoryManger.class); private static RepositoryManger instance; public static ArrayList MOD_LIST = new ArrayList<>(); public static int MOD_LIST_SIZE = 0; private static HashMap statusMap = new HashMap<>(); private List observerList = new ArrayList<>(); private RepositoryManger() { statusMap.put(Type.METADATA, DownloadStatus.FINNISHED); statusMap.put(Type.MODSET, DownloadStatus.FINNISHED); statusMap.put(Type.CHANGELOG, DownloadStatus.FINNISHED); } public void getAsync(String urlS, Callback.HttpCallback callback) { logger.info("async http request {}", urlS); new Thread(() -> { try { URI url = new URI(urlS); HttpRequest request = HttpRequest.newBuilder() .uri(url) .GET() .headers("User-Agent", ArmA3Launcher.USER_AGENT) .timeout(Duration.of(3, SECONDS)) .build(); HttpResponse response = HttpClient.newBuilder() .followRedirects(HttpClient.Redirect.ALWAYS) .build().send(request, HttpResponse.BodyHandlers.ofString()); Response r = new Response(response); if (!r.isSuccessful()) { logger.error("Cant open {} code {}", r.request().uri(), r.getStatusCode()); return; } callback.response(r); } catch (IOException | URISyntaxException | InterruptedException e) { logger.error(e); callback.response(null); } }).start(); } public void refreshMeta() { statusMap.replace(Type.METADATA, DownloadStatus.RUNNING); RepositoryManger.getInstance().notifyObservers(Type.METADATA.toString()); getAsync(ArmA3Launcher.config.getString("sync.url") + "/.sync/server.json", new Callback.HttpCallback() { @Override public void response(Response r) { if (!r.isSuccessful()) { statusMap.replace(Type.METADATA, DownloadStatus.ERROR); RepositoryManger.getInstance().notifyObservers(Type.METADATA.toString()); return; } try { Modset.MODSET_LIST.clear(); Ini.Section section = ArmA3Launcher.user_config.get("presets"); if (section != null) { for (String key : section.keySet()) { String jsonString = section.get(key); JSONArray ja = new JSONArray(jsonString); new Modset(key, ja, Modset.Type.CLIENT); } } JSONObject jsonObject = new JSONObject(r.getBody()); if (jsonObject.has("modsets")) { JSONArray modsets = jsonObject.getJSONArray("modsets"); if (modsets.length() > 0) { for (int i = 0; i < modsets.length(); i++) { JSONObject modset = modsets.getJSONObject(i); new Modset(modset, Modset.Type.SERVER); } } } // Init servers after modsets because server search preset string in modsets if (jsonObject.has("servers")) { Server.SERVER_LIST.clear(); JSONArray servers = jsonObject.getJSONArray("servers"); if (servers.length() > 0) { for (int i = 0; i < servers.length(); i++) { JSONObject server = servers.getJSONObject(i); new Server(server); } } } statusMap.replace(Type.METADATA, DownloadStatus.FINNISHED); RepositoryManger.getInstance().notifyObservers(Type.METADATA.toString()); } catch (NullPointerException e) { logger.error(e); } } }); } public void refreshModset() { statusMap.replace(Type.MODSET, DownloadStatus.RUNNING); RepositoryManger.getInstance().notifyObservers(Type.MODSET.toString()); getAsync(ArmA3Launcher.config.getString("sync.url") + "/.sync/modset.json", new Callback.HttpCallback() { @Override public void response(Response r) { if (!r.isSuccessful()) { statusMap.replace(Type.MODSET, DownloadStatus.ERROR); RepositoryManger.getInstance().notifyObservers(Type.MODSET.toString()); return; } try { RepositoryManger.MOD_LIST.clear(); RepositoryManger.MOD_LIST_SIZE = 0; JSONObject jsonObject = new JSONObject(r.getBody()); String modPath = ArmA3Launcher.user_config.get("client", "modPath"); if(modPath == null) modPath = ""; String finalModPath = modPath; jsonObject.keySet().forEach(modname -> { Object keyvalue = jsonObject.get(modname); if (!(keyvalue instanceof JSONObject)) return; JSONObject jsonMod = (JSONObject)keyvalue; if(!jsonMod.has("size")) return; long modsize = jsonMod.getLong("size"); if(jsonMod.has("content")) { // Mod Directory JSONObject content = jsonMod.getJSONObject("content"); ArrayList modFiles = new ArrayList<>(); Iterator keys = content.keys(); while (keys.hasNext()) { String modfile = keys.next(); JSONObject jo = content.getJSONObject(modfile); long modfilesize = jo.getLong("size"); String sha1 = jo.getString("sha1"); final long lastModified = jo.getLong("lastModified"); modFiles.add(new ModFile(new File(finalModPath + File.separator + modname + File.separator + modfile), modfile, modname, modfilesize, sha1, lastModified)); RepositoryManger.MOD_LIST_SIZE++; } MOD_LIST.add(new Mod(modname, modsize, modFiles)); } else { // Single File MOD_LIST.add(new ModFile(new File(finalModPath + File.separator + modname), modname, modsize, jsonMod.getString("sha1"), jsonMod.getLong("lastModified"))); RepositoryManger.MOD_LIST_SIZE++; } }); statusMap.replace(Type.MODSET, DownloadStatus.FINNISHED); RepositoryManger.getInstance().notifyObservers(Type.MODSET.toString()); } catch (NullPointerException e) { logger.error(e); } } }); } public void refreshChangelog() { statusMap.replace(Type.CHANGELOG, DownloadStatus.RUNNING); RepositoryManger.getInstance().notifyObservers(Type.CHANGELOG.toString()); getAsync(ArmA3Launcher.config.getString("sync.url") + "/.sync/changelog.txt", new Callback.HttpCallback() { @Override public void response(Response r) { if (!r.isSuccessful()) { statusMap.replace(Type.CHANGELOG, DownloadStatus.ERROR); RepositoryManger.getInstance().notifyObservers(Type.CHANGELOG.toString()); return; } statusMap.replace(Type.CHANGELOG, DownloadStatus.FINNISHED); RepositoryManger.getInstance().notifyObservers(Type.CHANGELOG.toString()); Changelog.setChangelog(r.getBody()); } }); } public static RepositoryManger getInstance() { if (instance == null) instance = new RepositoryManger(); return instance; } public DownloadStatus getStatus(Type type) { return statusMap.get(type); } @Override public void addObserver(Observer observer) { observerList.add(observer); } @Override public void removeObserver(Observer observer) { observerList.remove(observer); } @Override public void notifyObservers(String obj) { for (Observer obs : observerList) obs.update(obj); } public enum Type { METADATA("metadata"), MODSET("modset"), CHANGELOG("changelog"); private String modset; Type(String modset) { this.modset = modset; } @Override public String toString() { return modset; } } }