fix: plugin & model catalog import cache are not cleared properly (#437)

* fix: plugin catalog cache is not wiped properly

* fix: import cache issue
This commit is contained in:
Louis 2023-10-25 01:06:37 +07:00 committed by GitHub
parent 914b4082a9
commit df5d75d1f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 97 additions and 40 deletions

View File

@ -1,2 +1,3 @@
declare const PLUGIN_NAME: string; declare const PLUGIN_NAME: string;
declare const MODULE_PATH: string; declare const MODULE_PATH: string;
declare const PLUGIN_CATALOG: string;

View File

@ -216,6 +216,9 @@ export function init({ register }: { register: RegisterExtensionPoint }) {
register(DataService.GetBotById, getBotById.name, getBotById); register(DataService.GetBotById, getBotById.name, getBotById);
register(DataService.DeleteBot, deleteBot.name, deleteBot); register(DataService.DeleteBot, deleteBot.name, deleteBot);
register(DataService.UpdateBot, updateBot.name, updateBot); register(DataService.UpdateBot, updateBot.name, updateBot);
// for plugin manifest
register(DataService.GetPluginManifest, getPluginManifest.name, getPluginManifest)
} }
function getConversations(): Promise<any> { function getConversations(): Promise<any> {
@ -323,3 +326,20 @@ function getBotById(botId: string): Promise<any> {
return Promise.reject(err); return Promise.reject(err);
}); });
} }
/**
* Retrieves the plugin manifest by importing the remote model catalog and clearing the cache to get the latest version.
* A timestamp is added to the URL to prevent caching.
* @returns A Promise that resolves with the plugin manifest.
*/
function getPluginManifest(): Promise<any> {
// Clear cache to get the latest model catalog
delete require.cache[
require.resolve(/* webpackIgnore: true */ PLUGIN_CATALOG)
];
// Import the remote model catalog
// Add a timestamp to the URL to prevent caching
return import(
/* webpackIgnore: true */ PLUGIN_CATALOG + `?t=${Date.now()}`
).then((module) => module.default);
}

View File

@ -40,8 +40,12 @@
"node_modules" "node_modules"
], ],
"dependencies": { "dependencies": {
"@janhq/core": "^0.1.6", "@janhq/core": "^0.1.7",
"pouchdb-find": "^8.0.1", "pouchdb-find": "^8.0.1",
"pouchdb-node": "^8.0.1" "pouchdb-node": "^8.0.1"
} },
"bundleDependencies": [
"pouchdb-node",
"pouchdb-find"
]
} }

View File

@ -1,7 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es2016", "target": "es2016",
"module": "ES6", "module": "esnext",
"moduleResolution": "node", "moduleResolution": "node",
"outDir": "./dist", "outDir": "./dist",
"esModuleInterop": true, "esModuleInterop": true,

View File

