api running in electron main process

This commit is contained in:
Jan Prochazka
2021-12-25 09:23:03 +01:00
parent 2ff9e8c452
commit 24071ebde7
11 changed files with 173 additions and 104 deletions

View File

@@ -90,7 +90,7 @@
}, },
"homepage": "./", "homepage": "./",
"scripts": { "scripts": {
"start": "cross-env ELECTRON_START_URL=http://localhost:5000 electron .", "start": "cross-env ELECTRON_START_URL=http://localhost:5000 ELECTRON_DEBUG=1 DEVMODE=1 electron .",
"start:local": "cross-env electron .", "start:local": "cross-env electron .",
"dist": "electron-builder", "dist": "electron-builder",
"build": "cd ../packages/api && yarn build && cd ../web && yarn build && cd ../../app && yarn dist", "build": "cd ../packages/api && yarn build && cd ../web && yarn build && cd ../../app && yarn dist",

View File

@@ -101,25 +101,25 @@ function buildMenu() {
{ {
label: 'dbgate.org', label: 'dbgate.org',
click() { click() {
require('electron').shell.openExternal('https://dbgate.org'); electron.shell.openExternal('https://dbgate.org');
}, },
}, },
{ {
label: 'DbGate on GitHub', label: 'DbGate on GitHub',
click() { click() {
require('electron').shell.openExternal('https://github.com/dbgate/dbgate'); electron.shell.openExternal('https://github.com/dbgate/dbgate');
}, },
}, },
{ {
label: 'DbGate on docker hub', label: 'DbGate on docker hub',
click() { click() {
require('electron').shell.openExternal('https://hub.docker.com/r/dbgate/dbgate'); electron.shell.openExternal('https://hub.docker.com/r/dbgate/dbgate');
}, },
}, },
{ {
label: 'Report problem or feature request', label: 'Report problem or feature request',
click() { click() {
require('electron').shell.openExternal('https://github.com/dbgate/dbgate/issues/new'); electron.shell.openExternal('https://github.com/dbgate/dbgate/issues/new');
}, },
}, },
commandItem('tabs.changelog'), commandItem('tabs.changelog'),
@@ -182,6 +182,7 @@ function createWindow() {
// enableRemoteModule: true, // enableRemoteModule: true,
}, },
}); });
mainWindow.webContents.openDevTools();
// require('@electron/remote/main').enable(mainWindow.webContents); // require('@electron/remote/main').enable(mainWindow.webContents);
if (store.get('winIsMaximized')) { if (store.get('winIsMaximized')) {
mainWindow.maximize(); mainWindow.maximize();
@@ -190,7 +191,7 @@ function createWindow() {
mainMenu = buildMenu(); mainMenu = buildMenu();
mainWindow.setMenu(mainMenu); mainWindow.setMenu(mainMenu);
function loadMainWindow(initArgs) { function loadMainWindow() {
const startUrl = const startUrl =
process.env.ELECTRON_START_URL || process.env.ELECTRON_START_URL ||
url.format({ url.format({
@@ -198,18 +199,18 @@ function createWindow() {
protocol: 'file:', protocol: 'file:',
slashes: true, slashes: true,
}); });
mainWindow.webContents.on('did-finish-load', function () { // mainWindow.webContents.on('did-finish-load', function () {
mainWindow.webContents.executeJavaScript( // mainWindow.webContents.executeJavaScript(
`runInit=()=>{ // `runInit=()=>{
try{ // try{
dbgate_initializeElectron(${JSON.stringify(initArgs)}); // dbgate_initializeElectron(${JSON.stringify(initArgs)});
}catch(e){ // }catch(e){
setTimeout(runInit,100) // setTimeout(runInit,100)
} // }
}; // };
runInit()` // runInit()`
); // );
}); // });
mainWindow.on('close', () => { mainWindow.on('close', () => {
store.set('winBounds', mainWindow.getBounds()); store.set('winBounds', mainWindow.getBounds());
store.set('winIsMaximized', mainWindow.isMaximized()); store.set('winIsMaximized', mainWindow.isMaximized());
@@ -220,27 +221,35 @@ function createWindow() {
} }
} }
if (process.env.ELECTRON_START_URL) { const api = require(path.join(
loadMainWindow({}); __dirname,
} else { process.env.ELECTRON_DEBUG ? '../../packages/api' : '../packages/api/dist/bundle.js'
const apiProcess = fork(path.join(__dirname, '../packages/api/dist/bundle.js'), [ ));
'--dynport', api.getMainModule().useAllControllers(null, electron);
'--is-electron-bundle',
'--native-modules',
path.join(__dirname, 'nativeModules'),
// '../../../src/nativeModules'
]);
apiProcess.on('message', msg => {
if (msg.msgtype == 'listening') {
const { port, authorization } = msg;
loadMainWindow({ loadMainWindow();
port,
authorization, // if (process.env.ELECTRON_START_URL) {
}); // loadMainWindow({});
} // } else {
}); // const apiProcess = fork(path.join(__dirname, '../packages/api/dist/bundle.js'), [
} // '--dynport',
// '--is-electron-bundle',
// '--native-modules',
// path.join(__dirname, 'nativeModules'),
// // '../../../src/nativeModules'
// ]);
// apiProcess.on('message', msg => {
// if (msg.msgtype == 'listening') {
// const { port, authorization } = msg;
// loadMainWindow({
// port,
// authorization,
// });
// }
// });
// }
// and load the index.html of the app. // and load the index.html of the app.
// mainWindow.loadURL('http://localhost:3000'); // mainWindow.loadURL('http://localhost:3000');

View File

@@ -39,6 +39,7 @@
"fs-reverse": "^0.0.3", "fs-reverse": "^0.0.3",
"get-port": "^5.1.1", "get-port": "^5.1.1",
"http": "^0.0.0", "http": "^0.0.0",
"is-electron": "^2.2.1",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"json-stable-stringify": "^1.0.1", "json-stable-stringify": "^1.0.1",
"line-reader": "^0.4.0", "line-reader": "^0.4.0",

View File

@@ -8,12 +8,14 @@ if (processArgs.startProcess) {
const proc = require('./proc'); const proc = require('./proc');
const module = proc[processArgs.startProcess]; const module = proc[processArgs.startProcess];
module.start(); module.start();
} else if (!module['parent'] && !processArgs.checkParent) {
const main = require('./main');
main.start();
} }
// else if (!module['parent'] && !processArgs.checkParent) {
// const main = require('./main');
// main.start();
// }
module.exports = { module.exports = {
...shell, ...shell,
getMainModule: () => require('./main'), getMainModule: () => require('./main'),

View File

@@ -102,20 +102,7 @@ function start() {
}) })
); );
useController(app, '/connections', connections); useAllControllers(app, null);
useController(app, '/server-connections', serverConnections);
useController(app, '/database-connections', databaseConnections);
useController(app, '/metadata', metadata);
useController(app, '/sessions', sessions);
useController(app, '/runners', runners);
useController(app, '/jsldata', jsldata);
useController(app, '/config', config);
useController(app, '/archive', archive);
useController(app, '/uploads', uploads);
useController(app, '/plugins', plugins);
useController(app, '/files', files);
useController(app, '/scheduler', scheduler);
useController(app, '/query-history', queryHistory);
// if (process.env.PAGES_DIRECTORY) { // if (process.env.PAGES_DIRECTORY) {
// app.use('/pages', express.static(process.env.PAGES_DIRECTORY)); // app.use('/pages', express.static(process.env.PAGES_DIRECTORY));
@@ -158,4 +145,21 @@ function start() {
} }
} }
module.exports = { start }; function useAllControllers(app, electron) {
useController(app, electron, '/connections', connections);
useController(app, electron, '/server-connections', serverConnections);
useController(app, electron, '/database-connections', databaseConnections);
useController(app, electron, '/metadata', metadata);
useController(app, electron, '/sessions', sessions);
useController(app, electron, '/runners', runners);
useController(app, electron, '/jsldata', jsldata);
useController(app, electron, '/config', config);
useController(app, electron, '/archive', archive);
useController(app, electron, '/uploads', uploads);
useController(app, electron, '/plugins', plugins);
useController(app, electron, '/files', files);
useController(app, electron, '/scheduler', scheduler);
useController(app, electron, '/query-history', queryHistory);
}
module.exports = { start, useAllControllers };

