Skip to content

Commit a5efce5

Browse files
Fix module repository loading
Use the working backup repository API endpoint for module JSON, surface failed HTTP responses, and load full module details when README content is missing. Keeps the browser action on the public modules.lsposed.org web page because the backup host only serves the JSON API. Builds on the approach from JingMatrix#747 by byemaxx. Co-authored-by: Qing <44231502+byemaxx@users.noreply.github.com>
1 parent cf1153e commit a5efce5

2 files changed

Lines changed: 148 additions & 56 deletions

File tree

app/src/main/java/org/lsposed/manager/repo/RepoLoader.java

Lines changed: 56 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,7 @@ public boolean upgradable(long versionCode, String versionName) {
7676
private final Path repoFile = Paths.get(App.getInstance().getFilesDir().getAbsolutePath(), "repo.json");
7777
private final Set<RepoListener> listeners = ConcurrentHashMap.newKeySet();
7878
private boolean repoLoaded = false;
79-
private static final String originRepoUrl = "https://modules.lsposed.org/";
80-
private static final String backupRepoUrl = "https://modules-blogcdn.lsposed.org/";
81-
82-
private static final String secondBackupRepoUrl = "https://modules-cloudflare.lsposed.org/";
83-
private static String repoUrl = originRepoUrl;
79+
private static final String repoUrl = "https://backup.modules.lsposed.org/";
8480
private final Resources resources = App.getInstance().getResources();
8581
private final String[] channels = resources.getStringArray(R.array.update_channel_values);
8682

@@ -98,22 +94,25 @@ public static synchronized RepoLoader getInstance() {
9894

9995
synchronized public void loadRemoteData() {
10096
repoLoaded = false;
97+
boolean loaded = false;
10198
try {
10299
try (var response = App.getOkHttpClient().newCall(new Request.Builder().url(repoUrl + "modules.json").build()).execute()) {
103-
104-
if (response.isSuccessful()) {
105-
ResponseBody body = response.body();
106-
if (body != null) {
107-
try {
108-
String bodyString = body.string();
109-
Files.write(repoFile, bodyString.getBytes(StandardCharsets.UTF_8));
110-
loadLocalData(false);
111-
} catch (Throwable t) {
112-
Log.e(App.TAG, Log.getStackTraceString(t));
113-
for (RepoListener listener : listeners) {
114-
listener.onThrowable(t);
115-
}
116-
}
100+
if (!response.isSuccessful()) {
101+
throw new IOException("Unexpected response " + response.code() + " from " + response.request().url());
102+
}
103+
ResponseBody body = response.body();
104+
if (body == null) {
105+
throw new IOException("Empty response from " + response.request().url());
106+
}
107+
try {
108+
String bodyString = body.string();
109+
Files.write(repoFile, bodyString.getBytes(StandardCharsets.UTF_8));
110+
loadLocalData(false);
111+
loaded = true;
112+
} catch (Throwable t) {
113+
Log.e(App.TAG, Log.getStackTraceString(t));
114+
for (RepoListener listener : listeners) {
115+
listener.onThrowable(t);
117116
}
118117
}
119118
}
@@ -122,12 +121,12 @@ synchronized public void loadRemoteData() {
122121
for (RepoListener listener : listeners) {
123122
listener.onThrowable(e);
124123
}
125-
if (repoUrl.equals(originRepoUrl)) {
126-
repoUrl = backupRepoUrl;
127-
loadRemoteData();
128-
} else if (repoUrl.equals(backupRepoUrl)) {
129-
repoUrl = secondBackupRepoUrl;
130-
loadRemoteData();
124+
} finally {
125+
if (!loaded) {
126+
repoLoaded = true;
127+
for (RepoListener listener : listeners) {
128+
listener.onRepoLoaded();
129+
}
131130
}
132131
}
133132
}
@@ -252,40 +251,46 @@ public void loadRemoteReleases(String packageName) {
252251
@Override
253252
public void onFailure(@NonNull Call call, @NonNull IOException e) {
254253
Log.e(App.TAG, call.request().url() + e.getMessage());
255-
if (repoUrl.equals(originRepoUrl)) {
256-
repoUrl = backupRepoUrl;
257-
loadRemoteReleases(packageName);
258-
} else if (repoUrl.equals(backupRepoUrl)) {
259-
repoUrl = secondBackupRepoUrl;
260-
loadRemoteReleases(packageName);
261-
} else {
262-
for (RepoListener listener : listeners) {
263-
listener.onThrowable(e);
264-
}
254+
for (RepoListener listener : listeners) {
255+
listener.onThrowable(e);
265256
}
266257
}
267258

268259
@Override
269260
public void onResponse(@NonNull Call call, @NonNull Response response) {
270-
if (response.isSuccessful()) {
261+
if (!response.isSuccessful()) {
262+
var e = new IOException("Unexpected response " + response.code() + " from " + call.request().url());
263+
for (RepoListener listener : listeners) {
264+
listener.onThrowable(e);
265+
}
266+
response.close();
267+
return;
268+
}
269+
try (response) {
271270
ResponseBody body = response.body();
272-
if (body != null) {
273-
try {
274-
String bodyString = body.string();
275-
Gson gson = new Gson();
276-
OnlineModule module = gson.fromJson(bodyString, OnlineModule.class);
277-
module.releasesLoaded = true;
278-
onlineModules.replace(packageName, module);
279-
for (RepoListener listener : listeners) {
280-
listener.onModuleReleasesLoaded(module);
281-
}
282-
} catch (Throwable t) {
283-
Log.e(App.TAG, Log.getStackTraceString(t));
284-
for (RepoListener listener : listeners) {
285-
listener.onThrowable(t);
286-
}
271+
if (body == null) {
272+
throw new IOException("Empty response from " + call.request().url());
273+
}
274+
try {
275+
String bodyString = body.string();
276+
Gson gson = new Gson();
277+
OnlineModule module = gson.fromJson(bodyString, OnlineModule.class);
278+
module.releasesLoaded = true;
279+
onlineModules.replace(packageName, module);
280+
for (RepoListener listener : listeners) {
281+
listener.onModuleReleasesLoaded(module);
282+
}
283+
} catch (Throwable t) {
284+
Log.e(App.TAG, Log.getStackTraceString(t));
285+
for (RepoListener listener : listeners) {
286+
listener.onThrowable(t);
287287
}
288288
}
289+
} catch (Throwable t) {
290+
Log.e(App.TAG, Log.getStackTraceString(t));
291+
for (RepoListener listener : listeners) {
292+
listener.onThrowable(t);
293+
}
289294
}
290295
}
291296
});

app/src/main/java/org/lsposed/manager/ui/fragment/RepoItemFragment.java

Lines changed: 92 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ public class RepoItemFragment extends BaseFragment implements RepoLoader.RepoLis
109109
OnlineModule module;
110110
private ReleaseAdapter releaseAdapter;
111111
private InformationAdapter informationAdapter;
112+
private boolean remoteModuleLoadRequested = false;
113+
private boolean releaseLoadRequestedByUser = false;
112114

113115
@Nullable
114116
@Override
@@ -147,6 +149,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
147149
releaseAdapter = new ReleaseAdapter();
148150
informationAdapter = new InformationAdapter();
149151
RepoLoader.getInstance().addListener(this);
152+
loadRemoteModuleIfReadmeMissing();
150153
return binding.getRoot();
151154
}
152155

@@ -184,7 +187,7 @@ private void renderGithubMarkdown(WebView view, @Nullable String text) {
184187
} else {
185188
direction = "ltr";
186189
}
187-
if (text == null) {
190+
if (TextUtils.isEmpty(text)) {
188191
text = "<center>" + App.getInstance().getString(R.string.list_empty) + "</center>";
189192
}
190193
if (ResourceUtils.isNightMode(getResources().getConfiguration())) {
@@ -238,6 +241,43 @@ public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceReque
238241
}
239242
}
240243

244+
@Nullable
245+
private OnlineModule refreshModuleFromRepo() {
246+
if (module == null || module.getName() == null) return module;
247+
var updatedModule = RepoLoader.getInstance().getOnlineModule(module.getName());
248+
if (updatedModule != null) {
249+
module = updatedModule;
250+
}
251+
return module;
252+
}
253+
254+
private boolean hasReadme(@Nullable OnlineModule module) {
255+
return module != null && (!TextUtils.isEmpty(module.getReadmeHTML()) || !TextUtils.isEmpty(module.getReadme()));
256+
}
257+
258+
private void loadRemoteModuleIfReadmeMissing() {
259+
var currentModule = refreshModuleFromRepo();
260+
if (currentModule == null || currentModule.getName() == null) return;
261+
if (remoteModuleLoadRequested || currentModule.releasesLoaded || hasReadme(currentModule)) return;
262+
263+
remoteModuleLoadRequested = true;
264+
RepoLoader.getInstance().loadRemoteReleases(currentModule.getName());
265+
}
266+
267+
@Nullable
268+
private String getModuleReadme() {
269+
var currentModule = refreshModuleFromRepo();
270+
if (currentModule == null) return null;
271+
String readme = currentModule.getReadmeHTML();
272+
if (TextUtils.isEmpty(readme)) {
273+
readme = currentModule.getReadme();
274+
}
275+
if (TextUtils.isEmpty(readme)) {
276+
loadRemoteModuleIfReadmeMissing();
277+
}
278+
return readme;
279+
}
280+
241281
@Override
242282
public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) {
243283

@@ -260,16 +300,27 @@ public void onDestroyView() {
260300
binding = null;
261301
}
262302

303+
@Override
304+
public void onRepoLoaded() {
305+
refreshModuleFromRepo();
306+
loadRemoteModuleIfReadmeMissing();
307+
if (releaseAdapter != null) {
308+
runAsync(releaseAdapter::loadItems);
309+
}
310+
}
311+
263312
@Override
264313
public void onModuleReleasesLoaded(OnlineModule module) {
314+
if (this.module == null || module == null || !TextUtils.equals(this.module.getName(), module.getName())) return;
265315
this.module = module;
266316
var repoLoader = RepoLoader.getInstance();
267317
if (releaseAdapter != null) {
268318
runAsync(releaseAdapter::loadItems);
269319
}
270-
if ((repoLoader.getReleases(module.getName()) != null ? repoLoader.getReleases(module.getName()).size() : 1) == 1) {
320+
if (releaseLoadRequestedByUser && (repoLoader.getReleases(module.getName()) != null ? repoLoader.getReleases(module.getName()).size() : 1) == 1) {
271321
showHint(R.string.module_release_no_more, true);
272322
}
323+
releaseLoadRequestedByUser = false;
273324
}
274325

275326
@Override
@@ -456,6 +507,7 @@ public void onBindViewHolder(@NonNull ReleaseAdapter.ViewHolder holder, int posi
456507
if (holder.progress.getVisibility() == View.GONE) {
457508
holder.title.setVisibility(View.GONE);
458509
holder.progress.show();
510+
releaseLoadRequestedByUser = true;
459511
RepoLoader.getInstance().loadRemoteReleases(module.getName());
460512
}
461513
});
@@ -611,9 +663,17 @@ public void onPause() {
611663
}
612664
}
613665

614-
public static class ReadmeFragment extends BorderFragment {
666+
public static class ReadmeFragment extends BorderFragment implements RepoLoader.RepoListener {
615667
ItemRepoReadmeBinding binding;
616668

669+
private void renderReadme() {
670+
var parent = getParentFragment();
671+
if (!(parent instanceof RepoItemFragment) || binding == null) return;
672+
673+
var repoItemFragment = (RepoItemFragment) parent;
674+
repoItemFragment.renderGithubMarkdown(binding.readme, repoItemFragment.getModuleReadme());
675+
}
676+
617677
@Nullable
618678
@Override
619679
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@@ -624,13 +684,40 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
624684
}
625685
return null;
626686
}
627-
var repoItemFragment = (RepoItemFragment) parent;
628687
binding = ItemRepoReadmeBinding.inflate(getLayoutInflater(), container, false);
629-
repoItemFragment.renderGithubMarkdown(binding.readme, repoItemFragment.module.getReadmeHTML());
688+
renderReadme();
630689
borderView = binding.scrollView;
690+
RepoLoader.getInstance().addListener(this);
631691
return binding.getRoot();
632692
}
633693

694+
@Override
695+
public void onRepoLoaded() {
696+
if (binding != null) {
697+
runOnUiThread(this::renderReadme);
698+
}
699+
}
700+
701+
@Override
702+
public void onModuleReleasesLoaded(OnlineModule module) {
703+
if (binding != null) {
704+
var parent = getParentFragment();
705+
if (parent instanceof RepoItemFragment) {
706+
var repoItemFragment = (RepoItemFragment) parent;
707+
if (repoItemFragment.module != null && TextUtils.equals(repoItemFragment.module.getName(), module.getName())) {
708+
runOnUiThread(this::renderReadme);
709+
}
710+
}
711+
}
712+
}
713+
714+
@Override
715+
public void onDestroyView() {
716+
RepoLoader.getInstance().removeListener(this);
717+
binding = null;
718+
super.onDestroyView();
719+
}
720+
634721
@Override
635722
void scrollToTop() {
636723
binding.scrollView.fullScroll(ScrollView.FOCUS_UP);

0 commit comments

Comments
 (0)