Not able to connect to MySQL database from Electron application - javascript

I have started learning electron js application development, so I have created a simple electron js application and I am trying to get data from the MySQL database display it on the HTML page.
In the developer console, inside the MySQL connection object state is disconnected.
am able to get an alert which is renderer.js file and dbmgr.js file.
Package.json
{
"name": "myfirstelectronapp",
"version": "1.0.0",
"description": "My first electron app",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"author": "Pradeep",
"license": "MIT",
"dependencies": {
"electron": "^17.1.2",
"mysql": "^2.18.1"
}
}
index.html
<body>
<h1>My First Electron application get started</h1>
<div id="names"></div>
<script src="renderer.js"></script>
</body>
renderer.js
document.addEventListener('DOMContentLoaded', async () => {
alert('renderer.js');
let names = window.api.getData();
console.log(names);
let divId = document.getElementById("names");
let namestring = names.join("<br> /");
divId.innerHTML = namestring;
});
preload.js
const dmmgr=require("./models/dbmgr");
const {contextBridge}=require('electron');
const getData=()=>{
return dmmgr.getData();
}
contextBridge.exposeInMainWorld("api",{
getData : getData
})
main.js
const electron = require('electron');
const path = require('path');
const { app, BrowserWindow } = electron;
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, './preload.js')
}
})
win.loadFile("index.html");
}
app.whenReady().then(() => {
createWindow();
});
app.on('window-all-closed', () => {
if (process.platform != 'darwin') app.quit();
})
dbmgr.js
code connect mysql
var mysql = require('mysql');
// Add the credentials to access your database
var connection = mysql.createConnection({
host: 'localhost',
port:'3306',
user: 'root',
password: 'root', // or the original password : 'apaswword'
database: 'vs_users_temp'
});
// connect to mysql
connection.connect(function (err) {
// in case of error
if (err) {
console.log("Error "+err.code);
console.log("Error "+err.sqlMessage);
}
});
exports.getData = () => {
alert('dbmgr.js');
console.log(connection);
// Perform a query
$query = 'SELECT * FROM user';
connection.query($query, function (err, rows, fields) {
if (err) {
console.log("An error ocurred performing the query.");
console.log(err);
return;
}
console.log("Query succesfully executed", rows);
return rows;
});
}
// Close the connection
connection.end(function () {
// The connection has been closed
});