@ -19,6 +19,9 @@ module.exports = {
new webpack.DefinePlugin({ new webpack.DefinePlugin({
PLUGIN_NAME: JSON.stringify(packageJson.name), PLUGIN_NAME: JSON.stringify(packageJson.name),
MODULE_PATH: JSON.stringify(`${packageJson.name}/${packageJson.module}`), MODULE_PATH: JSON.stringify(`${packageJson.name}/${packageJson.module}`),
PLUGIN_CATALOG: JSON.stringify(
"https://cdn.jsdelivr.net/npm/@janhq/plugin-catalog@latest/dist/index.js"
),
}), }),
], ],
output: { output: {

View File

@ -8,19 +8,24 @@ import {
} from "@janhq/core"; } from "@janhq/core";
import { parseToModel } from "./helper"; import { parseToModel } from "./helper";
const downloadModel = (product) => downloadFile(product.downloadUrl, product.fileName); const downloadModel = (product) =>
downloadFile(product.downloadUrl, product.fileName);
const deleteModel = (path) => deleteFile(path); const deleteModel = (path) => deleteFile(path);
async function getConfiguredModels() { /**
// Clear cache to get the latest model catalog * Retrieves a list of configured models from the model catalog URL.
delete require.cache[MODEL_CATALOG_URL]; * @returns A Promise that resolves to an array of configured models.
*/
// Import the remote model catalog async function getConfiguredModels(): Promise<any> {
const module = require(MODEL_CATALOG_URL); // Add a timestamp to the URL to prevent caching
return module.default.map((e) => { return import(
return parseToModel(e); /* webpackIgnore: true */ MODEL_CATALOG_URL + `?t=${Date.now()}`
}); ).then((module) =>
module.default.map((e) => {
return parseToModel(e);
})
);
} }
/** /**
@ -44,7 +49,11 @@ function storeModel(model: any) {
* @param model Product * @param model Product
*/ */
function updateFinishedDownloadAt(_id: string): Promise<any> { function updateFinishedDownloadAt(_id: string): Promise<any> {
return store.updateMany("models", { _id }, { time: Date.now(), finishDownloadAt: 1 }); return store.updateMany(
"models",
{ _id },
{ time: Date.now(), finishDownloadAt: 1 }
);
} }
/** /**
@ -84,14 +93,38 @@ function onStart() {
export function init({ register }: { register: RegisterExtensionPoint }) { export function init({ register }: { register: RegisterExtensionPoint }) {
register(PluginService.OnStart, PLUGIN_NAME, onStart); register(PluginService.OnStart, PLUGIN_NAME, onStart);
register(ModelManagementService.DownloadModel, downloadModel.name, downloadModel); register(
ModelManagementService.DownloadModel,
downloadModel.name,
downloadModel
);
register(ModelManagementService.DeleteModel, deleteModel.name, deleteModel); register(ModelManagementService.DeleteModel, deleteModel.name, deleteModel);
register(ModelManagementService.GetConfiguredModels, getConfiguredModels.name, getConfiguredModels); register(
ModelManagementService.GetConfiguredModels,
getConfiguredModels.name,
getConfiguredModels
);
register(ModelManagementService.StoreModel, storeModel.name, storeModel); register(ModelManagementService.StoreModel, storeModel.name, storeModel);
register(ModelManagementService.UpdateFinishedDownloadAt, updateFinishedDownloadAt.name, updateFinishedDownloadAt); register(
ModelManagementService.UpdateFinishedDownloadAt,
updateFinishedDownloadAt.name,
updateFinishedDownloadAt
);
register(ModelManagementService.DeleteDownloadModel, deleteDownloadModel.name, deleteDownloadModel); register(
register(ModelManagementService.GetModelById, getModelById.name, getModelById); ModelManagementService.DeleteDownloadModel,
register(ModelManagementService.GetFinishedDownloadModels, getFinishedDownloadModels.name, getFinishedDownloadModels); deleteDownloadModel.name,
deleteDownloadModel
);
register(
ModelManagementService.GetModelById,
getModelById.name,
getModelById
);
register(
ModelManagementService.GetFinishedDownloadModels,
getFinishedDownloadModels.name,
getFinishedDownloadModels
);
} }

View File

@ -12,9 +12,10 @@ import {
import { MagnifyingGlassIcon } from '@heroicons/react/20/solid' import { MagnifyingGlassIcon } from '@heroicons/react/20/solid'
import classNames from 'classnames' import classNames from 'classnames'
import { PluginService, preferences } from '@janhq/core' import { DataService, PluginService, preferences } from '@janhq/core'
import { execute } from '../../../electron/core/plugin-manager/execution/extension-manager' import { execute } from '../../../electron/core/plugin-manager/execution/extension-manager'
import LoadingIndicator from './LoadingIndicator' import LoadingIndicator from './LoadingIndicator'
import { executeSerial } from '@services/pluginService'
export const Preferences = () => { export const Preferences = () => {
const [search, setSearch] = useState<string>('') const [search, setSearch] = useState<string>('')
@ -30,12 +31,10 @@ export const Preferences = () => {
/** /**
* Loads the plugin catalog module from a CDN and sets it as the plugin catalog state. * Loads the plugin catalog module from a CDN and sets it as the plugin catalog state.
* The `webpackIgnore` comment is used to prevent Webpack from bundling the module.
*/ */
useEffect(() => { useEffect(() => {
// @ts-ignore executeSerial(DataService.GetPluginManifest).then((data) => {
import(/* webpackIgnore: true */ PLUGIN_CATALOGS).then((module) => { setPluginCatalog(data)
setPluginCatalog(module.default)
}) })
}, []) }, [])

