Magisk/app/src/main/java/com/topjohnwu/magisk/asyncs/UpdateRepos.java

217 lines
7.4 KiB
Java
Raw Normal View History

2017-02-12 12:49:46 +01:00
package com.topjohnwu.magisk.asyncs;
2017-02-12 13:53:41 +01:00
import android.content.SharedPreferences;
import android.os.AsyncTask;
2017-02-12 12:49:46 +01:00
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.ReposFragment;
2017-09-29 21:04:23 +02:00
import com.topjohnwu.magisk.container.Repo;
2017-09-30 19:28:50 +02:00
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.utils.Logger;
2017-02-12 13:53:41 +01:00
import com.topjohnwu.magisk.utils.WebService;
import org.json.JSONArray;
import org.json.JSONObject;
2017-02-12 16:26:30 +01:00
import java.io.File;
2017-09-30 19:28:50 +02:00
import java.net.HttpURLConnection;
2017-02-12 13:53:41 +01:00
import java.text.SimpleDateFormat;
2017-04-25 18:14:01 +02:00
import java.util.ArrayList;
import java.util.Arrays;
2017-02-12 13:53:41 +01:00
import java.util.Date;
import java.util.HashMap;
2017-04-25 18:14:01 +02:00
import java.util.List;
2017-02-12 13:53:41 +01:00
import java.util.Locale;
import java.util.Map;
2017-02-12 12:49:46 +01:00
public class UpdateRepos extends ParallelTask<Void, Void, Void> {
2017-02-12 12:49:46 +01:00
2017-04-25 18:14:01 +02:00
private static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&page=%d";
2017-09-30 19:28:50 +02:00
public static final String ETAG_KEY = "ETag";
2017-04-25 18:14:01 +02:00
private static final String IF_NONE_MATCH = "If-None-Match";
private static final String LINK_KEY = "Link";
2017-02-12 16:26:30 +01:00
2017-04-25 18:14:01 +02:00
private static final int CHECK_ETAG = 0;
private static final int LOAD_NEXT = 1;
private static final int LOAD_PREV = 2;
2017-09-30 19:28:50 +02:00
private List<String> cached, etags, newEtags = new ArrayList<>();
2017-04-25 18:14:01 +02:00
private RepoDatabaseHelper repoDB;
private SharedPreferences prefs;
private boolean forceUpdate;
2017-02-12 13:53:41 +01:00
private int tasks = 0;
2017-10-15 18:54:48 +02:00
public UpdateRepos(boolean force) {
MagiskManager mm = MagiskManager.get();
prefs = mm.prefs;
repoDB = mm.repoDB;
mm.repoLoadDone.hasPublished = false;
2017-02-12 16:26:30 +01:00
// Legacy data cleanup
2017-10-15 18:54:48 +02:00
File old = new File(mm.getApplicationInfo().dataDir + "/shared_prefs", "RepoMap.xml");
2017-09-30 19:28:50 +02:00
if (old.exists() || prefs.getString("repomap", null) != null) {
old.delete();
prefs.edit().remove("version").remove("repomap").remove(ETAG_KEY).apply();
2017-04-25 18:14:01 +02:00
repoDB.clearRepo();
}
forceUpdate = force;
2017-04-25 18:14:01 +02:00
}
2017-02-12 13:53:41 +01:00
2017-04-25 18:14:01 +02:00
private void loadJSON(String jsonString) throws Exception {
JSONArray jsonArray = new JSONArray(jsonString);
2017-09-30 19:28:50 +02:00
// Empty page, throw error
if (jsonArray.length() == 0) throw new Exception();
2017-04-25 18:14:01 +02:00
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonobject = jsonArray.getJSONObject(i);
String id = jsonobject.getString("description");
String name = jsonobject.getString("name");
String lastUpdate = jsonobject.getString("pushed_at");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
Date updatedDate = format.parse(lastUpdate);
++tasks;
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
Repo repo = repoDB.getRepo(id);
Boolean updated;
try {
if (repo == null) {
repo = new Repo(name, updatedDate);
updated = true;
} else {
// Popout from cached
cached.remove(id);
if (forceUpdate) {
repo.update();
updated = true;
} else {
updated = repo.update(updatedDate);
}
}
if (updated) {
repoDB.addRepo(repo);
publishProgress();
}
if (!id.equals(repo.getId())) {
Logger.error("Repo [" + name + "] id=[" + repo.getId() + "] has illegal repo id");
}
} catch (Repo.IllegalRepoException e) {
Logger.error(e.getMessage());
repoDB.removeRepo(id);
}
--tasks;
});
2017-04-25 18:14:01 +02:00
}
}
2017-09-30 19:28:50 +02:00
private boolean loadPage(int page, int mode) {
2017-02-12 16:26:30 +01:00
Map<String, String> header = new HashMap<>();
2017-09-30 19:28:50 +02:00
String etag = "";
if (mode == CHECK_ETAG && page < etags.size()) {
etag = etags.get(page);
2017-04-25 18:14:01 +02:00
}
2017-09-30 19:28:50 +02:00
header.put(IF_NONE_MATCH, etag);
String url = String.format(Locale.US, REPO_URL, page + 1);
HttpURLConnection conn = WebService.request(url, header);
2017-02-12 13:53:41 +01:00
2017-04-25 18:14:01 +02:00
try {
2017-09-30 19:28:50 +02:00
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));
2017-04-25 18:14:01 +02:00
} catch (Exception e) {
e.printStackTrace();
2017-09-30 19:28:50 +02:00
// Don't continue
return true;
2017-04-25 18:14:01 +02:00
}
2017-02-12 13:53:41 +01:00
2017-09-30 19:28:50 +02:00
// Update ETAG
etag = header.get(ETAG_KEY);
etag = etag.substring(etag.indexOf('\"'), etag.lastIndexOf('\"') + 1);
newEtags.add(etag);
2017-02-12 13:53:41 +01:00
2017-04-25 18:14:01 +02:00
String links = header.get(LINK_KEY);
if (links != null) {
2017-09-30 19:28:50 +02:00
for (String s : links.split(", ")) {
if (mode != LOAD_PREV && s.contains("next")) {
// Force load all next pages
loadPage(page + 1, LOAD_NEXT);
} else if (mode != LOAD_NEXT && s.contains("prev")) {
// Back propagation
loadPage(page - 1, LOAD_PREV);
2017-04-25 18:14:01 +02:00
}
2017-02-12 13:53:41 +01:00
}
}
2017-04-25 18:14:01 +02:00
return true;
}
private Void waitTasks() {
while (tasks > 0) {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onProgressUpdate(Void... values) {
if (ReposFragment.adapter != null)
ReposFragment.adapter.notifyDBChanged();
}
2017-04-25 18:14:01 +02:00
@Override
protected Void doInBackground(Void... voids) {
2017-09-30 19:28:50 +02:00
etags = new ArrayList<>(Arrays.asList(prefs.getString(ETAG_KEY, "").split(",")));
cached = repoDB.getRepoIDList();
2017-04-25 18:14:01 +02:00
2017-09-30 19:28:50 +02:00
if (!loadPage(0, CHECK_ETAG)) {
// Nothing changed online
if (forceUpdate) {
for (String id : cached) {
if (id == null) continue;
++tasks;
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
Repo repo = repoDB.getRepo(id);
try {
repo.update();
repoDB.addRepo(repo);
} catch (Repo.IllegalRepoException e) {
Logger.error(e.getMessage());
repoDB.removeRepo(repo);
}
--tasks;
});
}
}
return waitTasks();
2017-04-25 18:14:01 +02:00
}
// Wait till all tasks are done
waitTasks();
// The leftover cached means they are removed from online repo
2017-04-25 18:14:01 +02:00
repoDB.removeRepo(cached);
// Update ETag
StringBuilder etagBuilder = new StringBuilder();
2017-09-30 19:28:50 +02:00
for (int i = 0; i < newEtags.size(); ++i) {
2017-04-25 18:14:01 +02:00
if (i != 0) etagBuilder.append(",");
2017-09-30 19:28:50 +02:00
etagBuilder.append(newEtags.get(i));
2017-04-25 18:14:01 +02:00
}
prefs.edit().putString(ETAG_KEY, etagBuilder.toString()).apply();
2017-02-12 12:49:46 +01:00
return null;
}
@Override
protected void onPostExecute(Void v) {
2017-10-15 18:54:48 +02:00
MagiskManager.get().repoLoadDone.publish();
super.onPostExecute(v);
2017-02-12 12:49:46 +01:00
}
}