Sending a message to the parent window in Electron - node.js

I have a rendering process open a modal window
import { remote } from 'electron';
let currentWindow = remote.getCurrentWindow();
let modalWindow = new BrowserWindow({width:800, heigh:500, parent:currentWindow});
modalWindow.loadURL('views/second.html');
How can I pass a message from the modalWindow back to its parent?

You have to use ipc communication.
In the Main process:
ipcMain.on('asynchronous-message', (event, arg) => {
//manage data
})
And in your modalWindow:
ipcRenderer.send('asynchronous-message', message)
ipcMain doc
ipcRenderer doc

Related

AbortController: how to stop instead of abort a Node.js stream?

My application has two buttons: start (to consume a stream from the server) and stop (to close the connection using AbortController). Here are my listeners:
let abortController = new AbortController();
start.addEventListener('click', async () => {
const readable = await consumeAPI(abortController.signal);
readable.pipeTo(appendToHTML(cards));
});
stop.addEventListener('click', () => {
abortController.abort();
console.log('aborting...');
abortController = new AbortController();
})
However, I would like to change the behavior of these buttons to pause and resume the request instead of abort and close.
AbortController MDN seems to have only the abort() and no other alternatives.
My server is using Readable.toWeb() from Node streams. I know there is a pause() and resume() function but I don't know how to use or how to call them from the client.

How to receive socket events inside a flutterBackgroundServices method [FLUTTER]

I am using a server in node js to run socket.io, what i want to do is that when the app is in the background it still receive events from the sockets, can only send events, but does not receive them.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
socketConnection.socket.connect();
await FlutterBackgroundService.initialize(onStart); //here start executing the onStart method
runApp(MyApp());
}
onStart() async {
WidgetsFlutterBinding.ensureInitialized();
final service = FlutterBackgroundService();
if (await service.isServiceRunning()) {
socketEvents();//socket events method
}
}
socketEvents() {
log(socketConnection.socket.connected.toString()); //here I want to know if it is connected and it always shows me **false**, but it does connect
socketConnection.socket.on('noty_event', (data) async {
log(data['msg'].toString()); //I want to show in the console when an event arrives but it does not show anything
});
}

Passing data from server to html with Electron/Nodejs

