Skip to content

Commit 08191a1

Browse files
committed
feat(plugins): enhance plugin loading with timeout and broken plugin tracking
Signed-off-by: 7HR4IZ3 <90985774+7HR4IZ3@users.noreply.github.com>
1 parent 62ca002 commit 08191a1

3 files changed

Lines changed: 168 additions & 108 deletions

File tree

package-lock.json

Lines changed: 16 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/acode.js

Lines changed: 115 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ import EditorFile from "lib/editorFile";
2929
import files from "lib/fileList";
3030
import fileTypeHandler from "lib/fileTypeHandler";
3131
import fonts from "lib/fonts";
32+
import {
33+
LOADED_PLUGINS,
34+
onPluginLoadCallback,
35+
onPluginsLoadCompleteCallback,
36+
} from "lib/loadPlugins";
3237
import NotificationManager from "lib/notificationManager";
3338
import openFolder, { addedFolder } from "lib/openFolder";
3439
import projects from "lib/projects";
@@ -44,7 +49,6 @@ import helpers from "utils/helpers";
4449
import KeyboardEvent from "utils/keyboardEvent";
4550
import Url from "utils/Url";
4651
import constants from "./constants";
47-
import { onPluginLoadCallback, onPluginsLoadCompleteCallback, LOADED_PLUGINS } from "lib/loadPlugins";
4852

4953
const { Fold } = ace.require("ace/edit_session/fold");
5054
const { Range } = ace.require("ace/range");
@@ -66,7 +70,23 @@ export default class Acode {
6670
},
6771
},
6872
];
69-
#pluginWatchers = {}
73+
#pluginWatchers = {};
74+
75+
/**
76+
* Clear a plugin's broken mark (so it can be retried)
77+
* @param {string} pluginId
78+
*/
79+
clearBrokenPluginMark(pluginId) {
80+
try {
81+
const broken = appSettings.value.pluginsBroken || {};
82+
if (broken[pluginId]) {
83+
delete broken[pluginId];
84+
appSettings.update(false);
85+
}
86+
} catch (e) {
87+
console.warn("Failed to clear broken plugin mark:", e);
88+
}
89+
}
7090

