Spawning Ruby from Node.js - How to require within the Ruby file? - ruby

I have succesfully spawn a ruby script from my node application. However, in my Ruby script I would like to require some gems and files, and it seems that when doing a require, node.js doesn't get any response.
Here is how this looks:
var cp = require('child_process')
var ruby_child = cp.spawn('ruby',['libs/scorer/test.rb']);
var result = '';
ruby_child.stdout.on('data', function(data) {
result += data.toString();
});
ruby_child.on('close', function() {
console.log(result);
});
And my Ruby script looks like this:
require 'utils' # if I remove this line, I can get the response.
# Does it have an argument?
if ARGV.nil? || ARGV.empty?
p 'test'
exit
end

That's probably the require line failed. The Ruby program sent some error status to STDERR and then exited, and your js program didn't capture STDERR output.
Add some STDERR capture code in your js program for diagnostic information of your problem. You may probably found that the Ruby cannot find the required library in $LOAD_PATH.
ruby_child.stderr.on('data', function(data) {
console.log("ERROR --- " + data);
});

Related

How to download file directly from blob URL?

I am looking to download a PDF directly from a blob URL using Ruby code. The URL appears like this:
blob:https://dev.myapp.com/ba853441-d1f7-4595-9227-1b0e445b188b
I am able to visit the link in a web browser and have the PDF appear in a new tab. On inspection, other than the GET request there are some request headers related to browser/user agent.
I've attempted to use OpenURI but it detects the url as not an HTTP URI. Open URI works just fine with files from URLs that look like https://.../invoice.pdf
I've also tried to go the JS route with this snippet but this is returning 0 for me, as others have also reported.
Any automated solutions that require a download onClick and then navigating the local disk is not sufficient for my project. I am looking to retrieve files directly from the URL in the same fashion that OpenURI works for a file on a server. Thanks in advance.
I was able to get the Javascript snippet to work. The piece that I was missing was that the blob URL needed to be opened/visited in the browser first (in this case, Chrome). Here's a code snippet that might work for others.
def get_file_content_in_base64(uri)
result = page.evaluate_async_script("
var uri = arguments[0];
var callback = arguments[1];
var toBase64 = function(buffer){for(var r,n=new Uint8Array(buffer),t=n.length,a=new Uint8Array(4*Math.ceil(t/3)),i=new Uint8Array(64),o=0,c=0;64>c;++c)i[c]='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charCodeAt(c);for(c=0;t-t%3>c;c+=3,o+=4)r=n[c]<<16|n[c+1]<<8|n[c+2],a[o]=i[r>>18],a[o+1]=i[r>>12&63],a[o+2]=i[r>>6&63],a[o+3]=i[63&r];return t%3===1?(r=n[t-1],a[o]=i[r>>2],a[o+1]=i[r<<4&63],a[o+2]=61,a[o+3]=61):t%3===2&&(r=(n[t-2]<<8)+n[t-1],a[o]=i[r>>10],a[o+1]=i[r>>4&63],a[o+2]=i[r<<2&63],a[o+3]=61),new TextDecoder('ascii').decode(a)};
var xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.onload = function(){ callback(toBase64(xhr.response)) };
xhr.onerror = function(){ callback(xhr.status) };
xhr.open('GET', uri);
xhr.send();
", uri)
if result.is_a? Integer
fail 'Request failed with status %s' % result
end
return result
end
def get_pdf_from_blob
yield # Yield to whatever Click actions that trigger the file download
sleep 3 # Wait for direct download to complete
visit 'chrome://downloads'
sleep 3
file_name = page.text.split("\n")[3]
blob_url = page.text.split("\n")[4]
visit blob_url
sleep 3 # Wait for PDF to load
base64_str = get_file_content_in_base64(blob_url)
decoded_content = Base64.decode64(base64_str)
file_path = "./tmp/#{file_name}"
File.open(file_path, "wb") do |f|
f.write(decoded_content)
end
return file_path
end
From here you can send file_path to S3, send to PDF Reader, etc.

CasperJS test doesn't return after execution

I'm having a problem getting casperjs test to exit after execution, I have to hit CTL-C to exit execution. I'm on OSX 10.7 with casperjs 1.1 devel.
To test this wasn't my code I simply copied this sample from the docs:
var casper = require("casper").create();
function Cow() {
this.mowed = false;
this.moo = function moo() {
this.mowed = true; // mootable state: don't do that at home
return 'moo!';
};
}
casper.test.begin('Cow can moo', 2, function suite(test) {
var cow = new Cow();
test.assertEquals(cow.moo(), 'moo!');
test.assert(cow.mowed);
test.done();
});
And I get the following output
casperjs test cow-test.js
Test file: cow-test.js
# Cow can moo
PASS Subject equals the expected value
PASS Subject is strictly true
I then have to hit CTL-C to stop execution. Am I missing something to stop execution?
Per https://github.com/n1k0/casperjs/issues/593#issuecomment-23062361, the problem was that I had created a casper instance at the top of the file, which the documentation warns you not to do.
The solution was to remove the var casper = require("casper").create(); line.

How to send control C node.js and child_processes

Hello I want to send to the child_process, for example, ping 8.8.8.8-t, that is, an infinite number of ping. And some of the iterations I want to stop this command and execute a new, but in this case I do not want to kill a child process.
Example:
var spawn = require('child_process').spawn('cmd'),
iconv = require('iconv-lite');
spawn.stdout.on('data', function (data) {
console.log('Stdout: ', iconv.decode(data, 'cp866'));
});
spawn.stderr.on('data', function (data) {
console.log('Stderr: ', iconv.decode(data, 'cp866'));
});
spawn.stdin.write('ping 8.8.8.8 -t'+ '\r\n');
spawn.stdin.write(here control-c...); // WRONG
spawn.stdin.write('dir' + '\r\n');
I found your previous question. Looks like you are trying to create/emulate a terminal from within node.js. You can use readline for reading and writing from a terminal.
To write control character, you can see the example from its docs :
rl.write('Delete me!');
// Simulate ctrl+u to delete the line written previously
rl.write(null, {ctrl: true, name: 'u'});
To directly answer the question, to pass special characters you will need to pass their ASCII values. Ctrl + C becomes ASCII character 0x03. Value taken from here.
spawn.stdin.write("\x03");

Node.js: How to send control C to child process

I am writing one web-like linux shell using node.js + socket.io. Simple command like, ls, cd are working well.
But when issue command like ping google.com, the stdout is printing endlessly.
I tried to send Ctrl +C to stdin, but no luck.
1) spawn 'bash' process
spawn = require('child_process').spawn;
var sh = spawn('bash');
2) send bash stdout to socket.io
sh.stdout.on('data', function(data) {
console.log('stdout' + data);
listener.sockets.emit("stdout",new Buffer(data));
});
3) Sending Ctl C (\x03) to bash's stdin.
var listener = io.listen(server);
listener.set('log level',1);
listener.sockets.on('connection', function(client){
client.on('message', function(data){
if(data === "KILL") {
console.log('!!!!' + data);
sh.stdin.write('\x03');
client.broadcast.send(new Buffer("KILLING "));
//return;
};
console.log(data);
sh.stdin.write(data+"\n");
client.broadcast.send(new Buffer("> "+data));
});
});
I am stuck at this point. Seems like
Try process.kill(sh.pid). I use this to kill workers in a cluster when my master process shuts down. sh.signalCode should be equal to SIGTERM. Of course, I have no idea if this works on Windows.
try stdout.push(null).
I tried it on node 12. This will not kill your child process instead it will tell you output stream that there is no more input stream.

pushing tty output to node

For the satisfaction of my curiosity gene i'd like to play with bash/node combo.
I don't know how to make those 2 talk together. I just had a great smile on my face finding about TTY.JS ;-)
How do I feed terminal's output (sdtout?) to node? I thought about redirecting the stream to file and read it with node through 'fs' module. But there must be some prettier way I bet
thanks in advance.
Something like this should send terminal output to node
var app = require('express').createServer(),
io = require('socket.io').listen(app),
sys = require('util'),
exec = require('child_process').exec;
app.listen(4990);
io.sockets.on('connection', function(socket) {
socket.on('console', function(command, callBack) {
// client sends {command: 'ls -al'}
function puts(error, stdout, stderr) {
socket.emit('commandresult', stdout);
}
exec(command.command, puts);
});
});​
Hope this helps

Resources