I am currently developping a application in Node-js to launch process throught ssh2. So i use two librairies. Th first one is ssh2 and the second is ssh2-promise. The issue is how I can send an abort signal to my process. I don't understand how I can make this with this two librairies. I can close the socket but the application will continue and I didn't get the PID.
So I try the code below. It launch my process but I can't stop it.
async function sendCommand(commandString) {
let socket = await sshPromise.spawn(commandString);
process.push(socket);
socket.on('data', function (data) {
console.log(data);
});
console.log('Socket push in process array', process);
await sleep(2000);
stopFunctionSocket();
}
function stopFunctionSocket() {
process.forEach( function(socket) {
socket.on('exit', function () {
console.log('Process killed');
});
});
}
sendCommand('sipp/sipp -sn uas 127.0.0.1').then(
result => {
console.log(result);
}
);
I have my output but now, how I can abort the process ?
Thanks a lot.
We can do like this ,
function getWithCancel(url, token) { // the token is for cancellation
var xhr = new XMLHttpRequest;
xhr.open("GET", url);
return new Promise(function(resolve, reject) {
xhr.onload = function() { resolve(xhr.responseText); });
token.cancel = function() { // SPECIFY CANCELLATION
xhr.abort(); // abort request
reject(new Error("Cancelled")); // reject the promise
};
xhr.onerror = reject;
});
};
Which would let you do:
var token = {};
var promise = getWithCancel("/someUrl", token);
// later we want to abort the promise:
token.cancel();
EXPLANATION
You have several alternatives:
Use a third party library like bluebird who can move a lot faster than the spec and thus have cancellation as well as a bunch of other goodies - this is what large companies like WhatsApp do
Pass a cancellation token.
Using a third party library is pretty obvious. As for a token, you can make your method take a function in and then call it, as such:
Try to use this:
socket.kill()
See https://github.com/sanketbajoria/ssh2-promise/blob/bd573d2849a78ebd8315512449f4bd588df3b598/src/sshConnection.ts#L127
Related
I'm trying to make my own google action and I want to call an external api to get responses.
Here is my code:
const { conversation } = require('#assistant/conversation');
const functions = require('firebase-functions');
const app = conversation({debug:true});
const https = require('https');
app.handle('Tester', conv => {
// Implement your code here
conv.add("ok it works");
});
app.handle('Tester2', conv => {
// Implement your code here
let url = 'https://jsonplaceholder.typicode.com/users?_limit=2';
//const url = "https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22";
http_req(url).then((message)=> {
console.log(message[0].name);
conv.add(message[0].name);
//return Promise.resolve();
});
});
function http_req(url) {
return new Promise((resolve, reject) => {
https.get(url, function(resp) {
var json = "";
resp.on("data", function(chunk) {
//console.log("received JSON response: " + chunk);
json += chunk;
});
resp.on("end", function() {
let jsonData = JSON.parse(json);
console.log(jsonData[0].name);
resolve(jsonData);
});
}).on("error", (err) => {
reject("Error: " + err.message);
});
});
}
exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);
The logs:
Error text:
Error: Response has already been sent. Is this being used in an async call that was not returned as a promise to the intent handler?
The problem is that the assistant won't say the conv.add(message[0].name); (obviusly it has a value)
Thanks in advance!
Thanks to a reddit user
https://www.reddit.com/r/GoogleAssistantDev/comments/lia5r4/make_http_get_from_fulfillment_in_nodejs/gn23hi3?utm_source=share&utm_medium=web2x&context=3
This error messages tells you just about all you need to know! Your
call to con.add() is indeed being used in an asynchronous call (the
callback chained to the Promise you created from http_req), and you
are indeed not returning that Promise.
Here's what's happening:
Google calls your 'Tester2' handler
You start an asynchronous HTTP request via http_req, encapsulated in a
Promise
Your function completes before the HTTP request does
Google sees that you are not returning anything from your handler and
assumes that you're done, so it sends the Response
The HTTP request finishes and its Promise resolves, calling your code
attached by the then() function
The simple solution here is to return the Promise created by your
http_req(...).then(...) code, so Google will know that you're not just
quite done, and it should wait for that Promise to resolve before
sending the Response.
If you can use async/await it becomes a bit clearer:
app.handle('Tester2', async conv => {
// Implement your code here
let url = 'https://jsonplaceholder.typicode.com/users?_limit=2';
//const url = "https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22";
const message = await http_req(url);
console.log(message[0].name);
conv.add(message[0].name);
});
I would like to test my simple API that has /groups URL.
I want to make an API request to that URL (using Axios) before all tests begin and make the response visible to all test functions.
I am trying to make the response visible but not able to make it work. I followed a similar case with filling out the DB upfront but no luck with my case.
My simple test file below:
var expect = require('chai').expect
var axios = require('axios')
var response = {};
describe('Categories', function() {
describe('Groups', function() {
before(function() {
axios.get(config.hostname + '/groups').then(function (response) {
return response;
})
});
it('returns a not empty set of results', function(done) {
expect(response).to.have.length.greaterThan(0);
done();
})
});
});
I tried also a sligh modification of before function:
before(function(done) {
axios.get(config.hostname + '/groups')
.then(function (response) {
return response;
}).then(function() {
done();
})
});
but no luck too.
The error I am getting is simply that response isn't changing nor is visible within it. AssertionError: expected {} to have property 'length'
Summarising: How can I pass response from axios inside to in()?
Your first form is incorrect, because you're not returning the chained promise. As such, mocha has no way of knowing when your before is finished, or even that it's async at all. Your second form will solve this problem, but since axios.get already returns a promise, it's kind of a waste not to use mocha's built-in promise support.
As for making the response visible in the it, you need to assign it to a variable in a scope that will be visible within the it.
var expect = require('chai').expect
var axios = require('axios')
var response;
describe('Categories', function() {
describe('Groups', function() {
before(function() {
// Note that I'm returning the chained promise here, as discussed.
return axios.get(config.hostname + '/groups').then(function (res) {
// Here's the assignment you need.
response = res;
})
});
// This test does not need the `done` because it is not asynchronous.
// It will not run until the promise returned in `before` resolves.
it('returns a not empty set of results', function() {
expect(response).to.have.length.greaterThan(0);
})
});
});
I'm looking for a solution to waiting for an event to happen before sending a HTTP response.
Use Case
The idea is I call a function in one of my routes: zwave.connect("/dev/ttyACM5"); This function return immediately.
But there exists 2 events that notice about if it succeed or fail to connect the device:
zwave.on('driver ready', function(){...});
zwave.on('driver failed', function(){...});
In my route, I would like to know if the device succeed or fail to connect before sending the HTTP response.
My "solution"
When an event happen, I save the event in a database:
zwave.on('driver ready', function(){
//In the database, save the fact the event happened, here it's event "CONNECTED"
});
In my route, execute the connect function and wait for the event to
appear in the database:
router.get('/', function(request, response, next) {
zwave.connect("/dev/ttyACM5");
waitForEvent("CONNECTED", 5, null, function(){
response.redirect(/connected);
});
});
// The function use to wait for the event
waitForEvent: function(eventType, nbCallMax, nbCall, callback){
if(nbCall == null) nbCall = 1;
if(nbCallMax == null) nbCallMax = 1;
// Looking for event to happen (return true if event happened, false otherwise
event = findEventInDataBase(eventType);
if(event){
waitForEvent(eventType, nbCallMax, nbCall, callback);
}else{
setTimeout(waitForEvent(eventType, callback, nbCallMax, (nbCall+1)), 1500);
}
}
I don't think it is a good practice because it iterates calls over the database.
So what are your opinions/suggestions about it?
I've gone ahead and added the asynchronous and control-flow tags to your question because at the core of it, that is what you're asking about. (As an aside, if you're not using ES6 you should be able to translate the code below back to ES5.)
TL;DR
There are a lot of ways to handle async control flow in JavaScript (see also: What is the best control flow module for node.js?). You are looking for a structured way to handle it—likely Promises or the Reactive Extensions for JavaScript (a.k.a RxJS).
Example using a Promise
From MDN:
The Promise object is used for asynchronous computations. A Promise represents a value which may be available now, or in the future, or never.
The async computation in your case is the computation of a boolean value describing the success or failure to connect to the device. To do so, you can wrap the call to connect in a Promise object like so:
const p = new Promise((resolve) => {
// This assumes that the events are mutually exclusive
zwave.connect('/dev/ttyACM5');
zwave.on('driver ready', () => resolve(true));
zwave.on('driver failed', () => resolve(false));
});
Once you have a Promise representing the state of the connection, you can attach functions to its "future" value:
// Inside your route file
const p = /* ... */;
router.get('/', function(request, response, next) {
p.then(successful => {
if (successful) {
response.redirect('/connected');
}
else {
response.redirect('/failure');
}
});
});
You can learn more about Promises on MDN, or by reading one of many other resources on the topic (e.g. You're Missing the Point of Promises).
Have you tried this? From the look of it, your zwave probably have already implemented an EventEmmiter, you just need to attach a listener to it
router.get('/', function(request, response, next) {
zwave.connect("/dev/ttyACM5");
zwave.once('driver ready', function(){
response.redirect(/connected);
});
});
There is a npm sync module also. which is used for synchronize the process of executing the query.
When you want to run parallel queries in synchronous way then node restrict to do that because it never wait for response. and sync module is much perfect for that kind of solution.
Sample code
/*require sync module*/
var Sync = require('sync');
app.get('/',function(req,res,next){
story.find().exec(function(err,data){
var sync_function_data = find_user.sync(null, {name: "sanjeev"});
res.send({story:data,user:sync_function_data});
});
});
/*****sync function defined here *******/
function find_user(req_json, callback) {
process.nextTick(function () {
users.find(req_json,function (err,data)
{
if (!err) {
callback(null, data);
} else {
callback(null, err);
}
});
});
}
reference link: https://www.npmjs.com/package/sync
I'm trying to find a way to do what is shown in the diagram below with Node.js. Is it even possible?
Basically, I need to put an http request to wait for a signal from another http request in order to finish.
According to this you can provide a callback to an http request which you could use to finish the request to your server.
My two cents; try the following code, although it's not properly structured it should do the trick. You can call /first in different tabs multiple times and refresh /second to see them responding one by one.
var http = require('http'),
Promise = require('promise');
var queue = [];
function handleRequest(request, response) {
switch (request.url) {
case "/first":
new Promise(function (resolve) {
var guid = 'some-guid';
// enqueue in redis or whatever you like and save the guid to match later.
queue.push({
data: guid,
resolve: resolve
});
}).then(function () {
response.end('1st finished');
});
break;
case "/second":
// queue consumer calls this (probably with the guid parameter)
queue.length && queue.some(function (item) {
if (item.data === 'some-guid') {
item.resolve();
}
});
response.end();
break;
default:
response.end('call /first, then /second');
break;
}
}
var server = http.createServer(handleRequest);
server.listen(8080, function () {
console.log("Server listening on: http://localhost:%s", 8080);
});
I have been playing with Node.js for some time.
I have the following piece of script in my server:
socket.on('auth', function(uid, key) {
client.hgetall(uid, function (err, data) {
console.log(data);
if(key != data['key']) {
socket.disconnect();
}
this.user = data;
});
});
socket.on('loginGame', function(gameId) {
checkAuth();
console.log(user);
if(!games[gameId]) {
games[gameId] = {};
}
games[gameId][uid] = uid;
});
In my client;
socket.on('connect', function(){
socket.emit('auth', 1, 1);
socket.emit('loginGame', 1);
});
When I run this code, loginGame function finishes before auth function as I am doing I/O (using redis). I know this a feature of node.js, but I think I am missing something. How can I overcome this issue as auth function needs to finish before running any function. (I have a couple of more functions which need to run in serial)
I have found a node.js module: https://github.com/creationix/step . However, is this the only option? I think this is something most node.js developer might need. I am not that good at JS either.
What is the best and most elegant way of solving this issue?
Thanks,
Have the server send back an acknowledgement when auth is successful, and send loginGame in the handler for that message.