7191
constructor() {
7292
const encodingsModule = {
@@ -83,7 +103,7 @@ export default class Acode {
83103
list: themes.list,
84104
update: themes.update,
85105
// Deprecated, not supported anymore
86-
apply: () => { },
106+
apply: () => {},
87107
};
88108

89109
const sidebarAppsModule = {
@@ -301,101 +321,100 @@ export default class Acode {
301321
confirm(
302322
strings.install,
303323
`Do you want to install plugin '${pluginId}'${installerPluginName ? ` requested by ${installerPluginName}` : ""}?`,
304-
)
305-
.then((confirmation) => {
306-
if (!confirmation) {
307-
reject(new Error("User cancelled installation"));
308-
return;
309-
}
310-
311-
let purchaseToken;
312-
let product;
313-
const pluginUrl = Url.join(
314-
constants.API_BASE,
315-
`plugin/${pluginId}`,
316-
);
317-
fsOperation(pluginUrl)
318-
.readFile("json")
319-
.catch(() => {
320-
reject(new Error("Failed to fetch plugin details"));
321-
return null;
322-
})
323-
.then((remotePlugin) => {
324-
if (remotePlugin) {
325-
const isPaid = remotePlugin.price > 0;
326-
helpers
327-
.promisify(iap.getProducts, [remotePlugin.sku])
328-
.then((products) => {
329-
[product] = products;
330-
if (product) {
331-
return getPurchase(product.productId);
332-
}
333-
return null;
334-
})
335-
.then((purchase) => {
336-
purchaseToken = purchase?.purchaseToken;
337-
338-
if (isPaid && !purchaseToken) {
339-
if (!product) throw new Error("Product not found");
340-
return helpers.checkAPIStatus().then((apiStatus) => {
341-
if (!apiStatus) {
342-
alert(strings.error, strings.api_error);
343-
return;
344-
}
345-
346-
iap.setPurchaseUpdatedListener(
347-
...purchaseListener(onpurchase, onerror),
348-
);
349-
return helpers.promisify(
350-
iap.purchase,
351-
product.productId,
352-
);
324+
).then((confirmation) => {
325+
if (!confirmation) {
326+
reject(new Error("User cancelled installation"));
327+
return;
328+
}
329+
330+
let purchaseToken;
331+
let product;
332+
const pluginUrl = Url.join(
333+
constants.API_BASE,
334+
`plugin/${pluginId}`,
335+
);
336+
fsOperation(pluginUrl)
337+
.readFile("json")
338+
.catch(() => {
339+
reject(new Error("Failed to fetch plugin details"));
340+
return null;
341+
})
342+
.then((remotePlugin) => {
343+
if (remotePlugin) {
344+
const isPaid = remotePlugin.price > 0;
345+
helpers
346+
.promisify(iap.getProducts, [remotePlugin.sku])
347+
.then((products) => {
348+
[product] = products;
349+
if (product) {
350+
return getPurchase(product.productId);
351+
}
352+
return null;
353+
})
354+
.then((purchase) => {
355+
purchaseToken = purchase?.purchaseToken;
356+
357+
if (isPaid && !purchaseToken) {
358+
if (!product) throw new Error("Product not found");
359+
return helpers.checkAPIStatus().then((apiStatus) => {
360+
if (!apiStatus) {
361+
alert(strings.error, strings.api_error);
362+
return;
363+
}
364+
365+
iap.setPurchaseUpdatedListener(
366+
...purchaseListener(onpurchase, onerror),
367+
);
368+
return helpers.promisify(
369+
iap.purchase,
370+
product.productId,
371+
);
372+
});
373+
}
374+
})
375+
.then(() => {
376+
import("lib/installPlugin").then(
377+
({ default: installPlugin }) => {
378+
installPlugin(
379+
pluginId,
380+
remotePlugin.name,
381+
purchaseToken,
382+
).then(() => {
383+
resolve();
353384
});
354-
}
355-
})
356-
.then(() => {
357-
import("lib/installPlugin").then(
358-
({ default: installPlugin }) => {
359-
installPlugin(
360-
pluginId,
361-
remotePlugin.name,
362-
purchaseToken,
363-
).then(() => {
364-
resolve();
365-
});
366-
},
367-
);
368-
});
369-
370-
async function onpurchase(e) {
371-
const purchase = await getPurchase(product.productId);
372-
await ajax.post(
373-
Url.join(constants.API_BASE, "plugin/order"),
374-
{
375-
data: {
376-
id: remotePlugin.id,
377-
token: purchase?.purchaseToken,
378-
package: BuildInfo.packageName,
379-
},
380385
},
381386
);
382-
purchaseToken = purchase?.purchaseToken;
383-
}
387+
});
388+
389+
async function onpurchase(e) {
390+
const purchase = await getPurchase(product.productId);
391+
await ajax.post(
392+
Url.join(constants.API_BASE, "plugin/order"),
393+
{
394+
data: {
395+
id: remotePlugin.id,
396+
token: purchase?.purchaseToken,
397+
package: BuildInfo.packageName,
398+
},
399+
},
400+
);
401+
purchaseToken = purchase?.purchaseToken;
402+
}
384403

385-
async function onerror(error) {
386-
throw error;
387-
}
404+
async function onerror(error) {
405+
throw error;
388406
}
389-
});
390-
391-
async function getPurchase(sku) {
392-
const purchases = await helpers.promisify(iap.getPurchases);
393-
const purchase = purchases.find((p) =>
394-
p.productIds.includes(sku),
395-
);
396-
return purchase;
397-
}
398-
});
407+
}
408+
});
409+
410+
async function getPurchase(sku) {
411+
const purchases = await helpers.promisify(iap.getPurchases);
412+
const purchase = purchases.find((p) =>
413+
p.productIds.includes(sku),
414+
);
415+
return purchase;
416+
}
417+
});
399418
})
400419
.catch((error) => {
401420
reject(error);
@@ -423,8 +442,9 @@ export default class Acode {
423442
}
424443

425444
this.#pluginWatchers[pluginId] = {
426-
resolve, reject
427-
}
445+
resolve,
446+
reject,
447+
};
428448
});
429449
}
430450

0 commit comments

Comments
 (0)