Improve repo fetching

This commit is contained in:
topjohnwu 2017-10-01 01:28:50 +08:00
parent 35dc3d9df9
commit f6bcc84251

View File

@ -2,20 +2,19 @@ package com.topjohnwu.magisk.asyncs;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.text.TextUtils;
import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.ReposFragment; import com.topjohnwu.magisk.ReposFragment;
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.container.BaseModule; import com.topjohnwu.magisk.container.BaseModule;
import com.topjohnwu.magisk.container.Repo; import com.topjohnwu.magisk.container.Repo;
import com.topjohnwu.magisk.utils.Logger; import com.topjohnwu.magisk.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.utils.WebService; import com.topjohnwu.magisk.utils.WebService;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.File; import java.io.File;
import java.net.HttpURLConnection;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -27,9 +26,9 @@ import java.util.Map;
public class UpdateRepos extends ParallelTask<Void, Void, Void> { public class UpdateRepos extends ParallelTask<Void, Void, Void> {
public static final String ETAG_KEY = "ETag";
private static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&page=%d"; private static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&page=%d";
public static final String ETAG_KEY = "ETag";
private static final String IF_NONE_MATCH = "If-None-Match"; private static final String IF_NONE_MATCH = "If-None-Match";
private static final String LINK_KEY = "Link"; private static final String LINK_KEY = "Link";
@ -37,8 +36,7 @@ public class UpdateRepos extends ParallelTask<Void, Void, Void> {
private static final int LOAD_NEXT = 1; private static final int LOAD_NEXT = 1;
private static final int LOAD_PREV = 2; private static final int LOAD_PREV = 2;
private List<String> etags; private List<String> cached, etags, newEtags = new ArrayList<>();
private List<String> cached;
private RepoDatabaseHelper repoDB; private RepoDatabaseHelper repoDB;
private SharedPreferences prefs; private SharedPreferences prefs;
@ -47,21 +45,21 @@ public class UpdateRepos extends ParallelTask<Void, Void, Void> {
prefs = getMagiskManager().prefs; prefs = getMagiskManager().prefs;
repoDB = getMagiskManager().repoDB; repoDB = getMagiskManager().repoDB;
getMagiskManager().repoLoadDone.hasPublished = false; getMagiskManager().repoLoadDone.hasPublished = false;
String prefsPath = context.getApplicationInfo().dataDir + "/shared_prefs";
// Legacy data cleanup // Legacy data cleanup
File old = new File(prefsPath, "RepoMap.xml"); File old = new File(context.getApplicationInfo().dataDir + "/shared_prefs", "RepoMap.xml");
if (old.exists() || !prefs.getString("repomap", "empty").equals("empty")) { if (old.exists() || prefs.getString("repomap", null) != null) {
old.delete(); old.delete();
prefs.edit().remove("version").remove("repomap").remove(ETAG_KEY).apply(); prefs.edit().remove("version").remove("repomap").remove(ETAG_KEY).apply();
repoDB.clearRepo(); repoDB.clearRepo();
} }
etags = new ArrayList<>(
Arrays.asList(prefs.getString(ETAG_KEY, "").split(",")));
} }
private void loadJSON(String jsonString) throws Exception { private void loadJSON(String jsonString) throws Exception {
JSONArray jsonArray = new JSONArray(jsonString); JSONArray jsonArray = new JSONArray(jsonString);
// Empty page, throw error
if (jsonArray.length() == 0) throw new Exception();
for (int i = 0; i < jsonArray.length(); i++) { for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonobject = jsonArray.getJSONObject(i); JSONObject jsonobject = jsonArray.getJSONObject(i);
String id = jsonobject.getString("description"); String id = jsonobject.getString("description");
@ -73,7 +71,6 @@ public class UpdateRepos extends ParallelTask<Void, Void, Void> {
try { try {
Boolean updated; Boolean updated;
if (repo == null) { if (repo == null) {
Logger.dev("UpdateRepos: Create new repo " + id);
repo = new Repo(name, updatedDate); repo = new Repo(name, updatedDate);
updated = true; updated = true;
} else { } else {
@ -89,71 +86,46 @@ public class UpdateRepos extends ParallelTask<Void, Void, Void> {
} }
} }
private boolean loadPage(int page, String url, int mode) { private boolean loadPage(int page, int mode) {
Logger.dev("UpdateRepos: Loading page: " + (page + 1));
Map<String, String> header = new HashMap<>(); Map<String, String> header = new HashMap<>();
if (mode == CHECK_ETAG && page < etags.size() && !TextUtils.isEmpty(etags.get(page))) { String etag = "";
Logger.dev("ETAG: " + etags.get(page)); if (mode == CHECK_ETAG && page < etags.size()) {
header.put(IF_NONE_MATCH, etags.get(page)); etag = etags.get(page);
}
if (url == null) {
url = String.format(Locale.US, REPO_URL, page + 1);
}
String jsonString = WebService.getString(url, header);
if (TextUtils.isEmpty(jsonString)) {
// At least check the pages we know
return page + 1 < etags.size() && loadPage(page + 1, null, CHECK_ETAG);
} }
header.put(IF_NONE_MATCH, etag);
String url = String.format(Locale.US, REPO_URL, page + 1);
HttpURLConnection conn = WebService.request(url, header);
// The getString succeed, parse the new stuffs
try { try {
loadJSON(jsonString); if (conn == null) throw new Exception();
if (conn.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) {
newEtags.add(etag);
return page + 1 < etags.size() && loadPage(page + 1, CHECK_ETAG);
}
loadJSON(WebService.getString(conn));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return false; // Don't continue
return true;
} }
// Update the ETAG // Update ETAG
String newEtag = header.get(ETAG_KEY); etag = header.get(ETAG_KEY);
newEtag = newEtag.substring(newEtag.indexOf('\"'), newEtag.lastIndexOf('\"') + 1); etag = etag.substring(etag.indexOf('\"'), etag.lastIndexOf('\"') + 1);
Logger.dev("New ETAG: " + newEtag); newEtags.add(etag);
if (page < etags.size()) {
etags.set(page, newEtag);
} else {
etags.add(newEtag);
}
String links = header.get(LINK_KEY); String links = header.get(LINK_KEY);
if (links != null) { if (links != null) {
if (mode == CHECK_ETAG || mode == LOAD_NEXT) { for (String s : links.split(", ")) {
// Try to check next page URL if (mode != LOAD_PREV && s.contains("next")) {
url = null; // Force load all next pages
for (String s : links.split(", ")) { loadPage(page + 1, LOAD_NEXT);
if (s.contains("next")) { } else if (mode != LOAD_NEXT && s.contains("prev")) {
url = s.substring(s.indexOf("<") + 1, s.indexOf(">; ")); // Back propagation
break; loadPage(page - 1, LOAD_PREV);
}
}
if (url != null) {
loadPage(page + 1, url, LOAD_NEXT);
}
}
if (mode == CHECK_ETAG || mode == LOAD_PREV) {
// Try to check prev page URL
url = null;
for (String s : links.split(", ")) {
if (s.contains("prev")) {
url = s.substring(s.indexOf("<") + 1, s.indexOf(">; "));
break;
}
}
if (url != null) {
loadPage(page - 1, url, LOAD_PREV);
} }
} }
} }
return true; return true;
} }
@ -165,12 +137,11 @@ public class UpdateRepos extends ParallelTask<Void, Void, Void> {
@Override @Override
protected Void doInBackground(Void... voids) { protected Void doInBackground(Void... voids) {
Logger.dev("UpdateRepos: Loading repos"); etags = new ArrayList<>(Arrays.asList(prefs.getString(ETAG_KEY, "").split(",")));
cached = repoDB.getRepoIDList(); cached = repoDB.getRepoIDList();
if (!loadPage(0, null, CHECK_ETAG)) { if (!loadPage(0, CHECK_ETAG)) {
Logger.dev("UpdateRepos: No updates, use DB"); // Nothing changed
return null; return null;
} }
@ -179,13 +150,11 @@ public class UpdateRepos extends ParallelTask<Void, Void, Void> {
// Update ETag // Update ETag
StringBuilder etagBuilder = new StringBuilder(); StringBuilder etagBuilder = new StringBuilder();
for (int i = 0; i < etags.size(); ++i) { for (int i = 0; i < newEtags.size(); ++i) {
if (i != 0) etagBuilder.append(","); if (i != 0) etagBuilder.append(",");
etagBuilder.append(etags.get(i)); etagBuilder.append(newEtags.get(i));
} }
prefs.edit().putString(ETAG_KEY, etagBuilder.toString()).apply(); prefs.edit().putString(ETAG_KEY, etagBuilder.toString()).apply();
Logger.dev("UpdateRepos: Done");
return null; return null;
} }