How to use C++ application in a Node.js server? - javascript

My goal is to use a C++ application in a web server written in JavaScript (such as Node.js).
Do you have a solution for combining the two?

I'm not going to go too much in depth but in this case spawning process would be the "go to" option I guess.
Something like
const fs = require('fs');
const { spawn, exec } = require('child_process');
const logStream = fs.createWriteStream('./logFile.log');
const spawnedProcess = spawn("./some/path/to/executable.exe", [ "-flag1", "-flag2" ]);
// Handle error
spawnedProcess.stderr.pipe(logStream);
// Read data
spawnedProcess.stdout.on('data', data => {
console.log(data);
});
// Handle on exit
spawnedProcess.on('exit', c => {
console.log(`Process closed with code: ${c}`);
});
// Send something to the process (the process has to handle it)
spawnedProcess.stdin.write("some command or whatever\n");
It will widely differ if it's your cpp app so you can implement handling this kind of communication or not. There's still a possibility to write some C++ "proxy" to let this kind of thing work though.
If that won't work for you then let's hope that in some time someone with better idea will share some solution here.

Related

Running stateful commands in PowerShell through Node.js

Context: I have a javascript file that activates PowerShell's native SpeechSynthesizer module. The script receives a message and passes that through to PowerShell, where it is rendered as speech.
Problem: there is horrible latency (~5sec) between execution and response. This is because the script creates an entirely new PowerShell session and SpeechSynthesizer object with every execution.
Objective: I want to change the script so that a single PowerShell session and SpeechSynthesizer object is persisted and used across multiple sessions. I believe this will eradicate the latency completely.
Limiting Factor: this modification requires making the PowerShell execution stateful. Currently, I don't know how to incorporate stateful commands for the PowerShell in a javascript file.
Code:
const path = require('path');
const Max = require('max-api');
const { exec } = require('child_process');
// This will be printed directly to the Max console
Max.post(`Loaded the ${path.basename(__filename)} script`);
const execCommand = command => {
// Max.post(`Running command: ${command}`);
exec(command, {'shell':'powershell.exe'}, (err, stdout, stderr) => {
if (err) {
// node couldn't execute the command
Max.error(stderr);
Max.error(err);
return;
}
// the *entire* stdout and stderr (buffered)
Max.outletBang()
});
}
// Use the 'outlet' function to send messages out of node.script's outlet
Max.addHandler("speak", (msg) => {
let add = 'Add-Type -AssemblyName System.speech'
let create = '\$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer'
let speak = `\$speak.Speak(\'${msg}\')`
let command = ([add,create,speak]).join('; ')
execCommand(command)
});
Objective, Re-stated: I want to move the add and create commands to a 'create' handler which will only be ran once. The speak command will be run an arbitrary amount of times afterward.
Attempted Solution: I've found one package (https://github.com/bitsofinfo/powershell-command-executor) that supposedly supports stateful PowerShell commands, but it's very complicated. Also, the author mentions a risk of command injection and other insecurities, of which I have no knowledge of.
Any and all suggestions are welcome. Thanks!

Does anyone know how to define navigator online in main process in electron?

