2020-10-09 19:35:46 +02:00
|
|
|
(function(globalObject) {
|
|
|
|
// TODO: Not sure if that will work once packaged in Electron
|
2021-12-23 13:04:09 +02:00
|
|
|
const sandboxProxy = require('../../vendor/lib/@joplin/lib/services/plugins/sandboxProxy.js');
|
2020-10-09 19:35:46 +02:00
|
|
|
const ipcRenderer = require('electron').ipcRenderer;
|
|
|
|
|
2020-12-01 16:08:41 +02:00
|
|
|
const ipcRendererSend = (message, args) => {
|
|
|
|
try {
|
|
|
|
return ipcRenderer.send(message, args);
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Could not send IPC message:', message, ': ', args, error);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-10-09 19:35:46 +02:00
|
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
|
|
const pluginId = urlParams.get('pluginId');
|
2024-01-26 12:33:15 +02:00
|
|
|
const libraryData = JSON.parse(decodeURIComponent(urlParams.get('libraryData')));
|
2020-10-09 19:35:46 +02:00
|
|
|
|
|
|
|
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) => {
|
2021-01-27 14:48:47 +02:00
|
|
|
if (path === 'require' || path === 'plugins.require') { // plugins.require is deprecated
|
2021-01-24 20:03:33 +02:00
|
|
|
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') {
|
2023-01-05 12:21:12 +02:00
|
|
|
return require('../../node_modules/@joplin/lib/node_modules/sqlite3/lib/sqlite3.js');
|
2021-01-24 20:03:33 +02:00
|
|
|
}
|
|
|
|
|
2023-12-11 15:58:45 +02:00
|
|
|
if (modulePath === 'fs-extra') {
|
|
|
|
return require('fs-extra');
|
|
|
|
}
|
|
|
|
|
|
|
|
// 7zip-bin is required by one of the default plugins (simple-backup)
|
|
|
|
if (modulePath === '7zip-bin') {
|
2024-01-26 12:33:15 +02:00
|
|
|
return { path7za: libraryData.pathTo7za };
|
2023-12-11 15:58:45 +02:00
|
|
|
}
|
2021-01-24 20:03:33 +02:00
|
|
|
|
|
|
|
throw new Error(`Module not found: ${modulePath}`);
|
|
|
|
}
|
|
|
|
|
2020-10-09 19:35:46 +02:00
|
|
|
const callbackId = `cb_${pluginId}_${Date.now()}_${callbackIndex++}`;
|
|
|
|
const promise = new Promise((resolve, reject) => {
|
|
|
|
callbackPromises[callbackId] = { resolve, reject };
|
|
|
|
});
|
|
|
|
|
2020-12-01 16:08:41 +02:00
|
|
|
ipcRendererSend('pluginMessage', {
|
2020-10-09 19:35:46 +02:00
|
|
|
target: 'mainWindow',
|
|
|
|
pluginId: pluginId,
|
|
|
|
callbackId: callbackId,
|
|
|
|
path: path,
|
|
|
|
args: mapEventHandlersToIds(null, args),
|
|
|
|
});
|
|
|
|
|
|
|
|
return promise;
|
|
|
|
};
|
|
|
|
|
2020-10-21 02:43:06 +02:00
|
|
|
ipcRenderer.on('pluginMessage', async (_event, message) => {
|
2020-10-09 19:35:46 +02:00
|
|
|
if (message.eventId) {
|
|
|
|
const eventHandler = eventHandlers_[message.eventId];
|
|
|
|
|
|
|
|
if (!eventHandler) {
|
|
|
|
console.error('Got an event ID but no matching event handler: ', message);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-21 02:43:06 +02:00
|
|
|
let result = null;
|
|
|
|
let error = null;
|
|
|
|
try {
|
|
|
|
result = await eventHandler(...message.args);
|
|
|
|
} catch (e) {
|
|
|
|
error = e;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (message.callbackId) {
|
2020-12-01 16:08:41 +02:00
|
|
|
ipcRendererSend('pluginMessage', {
|
2020-10-21 02:43:06 +02:00
|
|
|
target: 'mainWindow',
|
|
|
|
pluginId: pluginId,
|
|
|
|
mainWindowCallbackId: message.callbackId,
|
|
|
|
result: result,
|
|
|
|
error: error,
|
|
|
|
});
|
|
|
|
}
|
2020-10-09 19:35:46 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-21 02:43:06 +02:00
|
|
|
if (message.pluginCallbackId) {
|
|
|
|
const promise = callbackPromises[message.pluginCallbackId];
|
2020-10-09 19:35:46 +02:00
|
|
|
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);
|