View File

@ -1,5 +1,6 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { executeSerial } from '../../electron/core/plugin-manager/execution/extension-manager' import { executeSerial } from '../../electron/core/plugin-manager/execution/extension-manager'
import { extensionPoints } from '../../electron/core/plugin-manager/execution'
import { SystemMonitoringService } from '@janhq/core' import { SystemMonitoringService } from '@janhq/core'
import { useSetAtom } from 'jotai' import { useSetAtom } from 'jotai'
import { totalRamAtom } from '@helpers/atoms/SystemBar.atom' import { totalRamAtom } from '@helpers/atoms/SystemBar.atom'
@ -9,6 +10,9 @@ export default function useGetSystemResources() {
const setTotalRam = useSetAtom(totalRamAtom) const setTotalRam = useSetAtom(totalRamAtom)
const getSystemResources = async () => { const getSystemResources = async () => {
if (!extensionPoints.get(SystemMonitoringService.GetResourcesInfo)) {
return
}
const resourceInfor = await executeSerial( const resourceInfor = await executeSerial(
SystemMonitoringService.GetResourcesInfo SystemMonitoringService.GetResourcesInfo
) )

View File

@ -21,14 +21,7 @@ const nextConfig = {
// do some stuff here // do some stuff here
config.optimization.minimize = false config.optimization.minimize = false
config.optimization.minimizer = [] config.optimization.minimizer = []
config.plugins = [ config.plugins = [...config.plugins, new webpack.DefinePlugin({})]
...config.plugins,
new webpack.DefinePlugin({
PLUGIN_CATALOGS: JSON.stringify(
'https://cdn.jsdelivr.net/npm/@janhq/plugin-catalog@latest/dist/index.js'
),
}),
]
return config return config
}, },
} }

View File

@ -14,7 +14,7 @@
"dependencies": { "dependencies": {
"@headlessui/react": "^1.7.15", "@headlessui/react": "^1.7.15",
"@heroicons/react": "^2.0.18", "@heroicons/react": "^2.0.18",
"@janhq/core": "^0.1.6", "@janhq/core": "^0.1.7",
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-toggle": "^1.0.3", "@radix-ui/react-toggle": "^1.0.3",

View File

@ -9,6 +9,8 @@ import {
plugins, plugins,
extensionPoints, extensionPoints,
} from '@/../../electron/core/plugin-manager/execution/index' } from '@/../../electron/core/plugin-manager/execution/index'
import { executeSerial } from '@services/pluginService'
import { DataService } from '@janhq/core'
const PluginCatalog = () => { const PluginCatalog = () => {
// const [search, setSearch] = useState<string>('') // const [search, setSearch] = useState<string>('')
@ -20,12 +22,10 @@ const PluginCatalog = () => {
/** /**
* Loads the plugin catalog module from a CDN and sets it as the plugin catalog state. * Loads the plugin catalog module from a CDN and sets it as the plugin catalog state.
* The `webpackIgnore` comment is used to prevent Webpack from bundling the module.
*/ */
useEffect(() => { useEffect(() => {
// @ts-ignore executeSerial(DataService.GetPluginManifest).then((data) => {
import(/* webpackIgnore: true */ PLUGIN_CATALOGS).then((module) => { setPluginCatalog(data)
setPluginCatalog(module.default)
}) })
}, []) }, [])
@ -127,7 +127,7 @@ const PluginCatalog = () => {
return ( return (
<div className="block w-full"> <div className="block w-full">
{pluginCatalog.map((item, i) => { {pluginCatalog?.map((item, i) => {
const isActivePlugin = activePlugins.some((x) => x.name === item.name) const isActivePlugin = activePlugins.some((x) => x.name === item.name)
const updateVersionPlugins = Number( const updateVersionPlugins = Number(
activePlugins activePlugins
@ -163,7 +163,7 @@ const PluginCatalog = () => {
)} )}
</div> </div>
<Switch <Switch
defaultChecked={isActivePlugin} checked={isActivePlugin}
onCheckedChange={(e) => { onCheckedChange={(e) => {
if (e === true) { if (e === true) {
downloadTarball(item.name) downloadTarball(item.name)