I know you can use navigator onLine inside the renderer process because it's a rendered inside a browser. But what I'm trying to do is something like this in the main process:
if (navigator.onLine){
mainWindow.loadURL("https://google.com")
} else {
mainWindow.loadFile(path.join(__dirname, 'index.html'));
}
So basically if the user is offline, just load a local html file, and if they're online, take them to a webpage. But, like expected, I keep getting the error that 'navigator is not defined'. Does anyone know how can I somehow import the navigate cdn in the main process? Thanks!
TL;DR: The easiest thing to do is to just ask Electron. You can do this via the net module from within the Main Process:
const { net } = require ("electron");
const isInternetAvailable = () => return net.isOnline ();
// To check:
if (isInternetAvailable ()) { /* do something... */ }
See Electron's documentation on the method; specifically, this approach doesn't tell you whether your service is accessible via the internet, but rather that a service can be contacted (or not even this, as the documentation mentions links which would not involve any HTTP request at all).
However, this is not a reliable measurement and you might want to increase its hit rate by manuallly checking whether a certain connection can be made.
In order to check whether an internet connection is available, you'll have to make a connection yourself and see if it fails. This can be done from the Main Process using plain NodeJS:
// HTTP code basically from the NodeJS HTTP tutorial at
// https://nodejs.dev/learn/making-http-requests-with-nodejs/
const https = require('https');
const REMOTE_HOST = "google.com"; // Or your domain
const REMOTE_EP = "/"; // Or your endpoint
const REMOTE_PAGE = "https://" + REMOTE_HOST + REMOTE_EP;
function checkInternetAvailability () {
return new Promise ((resolve, reject) => {
const options = {
hostname: REMOTE_HOST,
port: 443,
path: REMOTE_EP,
method: 'GET',
};
// Try to fetch the given page
const req = https.request (options, res => {
// Yup, that worked. Tell the depending code.
resolve (true);
req.destroy (); // This is no longer needed.
});
req.on ('error', error => {
reject (error);
});
req.on ('timeout', () => {
// No, connection timed out.
resolve (false);
req.destroy ();
});
req.end ();
});
}
// ... Your window initialisation code ...
checkInternetAvailability ().then (
internetAvailable => {
if (internetAvailable) mainWindow.loadURL (REMOTE_PAGE);
else mainWindow.loadFile (path.join (__dirname, 'index.html'));
// Call any code needed to be executed after this here!
}
).catch (error => {
console.error ("Oops, couldn't initialise!", error);
app.quit (1);
});
Please note that this code here might not be the most desirable since it just "crashes" your app with exit code 1 if there is any error other than connection timeout.
This, however, makes your startup asynchronous, which means that you need to pay attention on the execution chain of your app startup. Also, startup may be really slow in case the timeout is reached, it may be worth considering NodeJS' http module documentation.
Also, it makes sense to actually try to retrieve the page you're wanting to load in the BrowserWindow (constant values REMOTE_HOST and REMOTE_EP), because that also gives you an indication whether your server is up or not, although that means that the page will be fetched twice (in the best case, when the connection test succeeds and when Electron loads the page into the window). However, that should not be that big of a problem, since no external assets (images, CSS, JS) will be loaded.
One last note: This is not a good metric of whether any internet connection is available, it just tells you whether your server answered within the timeout window. It might very well be that any other service works or that the connection just is very slow (i.e., expect false negatives). Should be "good enough" for your use-case though.

Nuxt FingerprintJS Module Server and Client solution?

I using fingerprintJS in NuxtJS+Firebase Projects VuexStore.
When i call that function in client side can get Visitor ID. But i cant get if i use in server side like a nuxtServerInit.
const fpPromise = FingerprintJS.load();
const abc = (async() => {
const fp = await fpPromise
const result = await fp.get()
const visitorId = result.visitorId
return visitorId;
})()
abc.then(
function(value) {
state.visitorId = value
},
function(error) {
return error
}
)
is there a solution to this?
From the NuxtJS documentation (about server rendering):
Because you are in a Node.js environment you have access to Node.js
objects such as req and res. You do not have access to the window or
document objects as they belong to the browser environment. You can
however use window or document by using the beforeMount or mounted
hooks.
FingerprintJS depends heavily (example here) on the browser (hence browser fingerprinting). That means it needs e.g. window object which is not available in the server-side rendering context.
I'm not very experienced with NuxtJS, however, according to the documentation, you should add your fingerprinting code to the .vue file like
if (process.client) {
require('external_library')
}
Good luck!

Identify performance bottlenecks for XSLT transform using Saxon-JS

