Node.js : How to make spawn function synchronous instead of using spawnSync? - javascript

I'm currently using spawnSync and stdio:inherit to get the logs printed on my console. However I'm looking for custom logging to a separate file, in case if anything fails during the spawn.
I'm looking to create a wrapper around
spawn
so that it has following properties :
Synchronous function where output is stored in a variable
View output on the console
Write stdout and stderr to a file
For instance :
const result = spawnSync('ls', [ '-l', '-a' ], { stdio: 'inherit'}); // will print as it's processing
console.log(result.stdout); // will print null
const result = spawnSync('ls', [ '-l', '-a' ], { encoding: 'utf-8' }); // won't print anything
console.log(result.stdout); // will print ls results only on completion
I need result such that it will print while it's processing and write to a file at the same time
Also I'm looking for some strategy or solution from node.js side apart from shell scripting

I guess we can't make all three possible because of the limitation of node.js
As per the documentation
If we are trying to use stdio:'inherit' , we can either redirect output to parent stdout stream or file using
fs.openSync()
Because of the limitation, we can't use custom streams too.

Related

Mongo collection is accessible via mongosh (mongo shell) but not nodejs script

Running the mongod process in the background, in the mongo shell (mongosh), I have the wikipedia database loaded in my database "enwiki". So in the shell, I can just type db.pages.find(), and it will show me some pages from Wikipedia. Similarly, if I call db.getCollectionNames(), it returns ['pages']. db.getCollection("pages").find() also works.
However, if I go to my nodejs script, db.collection("pages").find() has nothing in it.
const MongoClient = require("mongodb").MongoClient;
const url = 'mongodb://localhost:27017/';
const dbName = 'enwiki';
const client = new MongoClient(url, { useUnifiedTopology: true });
client.connect().then(client => {
console.log('Connected successfully to server');
const db = client.db(dbName);
const cursor = db.collection("pages").find();
cursor.forEach(doc => { console.log(doc.plaintext);});
});
Running the above code just prints 'Connected successfully to server' and stops. (It should also print the plaintext of all my Wikipedia articles in my database.)
I'm new to mongo, so I feel like I'm missing something obvious. The database was originally created using dumpster-dive. Calling db.listCollections() returns this in the node debugger:
{ _events: Object,
_eventsCount: 0,
_maxListeners: 'undefined',
parent: Db,
filter: Object,
... }
That object does not contain the pages collection that I am expecting. How do I access the pages collection?
EDIT 1/18/22 (next day): Ran it today not in the debugger and it just worked. For some reason, running db.collection("pages").find() and db.collection("pages").find().limit(1) in the node debugger returns a similarly weird object to the one above. On the other hand, running cursor.forEach(doc => { console.log(doc.plaintext);}); in the node debugger just returns:
{ [[PromiseState]]: 'pending',
[[PromiseResult]]: 'undefined' }
And ends without doing anything else, so I thought it was doing nothing. In my not fully reduced code shown here, I also had a couple of typos within the forEach promise whose errors were getting suppressed.
The above code does work and it just didn't seem like it did. In my case, I think it was a combination of error suppression that I wasn't seeing and this weird node debugger behaviour that led me to believe it wasn't working. I would love an explanation for why this debugger behaviour is happening and how to avoid/fix it though.

How to write the argument of a function in the terminal with node js

I'm using this code to connect to mailchimp API, get a list of members and put all their email adresses in an array:
var mailchimpMarketing = require("#mailchimp/mailchimp_marketing");
mailchimpMarketing.setConfig({
apiKey: "MY API KEY",
server: "MY SERVER",
});
async function getArrayEmailMembersFromMailchimpListID(listID){
const response = await mailchimpMarketing.lists.getListMembersInfo(listID);
const emailsMailchimp = response.members.map(member => member.email_address);
console.log(emailsMailchimp)
return emailsMailchimp;
}
getArrayEmailMembersFromMailchimpListID("MY LIST ID")
My problem is that I want to write the list ID "MY LIST ID" in my terminal and not in my code when I'm starting the script. Something like that:
$node test.js MyListID
Instead of
$node test.js
But I don't know how to do it.
I think it's possible with process.argv or minimist but I don't understand how they work. Can someone explain it to me or is their any other possibility ?
From the Node-JS v8.x documentation:
The process.argv property returns an array containing the command line
arguments passed when the Node.js process was launched. The first
element will be process.execPath. See process.argv0 if access to the
original value of argv[0] is needed. The second element will be the
path to the JavaScript file being executed. The remaining elements
will be any additional command line arguments.
So in your case you can simply do:
getArrayEmailMembersFromMailchimpListID(process.argv[2])
Of course you should add some error-handling for this to make it more robust.

How can i create an array as a database with JSON files and use Javascript to update / save it

