1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-30 10:36:35 +02:00
joplin/packages/app-desktop/services/plugins/plugin_index.js

155 lines
4.3 KiB
JavaScript
Raw Normal View History

(function(globalObject) {
// TODO: Not sure if that will work once packaged in Electron
const sandboxProxy = require('../../vendor/lib/@joplin/lib/services/plugins/sandboxProxy.js');
const ipcRenderer = require('electron').ipcRenderer;
const nodePath = require('path');
const ipcRendererSend = (message, args) => {
try {
return ipcRenderer.send(message, args);
} catch (error) {
console.error('Could not send IPC message:', message, ': ', args, error);
throw error;
}
};
const urlParams = new URLSearchParams(window.location.search);
const pluginId = urlParams.get('pluginId');
let eventId_ = 1;
const eventHandlers_ = {};
function mapEventHandlersToIds(argName, arg) {
if (Array.isArray(arg)) {
for (let i = 0; i < arg.length; i++) {
arg[i] = mapEventHandlersToIds(`${i}`, arg[i]);
}
return arg;
} else if (typeof arg === 'function') {
const id = `___plugin_event_${argName}_${eventId_}`;
eventId_++;
eventHandlers_[id] = arg;
return id;
} else if (arg === null) {
return null;
} else if (arg === undefined) {
return undefined;
} else if (typeof arg === 'object') {
for (const n in arg) {
arg[n] = mapEventHandlersToIds(n, arg[n]);
}
}
return arg;
}
const callbackPromises = {};
let callbackIndex = 1;
const target = (path, args) => {
if (path === 'require' || path === 'plugins.require') { // plugins.require is deprecated
const modulePath = args && args.length ? args[0] : null;
if (!modulePath) throw new Error('No module path specified on `require` call');
// The sqlite3 is actually part of the lib package so we need to do
// something convoluted to get it working.
if (modulePath === 'sqlite3') {
return require('../../node_modules/@joplin/lib/node_modules/sqlite3/lib/sqlite3.js');
}
if (modulePath === 'fs-extra') {
return require('fs-extra');
}
// 7zip-bin is required by one of the default plugins (simple-backup)
if (modulePath === '7zip-bin') {
// 7zip-bin is very large -- return the path to a version of 7zip
// copied from 7zip-bin.
const executableName = process.platform === 'win32' ? '7za.exe' : '7za';
let rootDir = nodePath.dirname(nodePath.dirname(__dirname));
// When bundled, __dirname points to a file within app.asar. The build/ directory
// is outside of app.asar, and thus, we need an extra dirname(...).
if (nodePath.basename(rootDir).startsWith('app.asar')) {
rootDir = nodePath.dirname(rootDir);
}
const pathTo7za = nodePath.join(rootDir, 'build', '7zip', executableName);
return { path7za: nodePath.resolve(pathTo7za) };
}
throw new Error(`Module not found: ${modulePath}`);
}
const callbackId = `cb_${pluginId}_${Date.now()}_${callbackIndex++}`;
const promise = new Promise((resolve, reject) => {
callbackPromises[callbackId] = { resolve, reject };
});
ipcRendererSend('pluginMessage', {
target: 'mainWindow',
pluginId: pluginId,
callbackId: callbackId,
path: path,
args: mapEventHandlersToIds(null, args),
});
return promise;
};
ipcRenderer.on('pluginMessage', async (_event, message) => {
if (message.eventId) {
const eventHandler = eventHandlers_[message.eventId];
if (!eventHandler) {
console.error('Got an event ID but no matching event handler: ', message);
return;
}
let result = null;
let error = null;
try {
result = await eventHandler(...message.args);
} catch (e) {
error = e;
}
if (message.callbackId) {
ipcRendererSend('pluginMessage', {
target: 'mainWindow',
pluginId: pluginId,
mainWindowCallbackId: message.callbackId,
result: result,
error: error,
});
}
return;
}
if (message.pluginCallbackId) {
const promise = callbackPromises[message.pluginCallbackId];
if (!promise) {
console.error('Got a callback without matching promise: ', message);
return;
}
if (message.error) {
promise.reject(message.error);
} else {
promise.resolve(message.result);
}
return;
}
console.warn('Unhandled plugin message:', message);
});
const pluginScriptPath = urlParams.get('pluginScript');
const script = document.createElement('script');
script.src = pluginScriptPath;
document.head.appendChild(script);
globalObject.joplin = sandboxProxy(target);
})(window);