So I have an AngularJS(1) app which essentially runs a server side script when a user clicks a button.
client side controller Angular calls this method when a button is clicked:
$scope.executeDeployScript = function (demo) {
console.log("Starting "+ demo.instanceName);
$scope.clearDeploymentStatus();
$scope.processStarted = true;
$http.get('/api/demoSelect/startDemo', {
params: {
name: demo.instanceName,
path: demo.scriptPath
}
}).success(function (data) {
if (data === "Done") {
$http.get("/api/demoSelect/startDemo/ip", {
params: {
name: demo.instanceName
}
}).success(function (data) {
demo.url = data.replace(/\s/g, '') + ":" + demo.port
$scope.deploymentStatus = data.replace(/\s/g, '') + ":" + demo.port;
$scope.deploymentSuccess = true;
});
} else {
$scope.deploymentStatus = "Demo deployed failed. Try again : " + data;
$scope.deploymentSuccess = false;
}
});
server side route:
app.get("/api/demoSelect/startDemo", function (req, res, next) {
var child;
var demoName = req.query.name;
var demoPath = req.query.path;
var response = "";
console.log("Running boot script for "+ demoName);
child = exec(demoPath + " " + demoName,
function (error, stdout, stderr) {
if (error !== null) {
console.log('exec error!: ' + stderr);
res.send(stderr);
} else {
console.log(stdout);
res.send("Done");
}
});
});
The script takes a long time to complete (a couple minutes) and I noticed that the GET request is being repeated after a couple of minutes which in turn interrupts the currently running script and starts it again. The repeat is only happening server side since none of the angular client side code is being executed again. I am noticing the get request being repeated in the gulp debug output
Is there some time of time-out value I need to adjust for long get requests to prevent them from being repeated? If so, is that something that's handled in Node or Angular?
Any help is appreciated
Related
I am using a modified version of the sample code for Bluetooth device-information using the Web Bluetooth API.
The Bluetooth device was tested independently using NRF Connect app on my iPhone and everything works as intended. I used the UARTService ID as indicated on the NRF Connect app and used it to set OptionalServices. See the following code snippet.
let UARTService = "6e400001-b5a3-f393-e0a9-e50e24dcca9e"
let UARTCharRX = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"
let UARTCharTX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
let options = {};
//options.services = UARTService;
if (document.querySelector('#allDevices').checked) {
options.acceptAllDevices = true;
options.optionalServices = UARTService;
} else {
options.filters = filters;
}
console.log('Requesting Bluetooth Device.........');
console.log('with ' + JSON.stringify(options));
navigator.bluetooth.requestDevice(options)
.then(device => {
console.log('> Name: ' + device.name);
console.log('> Id: ' + device.id);
console.log('> Connected: ' + device.gatt.connected);
return device;
}).then(device => {
return device.gatt.connect();
}).then(function (server) {
console.log("Connected ? " + server.connected);
return server.getPrimaryService(UARTService);
}).then(function (result) {
console.log("DEvice information ", result);
}).catch(error => {
console.log('Argh! ' + error);
});
I get the following error:
Browser is WebBluetoothEnabled
device-info.js:37 Requesting Bluetooth Device.........
device-info.js:38 with {"acceptAllDevices":true,"optionalServices":"6e400001-b5a3-f393-e0a9-e50e24dcca9e"}
device-info.js:57 Argh! TypeError: Failed to execute 'requestDevice' on 'Bluetooth': Failed to read the 'optionalServices' property from 'RequestDeviceOptions': The provided value cannot be converted to a sequence.
Searching for 'RequestDeviceOptions': The provided value cannot be converted to a sequence. on stackoverflow and github issues was without answers.
I suspected a wrong Service UUID but on checking twice revealed it was correct.
optionalServices needs to be a list:
options.optionalServices = [ UARTService ];
I am running into an issue when I try to load the initial data for my blacklist from a Redis DB in my middleware code. Since the DB request takes some time it starts to fail.
Below is my code which gets fired when app starts via app.use(blacklist.blockRequests());.
When I try to make the function async I get the error that new TypeError('app.use() requires a middleware function').
One of the side effects is also that my array is empty when it's called again.
blockRequests: function() {
this.read();
this.logEvent('info', 'There are ' + this.blacklist.length + ' address(es) on the blacklist');
var self = this;
var interceptor = function(request, response, next) {
var ip = request.headers['x-forwarded-for'] || request.connection.remoteAddress;
if (self.isInBlacklist(ip)) {
self.logEvent('warn', 'Rejecting request from ' + ip + ', path and query was ' + request.originalUrl);
response.status(403).send();
} else {
next();
}
}
return interceptor;
},
And here is my read() function code:
read: function() {
try {
// get all records with prefix block:: from redis
redis.redis.keys('block::*', function (err, reply) {
// reply is null when the key is missing
if(err){}
else {
this.blacklist = []
for (let i = 0; i < reply.length; i++) {
let ipInt = reply[i].substring(7)
let ipStr = ipToInt(ipInt).toIP()
this.blacklist.push(ipStr)
}
}
});
} catch (error) {
if (error) {
this.blacklist = [];
}
}
}
If you're trying to make blockRequests() async, then it will start returning a promise and you can't use its return value directly in app.use(). Because then you'd be doing app.use(somePromise) and Express will balk because you have to pass it a function reference, not a promise.
Instead, you will have to use .then() or await to get the return value which is the function which you could then use with app.use().
If you show the larger calling context here (like where you're calling blockRequests() from), then we could offer more ideas on a fuller solution.
Here's a conceptual idea for how you could do this:
blockRequests: function() {
const self = this;
const interceptor = function(request, response, next) {
const ip = request.headers['x-forwarded-for'] || request.connection.remoteAddress;
if (self.isInBlacklist(ip)) {
self.logEvent('warn', 'Rejecting request from ' + ip + ', path and query was ' + request.originalUrl);
response.status(403).send();
} else {
next();
}
}
return interceptor;
},
read: function() {
// get all records with prefix block:: from redis
return new Promise((resolve, reject) => {
redis.redis.keys('block::*', (err, reply) => {
if (err) {
this.blacklist = [];
reject(err);
} else {
this.blacklist = [];
for (let i = 0; i < reply.length; i++) {
let ipInt = reply[i].substring(7)
let ipStr = ipToInt(ipInt).toIP()
this.blacklist.push(ipStr)
}
}
this.logEvent('info', 'There are ' + this.blacklist.length + ' address(es) on the blacklist');
resolve();
});
});
}
// register middleware for using blacklist
app.use(blacklist.blockRequests());
// now read the blacklist and when that is in place, then start the server
blacklist.read().then(() => {
// now we know that blacklist.blacklist is up-to-date
// start your server here
}).catch(err => {
console.log("Unable to start server - error in reading blacklist");
process.exit(1);
});
I'll start by saying I've found several similar issues posted on this site. None of them apply to my situation though.
I have a server and client (as is the norm with node.js/socket.io) and call emit a socket event when a button is pressed. This works fine... Except it seems to emit three times (at least the server runs the function three times). I've been staring at the code for way too long at this point and need another set of eyes.
Hopefully someone has an idea.
client code:
importJS('/js/pages/admin_base.js',function(){
var restartLMC = function(io){
toggleLoad();
var user = localStorage.getItem('User');
io.emit('restart_request',{session: user});
};
AdminIO = new io('http://localhost:26266');
AdminIO.on('restart_success',function(dat){
toggleLoad();
dropInfo(dat);
});
AdminIO.on('sendError',function(dat){
dropInfo(dat,{level: 'error'});
});
AdminIO.on('restart_fail',function(dat){
toggleLoad();
dropInfo(dat,{level: 'error'});
});
$('#restart').on('click',function(){
restartLMC(AdminIO);
});
});
Admin code:
process.stdout.write('\033c');
console.log('\x1b[36m', "Admin server starting...", '\x1b[0m');
var
ini = require('node-ini')
, conf = ini.parseSync('../config.ini')
, CS = require('../lm_modules/CoreSync.js')
, CoreSync = new CS()
, checkSession = function (session, callback) {
var res;
if (!CoreSync) { throw "Fatal error, there is no connection to the Core service!"; }
if (CoreSync.sessions) {
if (CoreSync.sessions[session]) {
res = CoreSync.sessions[session];
callback(res);
}
else {
CoreSync.sync('session', function (err, dat) {
if (CoreSync.sessions[session]) {
res = CoreSync.sessions[session];
callback(res);
} else { res = false; callback(res); }
});
}
} else {
res = false; callback(res);
}
if (res === "undefined") { callback(false); }
}
, runCMD = function(cmd,errCB,callback){
var
command
, args;
if(cmd.cmd){ command = cmd.cmd; } else { command = cmd; }
if(cmd.args){ args = cmd.args; }
const spawn = require('child_process').spawn;
const ex = spawn(command, args);
ex.stdout.on('data', (data) => {
callback(data);
});
ex.stderr.on('data', (data) => {
errCB(data);
});
ex.on('close', (code) => {
});
}
, executeCMD = function(cmd,callback){
const exec = require('child_process').exec
, cdw = (__dirname + '/../');
exec(cmd, {cwd: cdw}, (err, stdout, stderr) => {
if (err) {
callback(err,null);
return;
}
callback(stderr,stdout);
});
}
, io = require('socket.io').listen(26266) // can use up to 26485
console.log('\x1b[32m', "Admin server started.", '\x1b[0m');
console.log("Admin server listening at " + "http://" + conf["Server"]["binding"] + ":26266");
io.on('connection', function (socket) {
socket.on('restart_request', function(req){
console.log('Recieved restart request');
var success = false
, session = JSON.parse(req.session)
, sessionID = session.sessionID;
checkSession(sessionID, function (ses) {
if (ses === false) { console.error('CheckSession failed: No session exists'); return; }
if (ses.user.uuid !== session.uuid) { console.error('CheckSession failed: UUID mismatched'); return; }
if (ses.user.role < conf['Permissions']['lm_restart']){ socket.emit('restart_fail','Insufficient permissions.'); return; }
if(process.platform === 'win32'){
executeCMD('cd',function(err,res){
var errSent = false;
if(err){
console.error(err);
if(!errSent){ socket.emit('sendError','Restart failed'); }
errSent = true;
if(res === null){return;}
}
console.log(res);
socket.emit('restart_success','LM successfully restarted.');
});
}
else if(process.platform === 'linux'){
}
});
});
});
For those of you who may have seen this and found it a curious question/situation... I found two parts to this.
The first part is the $().on binding. For some reason (even though it's by no means called multiple times in the js code) adding unbind() in front of the binding resolved the issue in part... it cut the extra emits down from 3 to two (until I started another server app, then it went back up to three...)
The other part I found was that (for some reason) the socket.io connection is being duplicated as many times as there are socket servers running. More details on this issue here... I believe that once the cause for this is found, my issue will be resolved.
I am using stompit STOMP client. github - https://github.com/gdaws/node-stomp.
I am using ConnectFailover API for reconnect management. I have below code:
var stompit = require('stompit')
var reconnectOptions = {
'maxReconnects': 100,
'randomize' : false
};
var connManager = new stompit.ConnectFailover("failover:(stomp://mqbroker.nyc:61613,stomp://failovermqbroker.nyc:61613)", reconnectOptions);
connManager.on('error', function(error) {
var connectArgs = error.connectArgs;
var address = connectArgs.host + ':' + connectArgs.port;
console.error('Could not connect to ' + address + ' : ' + error.message);
});
connManager.on('connecting', function(connector) {
var address = connector.serverProperties.remoteAddress.transportPath;
console.log('Connecting to ' + address);
});
var totalMsgs = 50;
var count = 0;
var delayMs = 10000;
connManager.connect(function(error, client, reconnect) {
if (error) {
console.log("terminal error, given up reconnecting: " + error);
return;
}
client.on('error', function(error) {
// destroy the current client
client.destroy(error);
// calling reconnect is optional and you may not want to reconnect if the
// same error will be repeated.
reconnect();
});
var sendParams = {
'destination' : '/queue/myqueue',
'persistent' : 'true'
}
function sendMsg (){
setTimeout( function () {
console.log ('sending message ' + (count));
client.send(sendParams).end('Hello number ' + (count));
if (count++ < totalMsgs) {
sendMsg(count);
}
else {
client.send(sendParams).end('DISCONNECT');
client.disconnect();
console.log("Done.");
}
}, delayMs);
}
sendMsg();
});
The problem is that When the client gets disconnected from message broker, The producer keeps executing the sendMsg code and this causes loss of 2-3 messages in between. I want the client to stop executing when in disconnected state and resume when it is connected to failover instance.
Am I using the API incorrectly? What will be correct way to achieve this?
Have hacked at it for some time but this API lacks little documentation on how to use the features. Appreciate all the help.
Thanks,
xabhi
There is no problem with API but the with setTimeout code. I should clear the timeout when the client sees a connection failure.
UPDATED CODE: i, I'm new to Javascript programming and getting an undefined variable when trying to assign a new variable from a method.
I'm using node.js and creating a redis server using the redis-client in the "client variable".
var redis = require("redis");
var client = redis.createClient();
client.on("error", function (err) {
console.log("Error " + err); });
var numberPosts;
client.get("global:nextPostId", function(err, replies) {
numberPosts = replies;
console.log(numberPosts);
});
console.log(numberPosts);
When I call console.log inside the call back function it returns the proper value, however when I call the console.log outside of the callback function it returns "undefined". I'm trying to assign the value that is inside the callback function to the global variable numberPosts.
Any help is much appreciated, thanks.
Matt
I believe this will work:
client.get("global:nextPostId", function (err, reply) {
console.log("Number of posts: " + reply.toString());
})
The AJAX call is asynchronous so it doesn't have return value.. instead you have to use callback function and only there you have the value returned by the server method.
Edit: to assign the return value to global variable, first declare global variable:
var _numOfPosts = "";
Then:
client.get("global:nextPostId", function (err, reply) {
_numOfPosts = reply.toString());
})
However, the value won't be available until the AJAX call is finished so your original code can't work. There is not direct return value to store.
You can set timer to some reasonable response time, then have the code using the global variable in there.
Edit II: in order to call the method again once it's finished, have such code:
var _nextPostCallCount = 0;
function GetNextPost() {
//debug
console.log("GetNextPost called already " + _nextPostCallCount + " times");
//sanity check:
if (_nextPostCallCount > 1000) {
console.log("too many times, aborting");
return;
}
//invoke method:
client.get("global:nextPostId", function(err, replies) {
numberPosts = parseInt(replies.toString(), 10);
console.log("num of replies #" + (_nextPostCallCount + 1) + ": " + numberPosts);
//stop condition here.... for example if replies are 0
if (!isNaN(numberPosts) && numberPosts > 0)
GetNextPost();
});
//add to counter:
_nextPostCallCount++;
}
GetNextPost();
This will call the method over and over until the result is 0 or you pass some hard coded limit to prevent endless loop.
Try this instead to see errors:
var redis = require("redis");
client = redis.createClient();
client.on("error", function (err) {
console.log("Error " + err); });
//note the error logging
var numberPosts = client.get("global:nextPostId", function (error, response) {
if (error) {
console.log("async: " + error);
} else {
console.log("programming: " + response);
}
});
console.log("is lotsa fun: " + numberPosts);
As Shadow Wizard has pointed out you are trying to use numberPosts before there is something in it, as client.get() hasn't returned anything.
Read this to get a handle on node.js flow:
http://www.scribd.com/doc/40366684/Nodejs-Controlling-Flow
I was facing the the same issue when I applied the MVC framework.
To solve the problem, I employed the render function.
In the posts Model
exports.get = function(id,render) {
client.incr('post:id:'+id, function(err, reply) {
render(reply);
});
};
In the posts Controller
exports.get = function(req, res) {
posts.get('001', function (data){res.render('index',{post:data});});
};