I am making a discord bot in Node.js mostly for fun to get better at coding and i want the bot to push a string into an array and update the array file permanently.
I have been using separate .js files for my arrays such as this;
module.exports = [
"Map: Battlefield",
"Map: Final Destination",
"Map: Pokemon Stadium II",
];
and then calling them in my main file. Now i tried using .push() and it will add the desired string but only that one time.
What is the best solution to have an array i can update & save the inputs? apparently JSON files are good for this.
Thanks, Carl
congratulations on the idea of writing a bot in order to get some coding practice. I bet you will succeed with it!
I suggest you try to split your problem into small chunks, so it is going to be easier to reason about it.
Step1 - storing
I agree with you in using JSON files as data storage. For an app that is intended to be a "training gym" is more than enough and you have all the time in the world to start looking into databases like Postgres, MySQL or Mongo later on.
A JSON file to store a list of values may look like that:
{
"values": [
"Map: Battlefield",
"Map: Final Destination",
"Map: Pokemon Stadium II"
]
}
when you save this piece of code into list1.json you have your first data file.
Step2 - reading
Reading a JSON file in NodeJS is easy:
const list1 = require('./path-to/list1.json');
console.log(list.values);
This will load the entire content of the file in memory when your app starts. You can also look into more sophisticated ways to read files using the file system API.
Step3 - writing
Looks like you know your ways around in-memory array modifications using APIs like push() or maybe splice().
Once you have fixed the memory representation you need to persist the change into your file. You basically have to write it down in JSON format.
Option n.1: you can use the Node's file system API:
// https://stackoverflow.com/questions/2496710/writing-files-in-node-js
const fs = require('fs');
const filePath = './path-to/list1.json';
const fileContent = JSON.stringify(list1);
fs.writeFile(filePath, fileContent, function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
});
Option n.2: you can use fs-extra which is an extension over the basic API:
const fs = require('fs-extra');
const filePath = './path-to/list1.json';
fs.writeJson(filePath, list1, function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
});
In both cases list1 comes from the previous steps, and it is where you did modify the array in memory.
Be careful of asynchronous code:
Both the writing examples use non-blocking asynchronous API calls - the link points to a decent article.
For simplicity sake, you can first start by using the synchronous APIs which is basically:
fs.writeFileSync
fs.writeJsonSync
You can find all the details into the links above.
Have fun with bot coding!

Stream a command's response up to node

I'm trying to make a node package which executes a permanent script that keeps printing data and passes it to a package caller.
I use the exec object, in order to call this command:
var exec = require('child_process').exec;
// ...
exec("script always", function(error, stdout, stderr) {
if (error instanceof Error) {
throw error;
}
// here's where everything gets messy
if(callback)
callback(stream)
});
This command keeps printing data until I stop it. Now, how could I stream this console output to a node event another wants to implement? I've been reading about the Readable stream, but I don't know how to tie it all together (actually, heh, they have the function getReadableStreamSomehow() for the sake of the examples).
You should use spawn, not exec, as described here. This will return an object where you have direct access to the program's streams, so you can easily pipe them, e.g., or subscribe to their data events.
See this example for a sample on how to capture output of the curl command.
Hope this helps :-)

Can't seem to save the output of a client.shell() command to a variable

I am using node-webkit and ADBkit to attempt to read a line from an android build.prop and do something depending on what that line is.
full script at http://pastebin.com/7N7t1akk
The gist of it is this:
var model = client.shell(devices, "su -c 'grep ro.product.model /system/build.prop'" );
alert(model)
i want to read ro.product.model from build.prop into the variable model
As a test im simply attempting to create an alert that displays the return of this shell command, in my case ro.product.model=KFSOWI but whenever i run this script with a connected device the alert returns object Object
edit**
Ive just realized that client.getProperties(serial[, callback]) would probably work better but dont understand these functions (specifically callback) very well
I am very new to this area of Javascripting and home someone can offer some insight
JavaScript is asynchronous programming language, it is built on callbacks. Every function should have callback with data passed to it, if you will watch on documentation, you have client.shell(serial, command[, callback]) so data from executing client.shell() will be passed to callback. You should assign some function that will process callback, for your case will be this
client.shell(devices, "su -c 'grep ro.product.model /system/build.prop'", function(data) {
console.log(data);
});
P.S. there is no alert in nodejs
According to the documentation, you can catch the output in the 2nd argument of client.shell()'s callback:
client.shell(devices, "su -c 'grep ro.product.model /system/build.prop'", function(err, output) {
if (err) {
console.log(err);
}
console.log(output);
});
Use async / await for clearer code.
const data = await client.shell(devices, "su -c 'grep ro.product.model /system/build.prop'" );
console.log(data); // => "Samsung.TM395"
Of course, this only will work if this code is in an async function.
Streamed data.
For streamed data with adbkit, you will need to do a little more to read the entire stream and then output the results, like so:
const stream = await adbClient.shell( config.udid, "ime list -s" ) // adb command to list possible input devices (e.g. keyboards, etc.).
const result = await adb.util.readAll( stream );
console.log( result.toString() ); // => com.sec.android.inputmethod/.SamsungKeypad

Categories