Start Electron/Node.JS app and pass command line args from C# - javascript

I have a C# application which launches an Electron app (node.js). I'm attempting to pass a command line argument to the Node.JS application but when I access process.argv from within index.js the argument isn't there. Is there anything specific I should be doing to retrieve this argument from within my node application?
Process process = new Process();
process.StartInfo.FileName = pathToEXE;
process.StartInfo.Arguments = argument;
process.EnableRaisingEvents = true;
process.Start();

Basically process.argv array returns 2 values which are installed location and file opening path. So first of all you should assign those values in global object in main.js as below,
global.sharedObject = { installedLocation: process.argv[0], openFilePath:
process.argv[1]}
and access this in your index.js as below,
var remote = require('electron').remote;
var location = remote.getGlobal('sharedObject').installedLocation;
var filePath = remote.getGlobal('sharedObject').openFilePath;

Related

Show a variable from one JS file to another JS file

I have a node.js controller that create a csv file and it is stored in a specific folder, there is also a value from a var called endpoint.
The thing is that in the end of the lines of the controller i have this start function to start another process in another javascript file called bot.js
const scrapeWebsite = require('../bot')
const start = new scrapeWebsite();
var endpoint ="192.186.1.1"
try {
start.init();
} catch (e) {
res.send(JSON.stringify(e, null, 5))
}
In the bot.js file i want to access the value of the endpoint variable of my controller.js to use it in the bot function process and i dont know how to do this.
like declare a new var in the bot.js with the same value as the endpoint in the controller.js
class scrapeWebsite {
init() {
this.startScrape()
}
async startScrape() {...}
Export that function from bot.js
module.exports.function_name = function_name
And when you want to run it in node.js controller, import it using
const {function_name} = require("../bot")
And when you want to execute that function, call that function
function_name(<with, arguments, from, bot.js, file>)

Electron: Windows alternative for app.on 'open-file'

I am building an Electron app for editing .txt files on a windows computer. I have used electron builders fileAssociations to open .txt files however I cannot get the path of the file. When I looked in the Electron docs I found this which is exactly what I want except it is mac-only... is there a way to get the same functionality on Windows?
As Lucas Roland mentioned, you have to parse process.argv to get the filepath
if (process.argv.length >= 2) { // or electron.remote.process.argv
let filePath = process.argv[1];
//open, read, handle file
}
On Windows, you have to parse process.argv (in the main process) to
get the filepath.
from https://github.com/electron/electron/blob/master/docs/api/app.md#event-open-file-macos
On Windows, you need to use process.argv in the main process to read the file path. According to this answer, you can use the fs package to open, read & write files. There are a few more ways described to do the same thing.
Also, the following snippet from this blog post might be helpful.
How to configure your app to open linked files in Windows
On Windows, you have to parse process.argv to get the file path.
Then, you can use the IPC module to handle messages from the renderer process (web page) and retrieve a datastore from a file. This is how we did it:
In the main process:
var ipc = require('ipc');
var fs = require('fs');
// read the file and send data to the render process
ipc.on('get-file-data', function(event) {
var data = null;
if (process.platform == 'win32' && process.argv.length >= 2) {
var openFilePath = process.argv[1];
data = fs.readFileSync(openFilePath, 'utf-8');
}
event.returnValue = data;
});
I am not very well versed with electron, else I would have tried to give you a better answer, but this is what I could find with my understanding about it. I hope this helps!
For windows, parsing process.argv on app ready worked for me. So in the main process somewhere:
const { app } = require('electron');
const devEnv = /electron/.test(process.argv[0]);
app.on('ready', () => {
if (process.platform.startsWith('win') && !devEnv && process.argv.length >= 2) {
const filePath = process.argv[1];
// In my app, I initialise a new window here and send filePath through
// to the renderer process so it can be read and displayed.
} else {
// Create whatever your default window is (in my case, an empty document)
}
});
On windows, this event is fired every time you open a new file even if another file is already open in the application.
Remember also that during development, we launch the application with electron . or electron . --debug or something similar. Because of this, I also test whether the first argument is electron and skip over file opening logic in this case (the case that devEnv evaluates to 'true').
The best alternative that I have found for this problem is using second-instance event on the app module with process.argv.
When a user clicks a file associated with your app, on Windows (yeah! I only tried it on Windows), it will try to open a new instance of the app with the path of the related file inside process.argv. If you are not using multiple instances of the app, then you should prevent the app from opening multiple instances of the app and try to fetch the data (mainly the process.argv) to the main instance using the second-instance event from the app module.
First, you should get the singleInstanceLock from app.requestSingleInstanceLock() to make the current instance the only instance of the app. This will return a boolean. If it returns false, this means that another instance has the singleInstanceLock. Then you should close that instance using app.quit().
// Behaviour on second instance for parent process
const gotSingleInstanceLock = app.requestSingleInstanceLock();
if (!gotSingleInstanceLock) app.quit(); // Quits the app if app.requestSingleInstanceLock() returns false.
If the boolean is true, then this means the current app session is the main session of the app.
Then we should use the second-instance event of the app module to detect second instances from that point onwards. If another instance emerges, it will be closed, but second-instance event will be fired with the relevant arguments needed to identify what opened that instance to the process.argv. The second parameter of the callback added to the second-instance event can be used to get those arguments sent to that instance. From that point onwards, you can filter the strings inside the process.argv and get the relevant path of the file that opened the other instance.
// Behaviour on the second instance for the parent process
const gotSingleInstanceLock = app.requestSingleInstanceLock();
if (!gotSingleInstanceLock) app.quit();
else {
app.on('second-instance', (_, argv) => {
//User requested a second instance of the app.
//argv has the process.argv arguments of the second instance.
if (app.hasSingleInstanceLock()) {
if (mainWindow?.isMinimized()) mainWindow?.restore();
mainWindow?.focus();
process.argv = argv; // I tried to add the argv from the second instance to my main instance.
}
});
}
Please keep in mind that arguments in process.argv will be added differently when the app is packaged. Therefore, you should loop through the arguments and check whether an argument is a path in the system using the stat() function in the fs module and if it has the .txt extension at the end using the path.extname()
I found this method the hard way, so I hope that anyone with this problem wouldn't have to go through all of that.

node.js dynamic module(file) export

how can I exports this dynamic module?
// ./data/example5.js
module.exports = {title : example5, recentCheck : "2018-08-22"}
The contents change in real time. And I execute the followed function once a minute and connect the module.
var files = fs.readdirSync(`./data/`);
var i = 0;
var link = [];
while(i<files.length){ // read all file
link[i] = require(`../data/${files[i]}`);
 
//main.js
setInterval(start,10000);
I try to create and connect a new module file once a minute, but the first stored file(module) is extracted. The modulefile is being saved in real time correctly.
Shutting down and running the node will extract the changed modules correctly.
How do I handle a dynamically changing module?
I would recommend saving the data in a JSON file and then reading the data from the file rather than trying to use it as a module.
Just make the objects you're updating variables in the module that you're including.
Make a function called getVariable, and simply return the variable.
Include getVariable in your main module.

How to get value from modified object in Node.js

how to get modified value of object? index.js is called before index2.js
object.js
var object = {
size:'5'
};
var setSize = function(size) {
object.size = size;
}
exports.object = object;
exports.setSize = setSize;
index.js
var obj = require('path/object');
obj.setSize('10');
console.log(obj.object.size); //--> 10
index2.js
I want the result to be 10.
var obj = require('path/object');
console.log(obj.object.size); //--> 5
If you run node index.js separately from node index2.js, there is no way for index2.js to "know" what happened in the last process of index.js. You have to apply all your actions in a single process run. As #Andrew Li stated in his comment, you would have to require index.js in your index2.js. Simply requiring it, will have it's code executed and the changes to obj.object will be saved in Nodes module caching mechanism.
var obj = require('path/object');
require('./index');
// code inside index.js gets executed, changing obj.size to '10'
// note that this will also log '10' in the console, since a console.log(obj.size)
// is part of your code in index.js
console.log(obj.object.size) //--> 10
If you need to have index.js and index2.js executed in different processes but still be able to access a coherent value of obj, you need to store that value somewhere outside of the process space, like in a database or in the filesystem.

Nodejs set command line argument as constant

I want to get an argv from my command line when I am going to start my server and then I want to set it as a constant for a module.
For example I want to define my log file path from commandline:
My starter.js looks like:
var optimist = require("optimist");
var server = require("./start_server");
var argv = optimist.describe('logpath', 'logptah for info').argv;
server.init({logpath:argv.logpath});
My start_server.js looks like:
var restify = require('restify');
var server = restify.createServer({
name: 'dummy-project'
});
module.exports.logpath = null;
function init(args){
server.listen(1234, function() {
console.log("inside logs");
console.log(args.logpath);
module.exports.logpath = args.logpath;
console.log('%s listening at %s', server.name, server.url);
});
};
module.exports.init = init;
var fun = require('./common/loghandler');
My loghandler.js looks like:
var server = require('./../start_server');
console.log("inside log handler");
var LOGPATH = server.logpath;
console.log(LOGPATH);
When I am running node starter.js --logpath='../../custom/info.txt'
I am not getting the logpath inside my loghandler.
Seems logpath handler is called before the server.listen.
The console output looks like:
node starter.js --logpath='../../custom/info.txt'
inside log handler
null
inside log handler
../../custom/info.txt
dummy-project listening at http://0.0.0.0:1234
How I can overcome it and pass my log path as command line argument?
Thanks in advance.
Your init() function is executed after starter.js uses require('./start_server'). When you use require(), the file and all its dependencies are loaded. That means during this process, you also executed require('./common/loghandler'), which completes before server.init() is run in starter.js. Since server.logpath hasn't been set by this time, you get a null value.
Aside from that, module.exports is set at require time and changing the values later have no effect. To fix the problems you're having, you should avoid using functions before your application has fully loaded, and put return values in your modules.

Categories

Resources