If you are wanting to render data within your index.html file immediately after it has loaded then you could use win.webContents.send(channel, ...args); once the application is ready and the window is loaded. This is like pushing the data from the main thread instead of pulling it from the render thread (via your existing preload.js script).
Additionally, implementing concrete functions within your preload.js script can be difficult to understand and implement successfully. Instead, I find the approach of using the preload.js script as a gateway to communicate between the main thread and render thread(s) via the use of channel names to be much simpler to understand and implement.
In this preload.js script, one only needs to specify their whitelisted channel name(s). These channel names are used to identify within the main thread and render threads defined lines of communication (with optional data).
In the below preload file I have defined the channel name db:getData. You can use any channel name you like.
preload.js (main thread)
// Import the necessary Electron components.
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels.
const ipc = {
'render': {
// From render to main.
'send': [],
// From main to render.
'receive': [
'db:getData' // Channel name
],
// From render to main and back again.
'sendReceive': []
}
};
// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods.
'ipcRender', {
// From render to main.
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render.
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`.
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again.
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);
Once the application is ready and the window has been loaded, send a message using the channel name db:getData to the render thread along with the accompanying result set from the database.
main.js (main thread)
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const nodePath = require("path");
const dbmgr = require(nodePath.join(__dirname, 'dbmgr'); // Include your dbmgr module
// Prevent garbage collection
let window;
function createWindow() {
const window = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload.js')
}
});
window.loadFile('index.html')
.then(() => { window.webContents.send('db:getData', dbmgr.getData()); }) // Send data to render
.then(() => { window.show(); });
return window;
}
electronApp.on('ready', () => {
window = createWindow();
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
For simplicity, I have the Mysql connect and end functions within the called getData() function (which is exported for use in the main.js file).
Though I haven't used the mysql package before, I believe pooling connections is highly recommended.
dbmgr.js (main thread)
const mysql = require('mysql');
// Add the credentials to access your database
const connection = mysql.createConnection({
host: 'localhost',
port:'3306',
user: 'root',
password: 'root', // or the original password : 'apaswword'
database: 'vs_users_temp'
});
function getData() => {
// connect to mysql
connection.connect(function (err) {
// in case of error
if (err) {
console.log('Error ' + err.code);
console.log('Error ' + err.sqlMessage);
}
});
console.log(connection); // Testing
// Perform a query
$query = 'SELECT * FROM user';
connection.query($query, function (err, rows, fields) {
if (err) {
console.log('An error ocurred performing the query.');
console.log(err);
return;
}
console.log('Query succesfully executed', rows); // Testing
// Close the connection
connection.end(function () {});
return rows;
});
}
module.exports = { getData }
For the sake of simplicity I have included your renderer.js code within your index.html <script> tags.
Placing your <script> tag(s) (whether it is importing or inline) just below the closing </body> tag is best practice.
index.html (render thread)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>My First Electron application get started</h1>
<div id="names"></div>
</body>
<script>
window.ipcRender.receive('db:getData', (names) => {
console.log(names); // Testing
let divId = document.getElementById('names');
let namestring = names.join("<br> /");
divId.innerHTML = namestring;
});
</script>
</html>

Related

Looking for a solution to stream dynamic changes in JSON data on to browser without refreshing

I have a node.js / next.js api built that essentially does a bunch of stuff after the user submits text into a form on the front end. One of the things it does is write stage completion messages periodically to a JSON file to signify the completion of certain stages.
my api looks something like this
import dbConnect from '../../../lib/dbConnect'
import Demo from '../../../models/Demo'
import fs from 'fs'
import shell from 'shelljs';
export default async function handler(req, res) {
const {
method,
body,
} = req
await dbConnect()
switch (method) {
case 'GET':
try {
const demos = await Demo.find({})
res.status(200).json({ success: true, data: demos })
} catch (error) {
res.status(400).json({ success: false })
}
break
case 'POST':
try {
const initialjson = '[]'
const timestamp = Date.now();
// stage 1
if (shell.exec('./initial_checks.sh').code !== 0) {
shell.echo('Sorry stage failed');
shell.exit(1);
};
const objSuccess1 = JSON.parse(initialjson);
objSuccess1.push("Stage 1 complete", + timestamp);
const finalJSONSuccess1 = JSON.stringify(objSuccess1);
fs.writeFileSync('success-stage.json', finalJSONSuccess1);
// stage 2
if (shell.exec('./secondary_checks.sh').code !== 0) {
shell.echo('Sorry stage failed');
shell.exit(1);
};
const objSuccess2 = JSON.parse(initialjson);
objSuccess2.push("Stage 2 complete", + timestamp);
const finalJSONSuccess2 = JSON.stringify(objSuccess2);
fs.writeFileSync('success-stage.json', finalJSONSuccess2);
const demo = await Demo.create(
req.body
)
res.status(201).json({ success: true, data: demo })
} catch (error) {
res.status(400).json({ success: false })
}
break
default:
res.status(400).json({ success: false })
break
}
}
I am using socket.io, my server.js file is
server.js
const app = require("express")();
const server = require("http").Server(app);
const io = require("socket.io")(server);
const next = require("next");
const dev = process.env.NODE_ENV !== "production";
const nextApp = next({ dev });
const nextHandler = nextApp.getRequestHandler();
let port = 3000;
const fs = require('fs')
const data = fs.readFileSync('success-stage.json', 'utf8')
io.on("connect", (socket) => {
socket.emit("now", {
message: data
});
});
nextApp.prepare().then(() => {
app.all("*", (req, res) => {
return nextHandler(req, res);
});
server.listen(port, (err) => {
if (err) throw err;
console.log("> Ready on port: " + port);
});
});
and here is the pages/index.js file
import { useEffect, useRef, useState } from "react";
import io from "socket.io-client";
export default function IndexPage() {
const socket = useRef();
const [hello, setHello] = useState();
useEffect(() => {
socket.current = io();
socket.current.on("now", (data) => {
setHello(data.message);
});
}, []);
return <h1>{hello}</h1>;
}
so at this point we are seeing the 2nd message from my JSON file match what is rendered on the frontend when I build my application. It looks like this
["Stage 2 complete",1664289144513]
I am wondering how I can stream this data onto the front end for clients without having to refresh the page? I need it to show the current stage's success message... There are 5 total stages, so i guess i am looking for a way to either stream data or maybe to revalidate the browser window like every second without having to refresh... is this possible?
Any help would be greatly appreciated... Thanks in advance for your time everyone...
You've already got a solution implemented that can handle this. What you're describing is exactly what sockets are for -- bidirectional communication between the client and server without refreshing the page.
Just create a new socket listener on the frontend for a new topic, maybe "stageStatus", and then emit messages to that topic on the backend at various stages in the process. That's it!

Electron: Simplest example to pass variable from JS to HTML, using IPC, Contextbridge and Preload?

I am trying to learn electron, but I'm struggling to understand this basic functionality of IPC.
Already tried from documentation or tutorials but everytime they overcomplicate with complex examples or using other libaries like svelte, typescript etc. Also I don't want to show in console, I want to display directly in HTML page. I know these are basics, but any help is appreciated.
So far I understood that I need:
main.js
const { app, BrowserWindow, ipcMain } = require("electron");
const path = require("path");
app.whenReady().then(main);
let window;
async function main() {
window = new BrowserWindow({
width: 100,
height: 100,
webPreferences: {
preload: path.join(__dirname + "./preload.js")
},
})
window.on("ready-to-show", window.show);
window.loadFile(path.join(__dirname, "./index.html"));
}
ipcMain.on("GetMyVar", (event, args) => {
*???*
})
preload.js
const { ipcRenderer, contextBridge } = require("electron");
const API = {
window: {
GetMyVar: () => ipcRenderer.send("GetMyVar", MyVar) *???*
},
}
contextBridge.exposeInMainWorld("app", API);
renderer.js
const MyVar = "JUSTSHOWUP!";
index.html
<html>
<body>
<h1 id='MyVar'>???</h1>
</body>
</html>
Thank you!
Electron Inter-Process Communication is a difficult subject to
grasp without easy to understand examples.
Your preload.js script can be written in a number of different ways. In the below code example, I have included two
ways to do this.
preload-1.js uses a simplified, easy to understand direct implementation method. That said, for ease of
maintainability and debugging, as your Electron application grows, you will want to split your preload.js script up
into smaller individual preload scripts. Bearing in mind that you can only load one preload script per window
instance, you may have a need to repeat code between preload scripts.
preload-2.js uses a more flexible white listed channel naming system where you only need to load the one preload
script across all created windows. As a result, your preload script only performs a single function, to communicate
between your main process and render process(es). Implementation of the sent and received channel names are kept within
your specific code domains.
main.js (main process)
No matter which type of preload script you use, implementation will be the same within your main.js file.
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronIpcMain = require('electron').ipcMain;
const nodePath = require('path');
// Prevent garbage collection.
let window;
function createWindow() {
const window = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload-1.js')
// preload: nodePath.join(__dirname, 'preload-2.js')
}
});
window.loadFile('index.html')
.then(() => { window.webContents.send('messageFromMain', 'Message from main..!'); })
.then(() => { window.show(); });
return window;
}
electronApp.on('ready', () => {
window = createWindow();
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// ---
electronIpcMain.on('messageToMain', (event, message) => {
console.log('Message to main: ' + message);
})
preload-1.js (main process)
// Import the necessary Electron components
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// Exposed protected methods in the render process
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods
'ipcRender', {
// From render to main
messageToMain: (message) => {
ipcRenderer.send('messageToMain', message)
},
// From main to render
messageFromMain: (message) => {
ipcRenderer.on('messageFromMain', message)
}
});
preload-2.js (main process)
At the end of this preload.js script, I have included a section on how to use it within your main process and render
process(es).
// Import the necessary Electron components
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels
const ipc = {
'render': {
// From render to main
'send': [
'messageToMain'
],
// From main to render
'receive': [
'messageFromMain'
],
// From render to main and back again
'sendReceive': []
}
};
// Exposed protected methods in the render process
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods
'ipcRender', {
// From render to main
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);
/**
* Render --> Main
* ---------------
* Render: window.ipcRender.send('channel', data); // Data is optional.
* Main: electronIpcMain.on('channel', (event, data) => { methodName(data); })
*
* Main --> Render
* ---------------
* Main: windowName.webContents.send('channel', data); // Data is optional.
* Render: window.ipcRender.receive('channel', (data) => { methodName(data); });
*
* Render --> Main (Value) --> Render
* ----------------------------------
* Render: window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
* Main: electronIpcMain.handle('channel', (event, data) => { return someMethod(data); });
*
* Render --> Main (Promise) --> Render
* ------------------------------------
* Render: window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
* Main: electronIpcMain.handle('channel', async (event, data) => {
* return await promiseName(data)
* .then(() => { return result; })
* });
*/
index.html (render process)
To test which form of preload.js script you prefer, just comment out one whilst uncommenting the other.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Electron IPC Test</title>
</head>
<body>
<div>
<label for="messageFromMain">Message from Main Process: </label>
<input type="text" id="messageFromMain" disabled>
</div>
<hr>
<div>
<label for="messageToMain">Message to Main Process: </label>
<input type="text" id="messageToMain">
<input type="button" id="send" value="Send">
</div>
</body>
<script>
let messageFromMain = document.getElementById('messageFromMain');
let messageToMain = document.getElementById('messageToMain');
// Message from main (preload-1.js)
window.ipcRender.messageFromMain((event, message) => {
messageFromMain.value = message;
})
// Message from main (preload-2.js)
// window.ipcRender.receive('messageFromMain', (message) => {
// messageFromMain.value = message;
// })
// Message to main
document.getElementById('send').addEventListener('click', () => {
// (preload-1.js)
window.ipcRender.messageToMain(messageToMain.value);
// (preload-2.js)
// window.ipcRender.send('messageToMain', messageToMain.value);
})
</script>
</html>

Sending messages through Electron IPCmain channel to vue instance only works one way

I'm tyring to send messages back and forth between the main electron process and the vue instance. What i have so far is
Preload.js:
import { contextBridge, ipcRenderer } from 'electron'
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const dependency of ['chrome', 'node', 'electron']) {
replaceText(`${dependency}-version`, process.versions[dependency])
}
})
window.ipcRenderer = require('electron').ipcRenderer;
contextBridge.exposeInMainWorld('ipcRenderer', {
//Render (Vue) to main (Electron)
send: (channel, data) => {
let validChannels = ['clientMessage'] // <-- Array of all ipcRenderer Channels used in the client
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data)
}
},
//Main (Electron) to Render (Vue)
on: (channel, func) => {
let validChannels = ['electronMessage'] // <-- Array of all ipcMain Channels used in the electron
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...args))
}
}
})
So i have 2 whitelisted channels in ipcRender, one is called 'clientMessage' to send messaged from the vue instance to the electron main process, the other is 'electronMessage' to send messages from the electron main process to the vue instance.
In my background.js i have the following:
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
ipcMain.on('clientMessage', (event, args) => {
console.log('received a message from vue: '+args)
event.sender.send('message','return Message from electron'+args);
});
And in my app.Vue i have:
mounted () {
window.ipcRenderer.on('electronMessage', (event, data) => {
console.log('message from electron: '+data)
})
},
methods: {
sendMessage(){
window.ipcRenderer.send('clientMessage','testing')
}
}
The app runs fine, and when i call the sendMessage function I correctly get a console log on the electron terminal saying message received. So clearly vue -> electron messaging has worked, but why wont it work for the reverse?
Your contextBridge.exposeInMainWorld "keys" are ipcRenderer.send and ipcRenderer.receive.
You must use these keys to access your defined preload.js IPC methods. IE: send and on.
Specifically, to use the ipcRender.on(...) method, you call it with window.ipcRenderer.receive(...).
app.Vue (render thread)
// To send a message from render thread to main thread.
window.ipcRenderer.send('clientMessage','testing'); // Working
// To receive a message from main thread to render thread.
window.ipcRenderer.receive('electronMessage', (event, data) => {
console.log('message from electron: ' + data);
});
I figured out why, the way to send messages from electron main process to the renderer instance is not the same. Since there is only one electron main process running at all times, we can simple do window.ipcRenderer.send('', 'your message') in the vue renderer instance, but since there can be more than one renderer instances running, the main electron process needs to know which render process to send it to.
So in your main.js/background.js whatever .js you are running the electron main process out of. do this:
let win;
async function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
enableRemoteModule: true,
preload: path.join(__dirname, "preload.js")
}
})
.
.
.
and then to send a message to the render instance:
win.webContents.send('<channelName>','your message')
that way it sends it to the correct render process. So my code in the end looks like this:
ipcMain.on('clientMessage', (event, args) => {
console.log('received a message from vue: '+args)
win.webContents.send('electronMessage','Reply from main process: '+args)
});

Access methods in electron's main process from render process after building

Alright so I have these methods in my index.js main process that I want to access from the render process. I have tried two ways to go about this process.
ipcMain and ipcRender
The first idea was to use ipcMain and ipcRender using an "on" and "sendSync" The error I get back is "an object could not be cloned"
Index.js - Main Process
ipcMain.on( "getData", ( event, callBack ) => {
db = new sqlite3.Database(
dbPath,
sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE,
function(error) {
if(error){
log.error(`exception: ${error}`);
//throw error
if (callBack) callBack(error);
}
data.getModel(db, log, function(rawDataStr) {
if (callBack) callBack(rawDataStr);
})
}
)
return db
} );
App.Js - Render Process
window.require('electron').ipcRenderer.sendSync( "getData",function(rawData){
if (rawData.name && rawData.name == 'Error') {
alert('PRT DB is not present');
} else {
sharedObj.rawData = rawData;
app.advanceReadiness();
}
})
#electron/remote
The other solution I tried was to use #electron/remote. I understand the remote module was depreciated, but I was willing to try it. This works when I run the the app locally, but as soon as I build the app with electron-forge it can no longer find my global variable.
Index.js - Main Process
require('#electron/remote/main').initialize()
global.sharedObj = {
getData:function(callBack){
db = new sqlite3.Database(
dbPath,
sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE,
function(error) {
if(error){
log.error(`exception: ${error}`);
//throw error
if (callBack) callBack(error);
}
data.getModel(db, log, function(rawDataStr) {
if (callBack) callBack(rawDataStr);
})
}
)
}
}
App.js - Render Process
var sharedObj = window.require('#electron/remote').getGlobal('sharedObj');
sharedObj.getData(function (rawData) {
if (rawData.name && rawData.name == 'Error') {
alert('PRT DB is not present');
} else {
sharedObj.rawData = rawData;
app.advanceReadiness();
}
});
I suspect that your DB connection isn't cloneable, because this DB object doesn't fit one of the valid values that can be serialized by IPC (inter-process communication). (See this section to see what we can pass between renderer > main process without issue).
You probably need to do something like this. I'm not familiar with using sqlite3 in JS, but this should hopefully get you started on the right track. The general gist is that you should store a reference to your DB in your main.js file and then set up a listener that listens for requests from your front-end page. Once a message is sent to the main.js file (ie. backend), you will query your DB, and then return the results to the front-end by sending an IPC message back (win.webContents.send("fromMain", data); in the example elow).
main.js
const {
app,
BrowserWindow,
ipcMain
} = require("electron");
const path = require("path");
const fs = require("fs");
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;
let db = new sqlite3.Database(
dbPath,
sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE,
function (error) {
if (error) {
log.error(`exception: ${error}`);
//throw error
if (callBack) callBack(error);
}
data.getModel(db, log, function (rawDataStr) {
if (callBack) callBack(rawDataStr);
})
}
);
async function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false, // is default value after Electron v5
contextIsolation: true, // protect against prototype pollution
enableRemoteModule: false, // turn off remote
preload: path.join(__dirname, "preload.js") // use a preload script
}
});
// Load app
win.loadFile(path.join(__dirname, "dist/index.html"));
// rest of code..
}
app.on("ready", createWindow);
ipcMain.on("toMain", (event, args) => {
db.retrieveData().then(data => {
// Send result back to renderer process
win.webContents.send("fromMain", data);
});
});
preload.js
const {
contextBridge,
ipcRenderer
} = require("electron");
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld(
"api", {
send: (channel, data) => {
// whitelist channels
let validChannels = ["toMain"];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
let validChannels = ["fromMain"];
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...args));
}
}
}
);
index.html
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8"/>
<title>Title</title>
</head>
<body>
<script>
window.api.receive("fromMain", (data) => {
console.log(`Received ${data} from main process`);
});
window.api.send("toMain", "some data");
</script>
</body>
</html>

mongo client: how can I reuse the client in separate file?

Here is db.js file
const client = new MongoClient(DATABASE, mongodbOptions);
const connectWithMongoDb = () => {
client.connect((err) => {
if (err) {
throw err;
} else {
console.log('db connected');
}
});
};
module.exports = { client, connectWithMongoDb };
I called the connectWithMongoDb function from my server.js. db connects successfully. but the problem is I can't reuse the client. for example, I want to make a separate directory for collections. (in order to get a collection I need client object)
So, here is my collection.js file
const { client } = require('../helpers/db-helper/db');
exports.collection = client.db('organicdb').collection('products');
but the problem arises as soon as this file(collection.js) is called.
I am getting this error:
throw new MongoError('MongoClient must be connected before calling MongoClient.prototype.db'
You have to get the connection after connecting to MongoDB post that you can use it anywhere.
Read - https://mongodb.github.io/node-mongodb-native/api-generated/mongoclient.html
let client;
async function connect() {
if (!client) {
client = await MongoClient.connect(DATABASE, mongodbOptions)
.catch(err => { console.log(err); });
}
return client;
}
conet getConectedClient = () => client;
const testConnection = connect()
.then((connection) => console.log(connection)); // call the function like this
module.exports = { connect, getConectedClient };

Categories

Resources