Can anyone provide some guidance on pinpointing the bottleneck in a transform?
This is a node.js implementation of Saxon-JS. I'm trying to increase the speed of transforming some XML documents so that I can provide a Synchronous API that responds in under 60sec ideally (230sec is the hard limit of the Application Gateway). I need to be able to handle up to 50MB size XML files as well.
I've run node's built profiler (https://nodejs.org/en/docs/guides/simple-profiling/). But it's tough to make sense of the results given that the source code of the free version of Saxon-JS is not really human-readable.
My Code
const path = require('path');
const SaxonJS = require('saxon-js');
const { loadCodelistsInMem } = require('../standards_cache/codelists');
const { writeFile } = require('../config/fileSystem');
const config = require('../config/config');
const { getStartTime, getElapsedTime } = require('../config/appInsights');
// Used for easy debugging the xslt stylesheet
// Runs iati.xslt transform on the supplied XML
const runTransform = async (sourceFile) => {
try {
const fileName = path.basename(sourceFile);
const codelists = await loadCodelistsInMem();
// this pulls the right array of SaxonJS resources from the resources object
const collectionFinder = (url) => {
if (url.includes('codelist')) {
// get the right filepath (remove file:// and after the ?
const versionPath = url.split('schemata/')[1].split('?')[0];
if (codelists[versionPath]) return codelists[versionPath];
}
return [];
};
const start = getStartTime();
const result = await SaxonJS.transform(
{
sourceFileName: sourceFile,
stylesheetFileName: `${config.TMP_BASE_DIR}/data-quality/rules/iati.sef.json`,
destination: 'serialized',
collectionFinder,
logLevel: 10,
},
'async'
);
console.log(`${getElapsedTime(start)} (s)`);
await writeFile(`performance_tests/output/${fileName}`, result.principalResult);
} catch (e) {
console.log(e);
}
};
runTransform('performance_tests/test_files/test8meg.xml');
Example console output:
❯ node --prof utils/runTransform.js
SEF generated by Saxon-JS 2.0 at 2021-01-27T17:10:38.029Z with -target:JS -relocate:true
79.938 (s)
❯ node --prof-process isolate-0x102d7b000-19859-v8.log > v8_log.txt
Files:
stylesheet
Example XML: is test8meg.xml
Node Profiling log v8_log.txt
Snippet of the V8 log of the largest performance offender:
[Bottom up (heavy) profile]:
Note: percentage shows a share of a particular caller in the total
amount of its parent calls.
Callers occupying less than 1.0% are not shown.
ticks parent name
33729 52.5% T __ZN2v88internal20Builtin_ConsoleClearEiPmPNS0_7IsolateE
6901 20.5% T __ZN2v88internal20Builtin_ConsoleClearEiPmPNS0_7IsolateE
3500 50.7% T __ZN2v88internal20Builtin_ConsoleClearEiPmPNS0_7IsolateE
3197 91.3% LazyCompile: *k /Users/nosvalds/Projects/validator-api/node_modules/saxon-js/SaxonJS2N.js:287:264
3182 99.5% LazyCompile: *<anonymous> /Users/nosvalds/Projects/validator-api/node_modules/saxon-js/SaxonJS2N.js:682:218
2880 90.5% LazyCompile: *d /Users/nosvalds/Projects/validator-api/node_modules/saxon-js/SaxonJS2N.js:734:184
Thanks a lot. There aren't a ton of resources on this anymore to walk myself through. I've also already tried:
Using the stylesheetInternal parameter with pre-parsed JSON (didn't make a large difference)
Splitting the document into separate documents that only contain one activities <iati-activity> child element inside the root <iati-activities> root element, transforming each separately, and putting it back together this ended up taking 2x as long.
Best,
Nik
You asked the same question at https://saxonica.plan.io/boards/5/topics/8105?r=8106, and I have responded there. I know StackOverflow doesn't like link-only answers, but I prefer to support users via our own support channels rather than via StackOverflow where possible.

How debug a nodejs API

I've been worked on a vue project.
This vue project use the nodejs API I've created, in simple way, they are two entire differents project which are not located in the same directory and they are launched separately.
The problem is whenever I debug a route with node --inspect --debug-break event_type.controller.js for example named:
"/eventtype/create"
exports.create = (req, res) => {
const userId = jwt.getUserId(req.headers.authorization);
if (userId == null) {
res.status(401).send(Response.response401());
return;
}
// Validate request
if (!req.body.label || !req.body.calendarId) {
res.status(400).send(Response.response400());
return;
}
const calendarId = req.body.calendarId; // Calendar id
// Save to database
EventType.create({
label: req.body.label,
}).then((eventType) => {
Calendar.findByPk(calendarId).then((calendar) => {
eventType.addCalendar(calendar); // Add a Calendar
res.status(201).send(eventType);
}).catch((err) => {
res.status(500).send(Response.response500(err.message));
});
}).catch((err) => {
res.status(500).send(Response.response500(err.message));
});
};
Even if I create a breakpoint on const userId = jwt.getUserId(req.headers.authorization);
and from my vue app I trigger the api createEventType event, my break point is not passed.
Also when I press f8 after the breakpoint on my first line with the debugger, my file close automatically.
I do not use VS Code but Vim for coding but I've heard that maybe Vs Code could allow a simplified way to debug nodesjs application.
NOTE: I use the V8 node debugger.
For newer NodeJS versions (> 7.0.0) you need to use
node --inspect-brk event_type.controller.js
instead of
node --inspect --debug-break event_type.controller.js
to break on the first line of the application code. See https://nodejs.org/api/debugger.html#debugger_advanced_usage for more information.
The solution (even if it's not really a solution) has been to add console.log to the line I wanted to debug.

Categories