View File

@@ -2,6 +2,7 @@ const fs = require('fs');
const os = require('os'); const os = require('os');
const path = require('path'); const path = require('path');
const processArgs = require('./processArgs'); const processArgs = require('./processArgs');
const isElectron = require('is-electron');
const platform = process.env.OS_OVERRIDE ? process.env.OS_OVERRIDE : process.platform; const platform = process.env.OS_OVERRIDE ? process.env.OS_OVERRIDE : process.platform;
const isWindows = platform === 'win32'; const isWindows = platform === 'win32';
@@ -28,6 +29,7 @@ const platformInfo = {
isLinux, isLinux,
isDocker, isDocker,
isElectronBundle, isElectronBundle,
isElectron: isElectron(),
isDevMode, isDevMode,
isNpmDist, isNpmDist,
isSnap: process.env.ELECTRON_SNAP == 'true', isSnap: process.env.ELECTRON_SNAP == 'true',

View File

@@ -4,7 +4,7 @@ const express = require('express');
/** /**
* @param {string} route * @param {string} route
*/ */
module.exports = function useController(app, route, controller) { module.exports = function useController(app, electron, route, controller) {
const router = express.Router(); const router = express.Router();
if (controller._init) { if (controller._init) {
@@ -23,6 +23,21 @@ module.exports = function useController(app, route, controller) {
const meta = controller[`${key}_meta`]; const meta = controller[`${key}_meta`];
if (!meta) continue; if (!meta) continue;
const routeAction = `/${_.kebabCase(key)}`;
if (electron) {
if (meta === true) {
const handler = `${route.substring(1)}-${_.kebabCase(key)}`;
console.log('REGISTERING HANDLER', handler);
electron.ipcMain.handle(handler, async (event, args) => {
const data = await controller[key](args);
return data;
});
}
continue;
}
let method = 'post'; let method = 'post';
let raw = false; let raw = false;
let rawParams = false; let rawParams = false;
@@ -36,11 +51,10 @@ module.exports = function useController(app, route, controller) {
rawParams = meta.rawParams; rawParams = meta.rawParams;
} }
const route = `/${_.kebabCase(key)}`;
if (raw) { if (raw) {
router[method](route, controller[key]); router[method](routeAction, controller[key]);
} else { } else {
router[method](route, async (req, res) => { router[method](routeAction, async (req, res) => {
// if (controller._init && !controller._init_called) { // if (controller._init && !controller._init_called) {
// await controller._init(); // await controller._init();
// controller._init_called = true; // controller._init_called = true;
@@ -58,5 +72,7 @@ module.exports = function useController(app, route, controller) {
} }
} }
app.use(route, router); if (app) {
app.use(route, router);
}
}; };

View File

@@ -11,7 +11,7 @@
import { setAppLoaded } from './utility/appLoadManager'; import { setAppLoaded } from './utility/appLoadManager';
import ErrorHandler from './utility/ErrorHandler.svelte'; import ErrorHandler from './utility/ErrorHandler.svelte';
import OpenTabsOnStartup from './utility/OpenTabsOnStartup.svelte'; import OpenTabsOnStartup from './utility/OpenTabsOnStartup.svelte';
import { shouldWaitForElectronInitialize } from './utility/getElectron'; // import { shouldWaitForElectronInitialize } from './utility/getElectron';
import { subscribeConnectionPingers } from './utility/connectionsPinger'; import { subscribeConnectionPingers } from './utility/connectionsPinger';
import { subscribePermissionCompiler } from './utility/hasPermission'; import { subscribePermissionCompiler } from './utility/hasPermission';
import { apiCall } from './utility/api'; import { apiCall } from './utility/api';
@@ -19,10 +19,10 @@
let loadedApi = false; let loadedApi = false;
async function loadApi() { async function loadApi() {
if (shouldWaitForElectronInitialize()) { // if (shouldWaitForElectronInitialize()) {
setTimeout(loadApi, 100); // setTimeout(loadApi, 100);
return; // return;
} // }
try { try {
// console.log('************** LOADING API'); // console.log('************** LOADING API');

View File

@@ -1,6 +1,7 @@
import resolveApi, { resolveApiHeaders } from './resolveApi'; import resolveApi, { resolveApiHeaders } from './resolveApi';
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
import { cacheClean } from './cache'; import { cacheClean } from './cache';
import getElectron from './getElectron';
// import socket from './socket'; // import socket from './socket';
let eventSource; let eventSource;
@@ -13,37 +14,53 @@ function wantEventSource() {
} }
export async function apiCall(route: string, args: {} = undefined) { export async function apiCall(route: string, args: {} = undefined) {
const resp = await fetch(`${resolveApi()}/${route}`, { const electron = getElectron();
method: 'POST', if (electron) {
cache: 'no-cache', const resp = await electron.invoke(route.replace('/', '-'), args);
headers: { return resp;
'Content-Type': 'application/json', } else {
...resolveApiHeaders(), const resp = await fetch(`${resolveApi()}/${route}`, {
}, method: 'POST',
body: JSON.stringify(args), cache: 'no-cache',
}); headers: {
return resp.json(); 'Content-Type': 'application/json',
...resolveApiHeaders(),
},
body: JSON.stringify(args),
});
return resp.json();
}
} }
const apiHandlers = new WeakMap(); const apiHandlers = new WeakMap();
export function apiOn(event: string, handler: Function) { export function apiOn(event: string, handler: Function) {
wantEventSource(); const electron = getElectron();
if (!apiHandlers.has(handler)) { if (electron) {
const handlerProxy = e => { electron.addEventListener(event, handler);
// console.log('RECEIVED', e.type, JSON.parse(e.data)); } else {
handler(JSON.parse(e.data)); wantEventSource();
}; if (!apiHandlers.has(handler)) {
apiHandlers.set(handler, handlerProxy); const handlerProxy = e => {
} // console.log('RECEIVED', e.type, JSON.parse(e.data));
handler(JSON.parse(e.data));
};
apiHandlers.set(handler, handlerProxy);
}
eventSource.addEventListener(event, apiHandlers.get(handler)); eventSource.addEventListener(event, apiHandlers.get(handler));
}
} }
export function apiOff(event: string, handler: Function) { export function apiOff(event: string, handler: Function) {
wantEventSource(); const electron = getElectron();
if (apiHandlers.has(handler)) { if (electron) {
eventSource.removeEventListener(event, apiHandlers.get(handler)); electron.removeEventListener(event, handler);
} else {
wantEventSource();
if (apiHandlers.has(handler)) {
eventSource.removeEventListener(event, apiHandlers.get(handler));
}
} }
} }

View File

@@ -1,11 +1,11 @@
class ElectronApi { class ElectronApi {
public port?: number; // public port?: number;
public authorization?: string; // public authorization?: string;
private ipcRenderer = getIpcRenderer(); private ipcRenderer = getIpcRenderer();
constructor(args) { constructor() {
this.port = args.port; // this.port = args.port;
this.authorization = args.authorization; // this.authorization = args.authorization;
} }
send(msg, args = null) { send(msg, args = null) {
@@ -30,18 +30,29 @@ class ElectronApi {
async openExternal(url) { async openExternal(url) {
await this.ipcRenderer.invoke('openExternal', url); await this.ipcRenderer.invoke('openExternal', url);
} }
}
let apiInstance = null; async invoke(route, args) {
const res = await this.ipcRenderer.invoke(route, args);
return res;
}
function initializeElectron(args) { addEventListener(channel: string, listener: Function) {
apiInstance = new ElectronApi(args); this.ipcRenderer.on(channel, listener);
if (window['dbgate_recreateSocket']) { }
window['dbgate_recreateSocket']();
removeEventListener(channel: string, listener: Function) {
this.ipcRenderer.removeEventListener(channel, listener);
} }
} }
window['dbgate_initializeElectron'] = initializeElectron; // function initializeElectron(args) {
// apiInstance = new ElectronApi(args);
// if (window['dbgate_recreateSocket']) {
// window['dbgate_recreateSocket']();
// }
// }
// window['dbgate_initializeElectron'] = initializeElectron;
function getIpcRenderer() { function getIpcRenderer() {
if (window['require']) { if (window['require']) {
@@ -51,14 +62,16 @@ function getIpcRenderer() {
return null; return null;
} }
export function shouldWaitForElectronInitialize() { // export function shouldWaitForElectronInitialize() {
return !!getIpcRenderer() && !apiInstance; // return !!getIpcRenderer() && !apiInstance;
} // }
export function isElectronAvailable() { export function isElectronAvailable() {
return !!getIpcRenderer(); return !!getIpcRenderer();
} }
const apiInstance = isElectronAvailable() ? new ElectronApi() : null;
export default function getElectron(): ElectronApi { export default function getElectron(): ElectronApi {
return apiInstance; return apiInstance;
// try { // try {

View File

@@ -5316,6 +5316,11 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2:
is-data-descriptor "^1.0.0" is-data-descriptor "^1.0.0"
kind-of "^6.0.2" kind-of "^6.0.2"
is-electron@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/is-electron/-/is-electron-2.2.1.tgz#751b1dd8a74907422faa5c35aaa0cf66d98086e9"
integrity sha512-r8EEQQsqT+Gn0aXFx7lTFygYQhILLCB+wn0WCDL5LZRINeLH/Rvw1j2oKodELLXYNImQ3CRlVsY8wW4cGOsyuw==
is-extendable@^0.1.0, is-extendable@^0.1.1: is-extendable@^0.1.0, is-extendable@^0.1.1:
version "0.1.1" version "0.1.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"