I'm using preload and renderer js to pass data from html to server. I have a main window and I open another window (add window). I take data from add window and pass it to server. I receive the data on server, but I don't know how to send callback with data from server to main window html.
In preload I have:
contextBridge.exposeInMainWorld(
'windowControls',
{
add: (data)=> ipcRenderer.send('item:add',data),
received:(data)=> ipcRenderer.send('item:received',data)
In rendererAddwindow:
var input = document.getElementById("inputItem").value;
windowControls.add(input)
In app.js:
// Catch item:add
ipcMain.on('item:add',(e,item)=>{
console.log('item',item); // Here I can read item
mainWindow.webContents.on('did-finish-load',()=>{
mainWindow.webContents.send('item:received',item)
});
addWindow.close();
})
What should I write in rendererMain to get data as a callback in main window? The main renderer is executed at first run and not when callback is triggered (if I triggered callback with these lines at all).
The did-finish-load event is not what you are looking for. This event is fired once the webpage is loaded, it is emited only once if you stay on the same page.
You have 2 solutions to answer a message received in the main process.
Invoke the message instead of sending it
You should refer to the documentation to learn about invoking the message.
Here is the example from the documentation :
// Renderer process
ipcRenderer.invoke('some-name', someArgument).then((result) => {
// ...
})
// Main process
ipcMain.handle('some-name', async (event, someArgument) => {
const result = await doSomeWork(someArgument)
return result
})
Here is what it should look like in your example :
// Renderer process
ipcRenderer.invoke('item:add', item) // This sends the item to main process and wait for the answer
.then((data) => { // Callback triggered once the result comes back
console.log(data) // Do what you want with the data
})
// Main process
ipcMain.handle('item:add', async (event, item) => {
console.log(item)
return item // Or return whatever you want
})
Send a new message
This is not the best solution since it can become very complexe as the app grows. But you can send a new message from main to renderer :
// app.js file
ipcMain.on('item:add',(e,item)=>{
console.log({item})
if(yourWindow) { // It can throw an error if yourWindow is null or defined
yourWindow.webContents.send('item:received',item)
}
})
In app.js (when data is received from add window input):
// Catch item:add
ipcMain.on('item:add',(e,item)=>{
console.log('item',item); // Here I can read item
mainWindow.send('itemreceived',item)
addWindow.close();
})
In preload.js (outside contextBridge.exposeInMainWorld()):
const { contextBridge, ipcRenderer } = require('electron')
// Set up context bridge between the renderer process and the main process
contextBridge.exposeInMainWorld(
'windowControls',
{
close: () => ipcRenderer.send('windowControls:close'),
maximize: () => ipcRenderer.send('windowControls:maximize'),
minimize: () => ipcRenderer.send('windowControls:minimize'),
add: (data)=> ipcRenderer.send('item:add',data),
}
)
ipcRenderer.on('itemreceived',(event,message)=>{
console.log('item received message',message);
}
Similar example is here: https://gist.github.com/malept/3a8fcdc000fbd803d9a3d2b9f6944612

Why is the variable undefined? - Node - ElectronJs

I am creating an Electron app and I am trying to split my code in different scripts to make it more manageable; however, for some reason one of the variables in my script keeps returning undefined and I can't figure out why. I already checked similar questions here on SO, but did not find an answer.
I have a file called windowManipulation.js and this is part of it:
let signInWindow;
module.exports.createSignInWindow = () => {
signInWindow = new BrowserWindow({
show: false,
width: 1500,
height: 800,
webPreferences: {
nodeIntegration: true
}
});
signInWindow.loadFile(`views/logIn.html`)
signInWindow.once("ready-to-show", () => {
signInWindow.show();
});
signInWindow.on("close", () => {
signInWindow = null;
});
signInWindow.on('crashed', () => {
app.relaunch();
app.exit(0);
})
}
module.exports.closeSignInWindow = () => {
signInWindow.close();
signInWindow = null;
}
Now, when I call the function to create the window it creates it without a problem. But when I call the function to close it, it says that signInWindow is undefined.
Why is it undefined if it was supposed to be set when the signInWindow was created? What am I doing wrong?
It sounds like createSignInWindow and closeSignInWindow are being called from different processes. Being different processes, they each their own memory, and each would execute this file independently. So if you create the window in the main process, and close it from the window process, the window process will not think the variable exists.
So it sounds like you need to use ipcRenderer to communicate from the render to the main process so that it can close the window for you.
It'd be something like:
// renderer
const { ipcRenderer } = require('electron')
ipcRenderer.send('close-signin')
// main
const { ipcMain } = require('electron')
ipcMain.on('close-signin', closeSignInWindow)

Node.js child process isn't receiving stdin unless I close the stdin stream

I'm building a discord bot that wraps a terraria server in node.js so server users can restart the server and similar actions. I've managed to finish half the job, but I can't seem to create a command to execute commands on the terraria server. I've set it to write the command to the stdin of the child process and some basic debugging verifies that it does, but nothing apparently happens.
In the Node.js docs for child process stdin, it says "Note that if a child process waits to read all of its input, the child will not continue until this stream has been closed via end()." This seems likely to be the problem, as calling the end() function on it does actually send the command as expected. That said, it seems hard to believe that I'm unable to continuously send commands to stdin without having to close it.
Is this actually the problem, and if so what are my options for solving it? My code may be found below.
const discordjs = require("discord.js");
const child_process = require("child_process");
const tokens = require("./tokens");
const client = new discordjs.Client();
const terrariaServerPath = "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Terraria\\TerrariaServer.exe"
const terrariaArgs = ['-port', '7777', "-maxplayers", "8", "-world", "test.wld"]
var child = child_process.spawn(terrariaServerPath, terrariaArgs);
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.on('disconnect', () => {
client.destroy();
});
client.on('message', msg => {
if (msg.channel.name === 'terraria') {
var msgSplit = msg.content.split(" ");
if (msgSplit[0] === "!restart") {
child.kill();
child = child_process.spawn(terrariaServerPath, terrariaArgs);
registerStdio();
msg.reply("restarting server")
}
if (msgSplit[0] === "!exec") {
msg.reply(msgSplit[1]);
child.stdin.write(msgSplit[1] + "\n");
child.stdin.end();
}
}
});
client.login(tokens.discord_token);
var registerStdio = function () {
child.stdout.on('data', (data) => {
console.log(`${data}`);
});
child.stderr.on('data', (data) => {
console.error(`${data}`);
});
}
registerStdio();
I was able to solve the problem by using the library node-pty. As near as I can tell, the problem was that the child process was not reading the stdin itself and I was unable to flush it. Node-pty creates a virtual terminal object which can be written to instead of stdin. This object does not buffer writes and so any input is immediately sent to the program.

Resources