I have a node js script that spawns a non-terminating powershell script and listens for data:
node js script:
"use strict";
const cp = require("child_process");
const psData = cp.spawn
("powershell -executionpolicy bypass ./powershell-script.ps1", [], {
shell: "powershell.exe",
serialization: "json",
windowsHide: true,
});
psData.stdout.on("data", function (_data) {
try {
const psObj = JSON.parse(_data);
console.log(psObj);
} catch (e) {
console.error("Failed to Parse JSON!", e);
console.log(_data.toString());
}
});
powershell script:
function getData {
# some irrelevant code +
if ($readData -ne "")
{
$data = [ordered]#{
type = "text";
value = $readData;
}
$data = $data | ConvertTo-Json
Write-Output $data
}
}
while ($true) {
gedData
Start-Sleep -Milliseconds 250
}
The combination works fine up until $data in the ps script goes over a few kb, when that happens it looks like Write-Output splits the data in chunks and after writing each chunk it triggers the 'data' event and therefore
the psData.stdout.on("data",){} in the node script is triggered, so instead of getting a valid JSON file node gets parts of it and throws an error.
I reckon the Write-Output method splits the data, is there a way to increase its buffer size?
Any other ideas?
Thanks!
Related
Is it possible to create a variable in JavaScript and pass it to a batch file?
Just as a simple test echo a variable and move a file up a directory.
JavaScript.js
var s = "Gwen Stefani";
var myFile = "C:\\temp\\myfile.txt"
myBat.execute();
myBat.bat
echo s
move myFile ..
An alternative is to create a string which is saved out as a batch file and then executed, but I was wondering if if it could be done directly.
You can use command line arguments (as you are using exec I suppose this is node.js):
var s = "Gwen Stefani";
var myFile = "C:\\temp\\myfile.txt"
const exec = require('child_process').exec;
const child = exec('cmd /c myBat.bat '+ myFile+' '+s,
(error, stdout, stderr) => {
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
if (error !== null) {
console.log(`exec error: ${error}`);
}
});
or for extendscript:
var s = "Gwen Stefani";
var myFile = "C:\\temp\\myfile.txt";
system.callSystem('cmd /c myBat.bat '+ myFile+' '+s');
and the bat file:
echo %2
move "%~1" ..
(mv is unix command but not from windows shell)
I'm trying to implement iOS push notifications. My PHP version stopped working and I haven't been able to get it working again. However, I have a node.js script that works perfectly, using Apple's new Auth Key. I am able to call that from PHP using:
chdir("../apns");
exec("node app.js &", $output);
However, I would like to be able to pass the deviceToken and message to it. Is there any way to pass parameters to the script?
Here's the script I'm trying to run (app.js):
var apn = require('apn');
var apnProvider = new apn.Provider({
token: {
key: 'apns.p8', // Path to the key p8 file
keyId: '<my key id>', // The Key ID of the p8 file (available at https://developer.apple.com/account/ios/certificate/key)
teamId: '<my team id>', // The Team ID of your Apple Developer Account (available at https://developer.apple.com/account/#/membership/)
},
production: false // Set to true if sending a notification to a production iOS app
});
var deviceToken = '<my device token>';
var notification = new apn.Notification();
notification.topic = '<my app>';
notification.expiry = Math.floor(Date.now() / 1000) + 3600;
notification.badge = 3;
notification.sound = 'ping.aiff';
notification.alert = 'This is a test notification \u270C';
notification.payload = {id: 123};
apnProvider.send(notification, deviceToken).then(function(result) {
console.log(result);
process.exit(0)
});
You can pass parameters as you would pass it to any other script.
node index.js param1 param2 paramN
You can access the arguments through process.argv
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.
exec("node app.js --token=my-token --mesage=\"my message\" &", $output);
app.js
console.log(process.argv);
/*
Output:
[ '/usr/local/bin/node',
'/your/path/app.js',
'--token=my-token',
'--mesage=my message' ]
*/
You can use minimist to parse the arguments for you:
const argv = require('minimist')(process.argv.slice(2));
console.log(argv);
/*
Output
{
_: [],
token: 'my-token',
mesage: 'my message'
}
*/
console.log(argv.token) //my-token
console.log(argv.message) //my-message
After a lot of work, I have a solution. I am using a local web UI to send and receive data to/from Arduino
using AJAX, the php script is:
<?php
/**
* It is already not necessary to go to Device Manager> Ports (COM & LPT)>Arduino XXX (COMXX)>right, NO, the script PruebaCOMRetrieve.bat detect the COM port Arduino is connected to.
* click>Properties>
* Port Settings>Advanced>uncheck "use FIFO buffers ........."
* In other hand, remeber that the Tx speed has to be the same in writeandread.js as in
* Arduino sketch and in the COM
* properties in Device manager, I selected 115200 b/s.
*
*/
$t = $_POST['text1'];
include 'PruebaBatchCOM.php';
$puerto = escapeshellarg($usbCOM);
$dato = escapeshellarg($t);
exec("node C:\\xampp\\htdocs\\DisenoWEBTerminados\\BatteryTesterFinal\\Scripts\\writeandread.js
{$puerto} {$dato} 2>&1", $output1);
$str = implode($output1);
$str1 = explode(",",$str);
$myJSON = json_encode($str1);
echo $myJSON;
?>
PruebaBatchCOM.php
<?php
$puerto = array();
$file111 = "PruebaCOMRetrieve.bat";
exec($file111, $puerto);
$usbCOM = implode(",",$puerto);
?>
PruebaCOMRetrieve.bat
#echo off
setlocal
for /f "tokens=1* delims==" %%I in ('wmic path win32_pnpentity get caption
/format:list ^| find "Arduino Uno"') do (
call :setCOM "%%~J"
)
:: end main batch
goto :EOF
:setCOM <WMIC_output_line>
:: sets _COM#=line
setlocal
set "str=%~1"
set "num=%str:*(COM=%"
set "num=%num:)=%"
set port=COM%num%
echo %port%
The Node Js script is:
//writeandread.js
var portName = process.argv[2];
var dato = process.argv[3];
var SerialPort = require("serialport");
var Readline = require('#serialport/parser-readline');
var serialport = new SerialPort(portName, { baudRate: 115200 });
// Look for return and newline at the end of each data packet
var parser = serialport.pipe(new Readline({ delimiter: '\n' }));
serialport.on('open', function(err) {
// A timeout is necessary to wait the port to open (if not working, try to
increase the milliseconds value)
setTimeout(function() {
serialport.write(dato);
}, 1700);
if(err) {
console.log('Error when trying to open:' + err);
}
parser.on('data', function(data) {
console.log(data);
serialport.close(function (err) {
if(err){
console.log('port closed', err);
}
});
});
});
serialport.on('close', () => {
console.log('Bye');
});
With this scripts one can send and receive data from Arduino and pass it to AJAX script in the client side and do what one wants. Now I am adding a script to php firt one to detect programmatically the COM port Arduino is connected to.
enjoy.
how should I proceed to create an output like this in bash with nodejs
$ echo “Hello World” > foo.txt //creating the text file
$ ./test < foo.txt // launching the test.js script with the text file as input
Hello World //result
I've tried
test.js
#!/usr/bin/env node
var fs = require('fs');
fs.readFile('how to get foo.txt path enterd as input ?','utf8', function(err, data) {
if(err) throw err;
var array = data.toString().split("\n");
for(i in array) {
console.log(array[i]);
}
});
The script below will read the contents of foo.txt into the chunks variable. When the stream is finished the contents will output to console.
//node thisFile.js foo.txt
//console.log(process.argv) will tell you what the CLI inputs are
fileName = process.argv[2];
input = fs.createReadStream(fileName);
var chunks = '';
input.on('data' , function(data){
chunks += data;
});
input.on('end', function(){
console.log('blow ' + chunks);
});
Is this what you're asking?
While building a NNTP client in NodeJS, I have encountered the following problem. When calling the XZVER command, the first data I receive from the socket connection contains both a string and an inflated string;
224 compressed data follows (zlib version 1.2.3.3)
^*�u�#����`*�Ti���d���x�;i�R��ɵC���eT�����U'�|/S�0���� rd�
z�t]2���t�bb�3ѥ��>�͊0�ܵ��b&b����<1/ �C�<[<��d���:��VW̡��gBBim�$p#I>5�cZ�*ψ%��u}i�k�j
�u�t���8�K��`>��im
When I split this string and try to inflate it like this;
lines = chunk.toString().split('\r\n');
response = lines.shift();
zlib.inflate(new Buffer(lines.shift()), function (error, data) {
console.log(arguments);
callback();
});
I receive the following error;
[Error: invalid code lengths set] errno: -3, code: 'Z_DATA_ERROR'
Any help is welcome, I am kinda stuck here :(
UPDATE
After implementing the answer of mscdex, the whole function looks like this;
var util = require('util'),
zlib = require('zlib'),
Transform = require('stream').Transform;
function CompressedStream () {
var self = this;
this._transform = function (chunk, encoding, callback) {
var response = chunk.toString(),
crlfidx = response.indexOf('\r\n');
response = response.substring(0, crlfidx);
console.log(response);
zlib.gunzip(chunk.slice(crlfidx + 2), function (error, data) {
console.log(arguments);
callback();
});
};
Transform.call(this/*, { objectMode: true } */);
};
util.inherits(CompressedStream, Transform);
module.exports = CompressedStream;
You should probably avoid using split() in case those two bytes are in the raw data. You might try something like this instead:
var response = chunk.toString(),
crlfidx = response.indexOf('\r\n');
// should probably check crlfidx > -1 here ...
response = response.substring(0, crlfidx);
zlib.inflate(chunk.slice(crlfidx + 2), function (error, data) {
console.log(arguments);
callback();
});
However if you're doing this inside a 'data' event handler, you should be aware that you may not get the data you expect in a single chunk. Specifically you could get a CRLF split between chunks or you could get multiple responses in a single chunk.
It seems that my chunks were incorrectly encoded. By removing socket.setEncoding('utf8');, the problem was solved.
I want to download a zip file from the internet and unzip it in memory without saving to a temporary file. How can I do this?
Here is what I tried:
var url = 'http://bdn-ak.bloomberg.com/precanned/Comdty_Calendar_Spread_Option_20120428.txt.zip';
var request = require('request'), fs = require('fs'), zlib = require('zlib');
request.get(url, function(err, res, file) {
if(err) throw err;
zlib.unzip(file, function(err, txt) {
if(err) throw err;
console.log(txt.toString()); //outputs nothing
});
});
[EDIT]
As, suggested, I tried using the adm-zip library and I still cannot make this work:
var ZipEntry = require('adm-zip/zipEntry');
request.get(url, function(err, res, zipFile) {
if(err) throw err;
var zip = new ZipEntry();
zip.setCompressedData(new Buffer(zipFile.toString('utf-8')));
var text = zip.getData();
console.log(text.toString()); // fails
});
You need a library that can handle buffers. The latest version of adm-zip will do:
npm install adm-zip
My solution uses the http.get method, since it returns Buffer chunks.
Code:
var file_url = 'http://notepad-plus-plus.org/repository/7.x/7.6/npp.7.6.bin.x64.zip';
var AdmZip = require('adm-zip');
var http = require('http');
http.get(file_url, function(res) {
var data = [], dataLen = 0;
res.on('data', function(chunk) {
data.push(chunk);
dataLen += chunk.length;
}).on('end', function() {
var buf = Buffer.alloc(dataLen);
for (var i = 0, len = data.length, pos = 0; i < len; i++) {
data[i].copy(buf, pos);
pos += data[i].length;
}
var zip = new AdmZip(buf);
var zipEntries = zip.getEntries();
console.log(zipEntries.length)
for (var i = 0; i < zipEntries.length; i++) {
if (zipEntries[i].entryName.match(/readme/))
console.log(zip.readAsText(zipEntries[i]));
}
});
});
The idea is to create an array of buffers and concatenate them into a new one at the end. This is due to the fact that buffers cannot be resized.
Update
This is a simpler solution that uses the request module to obtain the response in a buffer, by setting encoding: null in the options. It also follows redirects and resolves http/https automatically.
var file_url = 'https://github.com/mihaifm/linq/releases/download/3.1.1/linq.js-3.1.1.zip';
var AdmZip = require('adm-zip');
var request = require('request');
request.get({url: file_url, encoding: null}, (err, res, body) => {
var zip = new AdmZip(body);
var zipEntries = zip.getEntries();
console.log(zipEntries.length);
zipEntries.forEach((entry) => {
if (entry.entryName.match(/readme/i))
console.log(zip.readAsText(entry));
});
});
The body of the response is a buffer that can be passed directly to AdmZip, simplifying the whole process.
Sadly you can't pipe the response stream into the unzip job as node zlib lib allows you to do, you have to cache and wait the end of the response. I suggest you to pipe the response to a fs stream in case of big files, otherwise you will full fill your memory in a blink!
I don't completely understand what you are trying to do, but imho this is the best approach. You should keep your data in memory only the time you really need it, and then stream to the csv parser.
If you want to keep all your data in memory you can replace the csv parser method fromPath with from that takes a buffer instead and in getData return directly unzipped
You can use the AMDZip (as #mihai said) instead of node-zip, just pay attention because AMDZip is not yet published in npm so you need:
$ npm install git://github.com/cthackers/adm-zip.git
N.B. Assumption: the zip file contains only one file
var request = require('request'),
fs = require('fs'),
csv = require('csv')
NodeZip = require('node-zip')
function getData(tmpFolder, url, callback) {
var tempZipFilePath = tmpFolder + new Date().getTime() + Math.random()
var tempZipFileStream = fs.createWriteStream(tempZipFilePath)
request.get({
url: url,
encoding: null
}).on('end', function() {
fs.readFile(tempZipFilePath, 'base64', function (err, zipContent) {
var zip = new NodeZip(zipContent, { base64: true })
Object.keys(zip.files).forEach(function (filename) {
var tempFilePath = tmpFolder + new Date().getTime() + Math.random()
var unzipped = zip.files[filename].data
fs.writeFile(tempFilePath, unzipped, function (err) {
callback(err, tempFilePath)
})
})
})
}).pipe(tempZipFileStream)
}
getData('/tmp/', 'http://bdn-ak.bloomberg.com/precanned/Comdty_Calendar_Spread_Option_20120428.txt.zip', function (err, path) {
if (err) {
return console.error('error: %s' + err.message)
}
var metadata = []
csv().fromPath(path, {
delimiter: '|',
columns: true
}).transform(function (data){
// do things with your data
if (data.NAME[0] === '#') {
metadata.push(data.NAME)
} else {
return data
}
}).on('data', function (data, index) {
console.log('#%d %s', index, JSON.stringify(data, null, ' '))
}).on('end',function (count) {
console.log('Metadata: %s', JSON.stringify(metadata, null, ' '))
console.log('Number of lines: %d', count)
}).on('error', function (error) {
console.error('csv parsing error: %s', error.message)
})
})
If you're under MacOS or Linux, you can use the unzip command to unzip from stdin.
In this example I'm reading the zip file from the filesystem into a Buffer object but it works
with a downloaded file as well:
// Get a Buffer with the zip content
var fs = require("fs")
, zip = fs.readFileSync(__dirname + "/test.zip");
// Now the actual unzipping:
var spawn = require('child_process').spawn
, fileToExtract = "test.js"
// -p tells unzip to extract to stdout
, unzip = spawn("unzip", ["-p", "/dev/stdin", fileToExtract ])
;
// Write the Buffer to stdin
unzip.stdin.write(zip);
// Handle errors
unzip.stderr.on('data', function (data) {
console.log("There has been an error: ", data.toString("utf-8"));
});
// Handle the unzipped stdout
unzip.stdout.on('data', function (data) {
console.log("Unzipped file: ", data.toString("utf-8"));
});
unzip.stdin.end();
Which is actually just the node version of:
cat test.zip | unzip -p /dev/stdin test.js
EDIT: It's worth noting that this will not work if the input zip is too big to be read in one chunk from stdin. If you need to read bigger files, and your zip file contains only one file, you can use funzip instead of unzip:
var unzip = spawn("funzip");
If your zip file contains multiple files (and the file you want isn't the first one) I'm afraid to say you're out of luck. Unzip needs to seek in the .zip file since zip files are just a container, and unzip may just unzip the last file in it. In that case you have to save the file temporarily (node-temp comes in handy).
Two days ago the module node-zip has been released, which is a wrapper for the JavaScript only version of Zip: JSZip.
var NodeZip = require('node-zip')
, zip = new NodeZip(zipBuffer.toString("base64"), { base64: true })
, unzipped = zip.files["your-text-file.txt"].data;