Skip to content

Commit 451b0c0

Browse files
author
埃博拉酱
committed
fix: route plugin API requests through native HTTP
Work around the plugin API CORS mismatch seen in the Android WebView. The upstream API currently responds with Access-Control-Allow-Origin: https://localhost while the app runs from http://localhost, which causes fetch-based plugin requests to fail even though the API is reachable. Add helpers.requestJson() so remote JSON requests prefer cordova-plugin-advanced-http instead of a fetch fallback. For the plugin API workload the bridge overhead is negligible compared with network latency, while the native path avoids the WebView CORS policy mismatch entirely. Update checkAPIStatus() to use the shared helper, await the async API status check in the sidebar extension panel, encode plugin search queries, and route plugin list, search, explore, and filtered requests in both plugin entry points through the shared JSON helper.
1 parent 6b24251 commit 451b0c0

File tree

3 files changed

+45
-29
lines changed

3 files changed

+45
-29
lines changed

src/pages/plugins/plugins.js

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -341,16 +341,16 @@ export default function PluginsInclude(updates) {
341341

342342
async function searchRemotely(query) {
343343
if (!query) return [];
344+
const encodedQuery = encodeURIComponent(query);
345+
const searchUrl = withSupportedEditor(
346+
`${constants.API_BASE}/plugins?name=${encodedQuery}`,
347+
);
344348
try {
345-
const response = await fetch(
346-
withSupportedEditor(`${constants.API_BASE}/plugins?name=${query}`),
347-
);
348-
const plugins = await response.json();
349+
const plugins = await helpers.requestJson(searchUrl);
349350
// Map the plugins to Item elements and return
350351
return plugins.map((plugin) => <Item {...plugin} />);
351352
} catch (error) {
352353
$list.all.setAttribute("empty-msg", strings["error"]);
353-
window.log("error", "Failed to search remotely:");
354354
window.log("error", error);
355355
return [];
356356
}
@@ -421,21 +421,20 @@ export default function PluginsInclude(updates) {
421421
if (filterState.type === "orderBy") {
422422
const page = filterState.nextPage || 1;
423423
try {
424-
let response;
424+
let items;
425425
if (filterState.value === "top_rated") {
426-
response = await fetch(
426+
items = await helpers.requestJson(
427427
withSupportedEditor(
428428
`${constants.API_BASE}/plugins?explore=random&page=${page}&limit=${LIMIT}`,
429429
),
430430
);
431431
} else {
432-
response = await fetch(
432+
items = await helpers.requestJson(
433433
withSupportedEditor(
434434
`${constants.API_BASE}/plugin?orderBy=${filterState.value}&page=${page}&limit=${LIMIT}`,
435435
),
436436
);
437437
}
438-
const items = await response.json();
439438
if (!Array.isArray(items)) {
440439
return { items: [], hasMore: false };
441440
}
@@ -470,10 +469,9 @@ export default function PluginsInclude(updates) {
470469

471470
try {
472471
const page = filterState.nextPage;
473-
const response = await fetch(
472+
const data = await helpers.requestJson(
474473
withSupportedEditor(`${constants.API_BASE}/plugins?page=${page}&limit=${LIMIT}`),
475474
);
476-
const data = await response.json();
477475
filterState.nextPage = page + 1;
478476

479477
if (!Array.isArray(data) || !data.length) {
@@ -567,10 +565,9 @@ export default function PluginsInclude(updates) {
567565

568566
$list.all.setAttribute("empty-msg", strings["loading..."]);
569567

570-
const response = await fetch(
568+
const newPlugins = await helpers.requestJson(
571569
withSupportedEditor(`${constants.API_BASE}/plugins?page=${currentPage}&limit=${LIMIT}`),
572570
);
573-
const newPlugins = await response.json();
574571

575572
if (newPlugins.length < LIMIT) {
576573
hasMore = false;

src/sidebarApps/extensions/index.js

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,11 @@ async function loadMorePlugins() {
145145
isLoading = true;
146146
startLoading($explore);
147147

148-
const response = await fetch(
148+
const newPlugins = await helpers.requestJson(
149149
withSupportedEditor(
150150
`${constants.API_BASE}/plugins?page=${currentPage}&limit=${LIMIT}`,
151151
),
152152
);
153-
const newPlugins = await response.json();
154153

155154
if (newPlugins.length < LIMIT) {
156155
hasMore = false;
@@ -218,7 +217,7 @@ async function searchPlugin() {
218217
$searchResult.onscroll = null;
219218

220219
$searchResult.content = "";
221-
const status = helpers.checkAPIStatus();
220+
const status = await helpers.checkAPIStatus();
222221
if (!status) {
223222
$searchResult.content = (
224223
<span className="error">{strings.api_error}</span>
@@ -228,14 +227,15 @@ async function searchPlugin() {
228227

229228
const query = this.value;
230229
if (!query) return;
230+
const encodedQuery = encodeURIComponent(query);
231231

232232
try {
233233
$searchResult.classList.add("loading");
234-
const plugins = await fsOperation(
234+
const plugins = await helpers.requestJson(
235235
withSupportedEditor(
236-
Url.join(constants.API_BASE, `plugins?name=${query}`),
236+
Url.join(constants.API_BASE, `plugins?name=${encodedQuery}`),
237237
),
238-
).readFile("json");
238+
);
239239

240240
installedPlugins = await listInstalledPlugins();
241241
$searchResult.content = plugins.map(ListItem);
@@ -409,7 +409,7 @@ async function loadInstalled() {
409409
async function loadExplore() {
410410
if (this.collapsed) return;
411411

412-
const status = helpers.checkAPIStatus();
412+
const status = await helpers.checkAPIStatus();
413413
if (!status) {
414414
$explore.$ul.content = <span className="error">{strings.api_error}</span>;
415415
return;
@@ -420,12 +420,11 @@ async function loadExplore() {
420420
currentPage = 1;
421421
hasMore = true;
422422

423-
const response = await fetch(
423+
const plugins = await helpers.requestJson(
424424
withSupportedEditor(
425425
`${constants.API_BASE}/plugins?page=${currentPage}&limit=${LIMIT}`,
426426
),
427427
);
428-
const plugins = await response.json();
429428

430429
if (plugins.length < LIMIT) {
431430
hasMore = false;
@@ -463,21 +462,20 @@ async function getFilteredPlugins(filterState) {
463462
if (filterState.type === "orderBy") {
464463
const page = filterState.nextPage || 1;
465464
try {
466-
let response;
465+
let items;
467466
if (filterState.value === "top_rated") {
468-
response = await fetch(
467+
items = await helpers.requestJson(
469468
withSupportedEditor(
470469
`${constants.API_BASE}/plugins?explore=random&page=${page}&limit=${LIMIT}`,
471470
),
472471
);
473472
} else {
474-
response = await fetch(
473+
items = await helpers.requestJson(
475474
withSupportedEditor(
476475
`${constants.API_BASE}/plugin?orderBy=${filterState.value}&page=${page}&limit=${LIMIT}`,
477476
),
478477
);
479478
}
480-
const items = await response.json();
481479
if (!Array.isArray(items)) {
482480
return { items: [], hasMore: false };
483481
}
@@ -512,12 +510,11 @@ async function getFilteredPlugins(filterState) {
512510

513511
try {
514512
const page = filterState.nextPage;
515-
const response = await fetch(
513+
const data = await helpers.requestJson(
516514
withSupportedEditor(
517515
`${constants.API_BASE}/plugins?page=${page}&limit=${LIMIT}`,
518516
),
519517
);
520-
const data = await response.json();
521518
filterState.nextPage = page + 1;
522519

523520
if (!Array.isArray(data) || !data.length) {

src/utils/helpers.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,9 +344,31 @@ export default {
344344
func(...args, resolve, reject);
345345
});
346346
},
347+
// Plugin API requests are all remote HTTPS calls. For this workload, the
348+
// JS-to-native bridge cost is negligible compared to network latency, so we
349+
// use native HTTP unconditionally instead of keeping a fetch fast path.
350+
// This also avoids the WebView CORS mismatch that caused false
351+
// "API unavailable" failures against the plugin API.
352+
async requestJson(url, headers = {}) {
353+
const nativeHttp = window.cordova?.plugin?.http;
354+
if (typeof nativeHttp?.get !== "function") {
355+
throw new Error("Native HTTP plugin is unavailable");
356+
}
357+
358+
const response = await new Promise((resolve, reject) => {
359+
nativeHttp.get(url, {}, headers, resolve, reject);
360+
});
361+
362+
if (typeof response?.data === "string") {
363+
return JSON.parse(response.data);
364+
}
365+
366+
return response?.data;
367+
},
347368
async checkAPIStatus() {
369+
const statusUrl = Url.join(constants.API_BASE, "status");
348370
try {
349-
const { status } = await ajax.get(Url.join(constants.API_BASE, "status"));
371+
const { status } = await this.requestJson(statusUrl);
350372
return status === "ok";
351373
} catch (error) {
352374
window.log("error", error);

0 commit comments

Comments
 (0)