Function does not call after callback - javascript

hello all StackOverflowers :) have a good day.
I have a mouse.exe, that is a simple C++ App that receives via stdio "getmouse", "setmouse x y" and "movemouse x y", getting the mouse position and setting it respectively...
That app is working fine and can receive commands while running.
I created a 'mouse' module in a folder, with this index.js
const spawn = require('child_process').spawn;
const EXE_ROUTE = __dirname + '\\mouse.exe';
var LOADED = false;
var Mouse = function (ready) {
if(LOADED) return ready && ready();
LOADED = true;
var child = spawn(EXE_ROUTE);
var stdout = Mouse.in = child.stdout;
var stdin = Mouse.out = child.stdin;
var err = Mouse.err = child.stderr;
Mouse.out.write("movemouse 100 100"); // This Works
Mouse.out.write("setmouse 20 20"); // This too
ready && ready();
}
module.exports = Mouse;
And my entry point is app.js
var Mouse = require('./mouse');
Mouse(function () {
console.log("Im here..."); // This prints
Mouse.out.write("movemouse 100 100"); // This does not work.
});
Mouse.out.write("movemouse 100 100"); // This Works :)
Im a bit confused because the callback is called just after the Mouse() function, so it shouldnt be any difference between writing the line below the Mouse(function () { ... }); and writing it in the callback...
PD: Dont tell me "You dont need to use a callback here, bc i will do some async tasks then and i will need the cb"
Thanks for your collaboration.

Related

my strings will not be re-declared in my loop

I have been programming a Battlesnake (https://play.battlesnake.com/) and I need to re-declare my move commands (like move="left" and move="right" for example) command but every time it goes over the code it uses the move command once and won't use it again. It also only uses the first one it can and won't use any other ones above it. Loops won't work because to my understanding the Battlesnake servers call the handleMove function each turn and if the Battlesnake servers don't get a response within 500 milliseconds the game will move for you. The code starts at the top of the handleMove and ends at the response.status thing. I know the code goes through the functions because I tracked it with console.log. The code goes through everything as intended, because I set console.log on all of the functions and inside all the if commands, and it runs through the move strings inside the if commands, but ignores all move commands it reaches after the code gets to response.status. That is where I am confused. A lot of the data is hosted on the Battlesnake servers, so if something is not declared in my code it probably came from the Battlesnake servers.
How can I fix this?
const express = require('express')
const PORT = process.env.PORT || 3000
const app = express()
app.use(bodyParser.json())
app.get('/', handleIndex)
app.post('/start', handleStart)
app.post('/move', handleMove)
app.post('/end', handleEnd)
app.listen(PORT, () => console.log(`Battlesnake Server listening at http://127.0.0.1:${PORT}`))
function handleIndex(request, response) {
var battlesnakeInfo = {
apiversion: '1',
author: '',
color: '#1c607d',
head: 'caffeine',
tail: 'leaf'
}
response.status(200).json(battlesnakeInfo)
}
function handleStart(request, response) {
var gameData = request.body
console.log('START')
response.status(200).send('ok')
}
function handleMove(request, response) {
var gameData = request.body
var head = gameData.you.head
var boardWidth = gameData.board.width
var boardHeight = gameData.board.height
var food = gameData.board.food[0]
// code i wrote
function moveUpB() {
if (head.x < 1) {
move = "up"
//refuses to execute at all??
}
}
function moveRightB() {
if (head.y > (boardHeight - 2)) {
move = "right"
//only used once
}
}
function moveDownB() {
if (head.x > (boardWidth - 2)) {
move = "down"
//only used once
}
}
function moveLeftB() {
if (head.y < 1) {
move = "left"
//only used once
}
}
moveUpB()
moveRightB()
moveDownB()
moveLeftB()
//aafter here it should go back to moveUpB but it doesent?
//rest of the code needed for the snake to move
console.log('MOVE: ' + move)
response.status(200).send({
move: move
})
}
function handleEnd(request, response) {
var gameData = request.body
console.log('END')
response.status(200).send('ok')
}

JS: How to stop a function from looping while the other function inside of it is executing?

In my project, I extract the feature points from a streaming video in function F1 and if some of them match with the data from the database I need to start the other function F2 inside F1. However, F2 cannot execute until the end because F1 keeps updating the input data to F2, so it just doesn't have enough time. Can I stop F1 from running while F2 is processing the data?
In my code I use tracking.js and OpenCV.js packages. First I run the video stream and for each frame I do next:
("corners2" and "descriptors2" are the data from the database)
function f1 (){
context2d.drawImage(video, 0, 0, canvas2d.width, canvas2d.height);
src1.data.set(context2d.getImageData(0, 0, canvas2d.width, canvas2d.height).data);
var blur1 = tracking.Image.blur(src1.data, canvas2d.width, canvas2d.height, blurRadius);
var gray1 = tracking.Image.grayscale(blur1, canvas2d.width, canvas2d.height);
var corners1 = tracking.Fast.findCorners(gray1, canvas2d.width, canvas2d.height);
var descriptors1 = tracking.Brief.getDescriptors(gray1, canvas2d.width, corners1);
cv.imshow("outputCanvas2d", src1);
const FPS = 30;
let begin = Date.now()
let delay = 1000/FPS - (Date.now() - begin);
setTimeout(f1, delay);
f2(corners1,descriptors1);
function f2(corners1,descriptors1) {
var matches = tracking.Brief.reciprocalMatch(corners1, descriptors1, corners2, descriptors2);
matches.sort(function(a, b) {
return b.confidence - a.confidence;
});
if (matches.length > 50){
window.app = new App();
} else {
console.log("not enought keypoints")
var matches = []
}
}
}
setTimeout(f1, 0);
From F2, if I have enough matches, I want to start an AR session by calling window.app = new App(); It starts but then it gives an error Cannot create an XRWebGLLayer with a lost WebGL context. I assume that it is due to the fact that F1 keeps running at the same time while it tries to start the AR session.
Sorry if my explanation is a bit confusing, I am quite new to JS and just try to make it work. Thank you for help.
The examples will use this JSONPlacerholder & axios as the purpose of this example is to illustrate awaits/asyncs & not requests, be sure to try them first
const f1 = async (params) => {
axios.get('https://jsonplaceholder.typicode.com/todos/').then(
).then((res) => {
console.log('f1')
});
};
const f2 = async (params) => {
axios.get('https://jsonplaceholder.typicode.com/todos/').then(
).then((res) => {
console.log('f2')
});
};
for (let i = 0; i < 20; i++){
f1();
f2();
// results will appear interferring as f1 will run & we won't wait till it finishes, instead
// the code will continue to f2 then won't wait for it to finish & then loop again
}
if you want to wait for one of them to finish, use await f1() to block all code untill f1() finishes, be sure to save it in a variable if it returns smth
Just two normal functions with the word async before the params, for more info

Using Multiple page.open in Single Script

My goal is to execute PhantomJS by using:
// adding $op and $er for debugging purposes
exec('phantomjs script.js', $op, $er);
print_r($op);
echo $er;
And then inside script.js, I plan to use multiple page.open() to capture screenshots of different pages such as:
var url = 'some dynamic url goes here';
page = require('webpage').create();
page.open(url, function (status) {
console.log('opening page 1');
page.render('./slide1.png');
});
page = require('webpage').create();
page.open(url, function (status) {
console.log('opening page 2');
page.render('./slide2.png');
});
page = require('webpage').create();
page.open(url, function (status) {
console.log('opening page 3');
page.render('./slide3.png');
phantom.exit(); //<-- Exiting phantomJS only after opening all 3 pages
});
On running exec, I get the following output on page:
Array ( [0] => opening page 3 ) 0
As a result I only get the screenshot of the 3rd page. I'm not sure why PhantomJS is skipping the first and second blocks of code (evident from the missing console.log() messages that were supposed to be output from 1st and 2nd block) and only executing the third block of code.
The problem is that the second page.open is being invoked before the first one finishes, which can cause multiple problems. You want logic roughly like the following (assuming the filenames are given as command line arguments):
function handle_page(file){
page.open(file,function(){
...
page.evaluate(function(){
...do stuff...
});
page.render(...);
setTimeout(next_page,100);
});
}
function next_page(){
var file=args.shift();
if(!file){phantom.exit(0);}
handle_page(file);
}
next_page();
Right, it's recursive. This ensures that the processing of the function passed to page.open finishes, with a little 100ms grace period, before you go to the next file.
By the way, you don't need to keep repeating
page = require('webpage').create();
I've tried the accepted answer suggestions, but it doesn't work (at least not for v2.1.1).
To be accurate the accepted answer worked some of the time, but I still experienced sporadic failed page.open() calls, about 90% of the time on specific data sets.
The simplest answer I found is to instantiate a new page module for each url.
// first page
var urlA = "http://first/url"
var pageA = require('webpage').create()
pageA.open(urlA, function(status){
if (status){
setTimeout(openPageB, 100) // open second page call
} else{
phantom.exit(1)
}
})
// second page
var urlB = "http://second/url"
var pageB = require('webpage').create()
function openPageB(){
pageB.open(urlB, function(){
// ...
// ...
})
}
The following from the page module api documentation on the close method says:
close() {void}
Close the page and releases the memory heap associated with it. Do not use the page instance after calling this.
Due to some technical limitations, the web page object might not be completely garbage collected. This is often encountered when the same object is used over and over again. Calling this function may stop the increasing heap allocation.
Basically after I tested the close() method I decided using the same web page instance for different open() calls is too unreliable and it needed to be said.
You can use recursion:
var page = require('webpage').create();
// the urls to navigate to
var urls = [
'http://phantomjs.org/',
'https://twitter.com/sidanmor',
'https://github.com/sidanmor'
];
var i = 0;
// the recursion function
var genericCallback = function () {
return function (status) {
console.log("URL: " + urls[i]);
console.log("Status: " + status);
// exit if there was a problem with the navigation
if (!status || status === 'fail') phantom.exit();
i++;
if (status === "success") {
//-- YOUR STUFF HERE ----------------------
// do your stuff here... I'm taking a picture of the page
page.render('example' + i + '.png');
//-----------------------------------------
if (i < urls.length) {
// navigate to the next url and the callback is this function (recursion)
page.open(urls[i], genericCallback());
} else {
// try navigate to the next url (it is undefined because it is the last element) so the callback is exit
page.open(urls[i], function () {
phantom.exit();
});
}
}
};
};
// start from the first url
page.open(urls[i], genericCallback());
Using Queued Processes, sample:
var page = require('webpage').create();
// Queue Class Helper
var Queue = function() {
this._tasks = [];
};
Queue.prototype.add = function(fn, scope) {
this._tasks.push({fn: fn,scope: scope});
return this;
};
Queue.prototype.process = function() {
var proxy, self = this;
task = this._tasks.shift();
if(!task) {return;}
proxy = {end: function() {self.process();}};
task.fn.call(task.scope, proxy);
return this;
};
Queue.prototype.clear = function() {
this._tasks = []; return this;
};
// Init pages .....
var q = new Queue();
q.add(function(proxy) {
page.open(url1, function() {
// page.evaluate
proxy.end();
});
});
q.add(function(proxy) {
page.open(url2, function() {
// page.evaluate
proxy.end();
});
});
q.add(function(proxy) {
page.open(urln, function() {
// page.evaluate
proxy.end();
});
});
// .....
q.add(function(proxy) {
phantom.exit()
proxy.end();
});
q.process();
I hope this is useful, regards.

this._get is not a function - javascript oop and prototypes

I'm using something similar to NodeJS called bondi, it's build on the Firefox js engine.. Basically i'm getting this error and I believe it's due to the way i'm referencing "this" in the .Get function below.
Basically there is a tool called SFtpClient. It has the method of "Get", to list the contents of a folder, but I want to change the prototype for this with a drop in include file. I need to change it so that it
a/ retries several times when it fails, and b/ it has a recursive folder listing function.
So I used the prototype to change it - moved .Get to ._Get.
Can anyone see why I would be getting the error:
Jan 23 04:51:34 beta bondi: === this._Get is not a function --- Prio(6) Result(0x0) File(/home/nwo/approot/include/sftpclientenh
when I run the code below?
Thanks
SFtpClient.prototype._Get = SFtpClient.prototype.Get;
SFtpClient.prototype.Get = function(Folder, Retries){
//defaults
if(!Retries) Retries = 5;
if(!Folder) Folder = "~/";
//vars
var FileListing = [];
var connect = function(){
//TODO JRF 19.01.2012 : re-enable this when bondi is fixed
// this.HomeDirectory.replace(/\/?$/, "/");
FileListing = this._Get(Folder);
return true;
}
var i = 1;
do{
var res = false;
try {
res = connect();
}catch(e){
Debug.LogInfo(e.message);
}
i++;
Server.Sleep(i*2000);
} while(res==false && i < Retries);
return FileListing;
}
Try res = connect.call(this) instead of res = connect().

Batch file called from Javascript/XPCOM doesn't show command prompt window

I am calling a batch file from Javascript in this fashion:
function runBatch(){
var exe = Components.classes['#mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
exe.initWithPath("C:\\test.bat");
var run = Components.classes['#mozilla.org/process/util;1'].createInstance(Components.interfaces.nsIProcess);
run.init(exe);
var parameters = ["hi"];
run.run(false, parameters,parameters.length);
}
my test batch file is:
echo on
echo %1
pause
exit
Each time I call a batch file, however, the command prompt is not displayed, as it would be if I simply ran the batch file from the desktop. How can I remedy this and display a command prompt for the batch file?
Edit
To be clear, the cmd.exe process is launched - I can see it in the task bar. But no window gets displayed. This snippet behaves similarly:
function runCmd(){
var exe = Components.classes['#mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
exe.initWithPath("C:\\WINDOWS\\system32\\cmd.exe");
var run = Components.classes['#mozilla.org/process/util;1'].createInstance(Components.interfaces.nsIProcess);
run.init(exe);
run.run(false, null,0);
}
The only solution I've heard so far (that should work, although I haven't done it yet, comes from Mook in the Mozilla xulrunner IRC channel:
create a temporary batch file, writing in the batch file to call and arguments to pass it. then execute the temporary batch file.
e.g psuedocode:
f = fopen("temp.bat");
fprintf(f, "other.bat 1 2 3 4 5");
fclose(f);
exec("temp.bat");
not very elegant but it should work.
Did you try using the launch method of nsiLocalFile?
function runBatch(){
var exe = Components.classes['#mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
exe.initWithPath("C:\\test.bat");
exe.launch();
}
This should have "the same effect as if you double-clicked the file."
This code snippet seems to work fine. Of course, you have to change D:\Windows\system32\ to path to cmd.exe in your operation system.
const FileFactory = new Components.Constructor("#mozilla.org/file/local;1","nsILocalFile","initWithPath");
var str_LocalProgram = "D:\\Windows\\system32\\cmd.exe";
var obj_Program = new FileFactory(str_LocalProgram);
var process = Components.classes["#mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
process.init(obj_Program);
var args = ["/C", "regedit.exe"];
process.run(true, args, args.length);
I had to launch a batch file and pass in an argument. This is how I did it:
let file = uri.QueryInterface(Components.interfaces.nsIFileURL).file;
let run = Components.classes['#mozilla.org/process/util;1']
.createInstance(Components.interfaces.nsIProcess);
let path = file.path;
if(file.exists())
{
// quick security check
if(file.isExecutable())
{
// show error message
return;
}
let localfile = file.QueryInterface(Components.interfaces.nsILocalFile);
if(localfile != null)
{
if (app == "app1")
{
localfile.initWithPath("C:\\app1.bat");
}
else
{
localfile.initWithPath("C:\\app2.bat");
}
run.init(localfile);
var parameters = [path];
run.run(false, parameters, parameters.length);
}
else
{
// show error message
}
}
else
{
// show error message
}
and in my Window batch file I did:
#ECHO OFF
START "application.exe" %1
using START, allowed me to launch the application and close the command line window
You are doing right but repair this:
function runBatch(){
var exe = Components.classes['#mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
exe.initWithPath("***C:\ \test.bat***");
var run = Components.classes['#mozilla.org/process/util;1'].createInstance(Components.interfaces.nsIProcess);
run.init(exe);
var parameters = ["hi"];
run.run(false, parameters,parameters.length);
}
If you do this???
function runBatch(){
var exe = Components.classes['#mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
exe.initWithPath("***C:\test.bat***");
var run = Components.classes['#mozilla.org/process/util;1'].createInstance(Components.interfaces.nsIProcess);
run.init(exe);
var parameters = ["hi"];
run.run(false, parameters,parameters.length);
}
An put #echo off at init???
Thanks
Pfft, very ugly code..
A much nicer trick is to use Win.com to spawn a 16bit subsystem of the command prompt.
Win.com will send the console to the right virtual terminal, showing you the output.
var lPath = getWorkingDir.path + "\\..\\..\\WINDOWS\\system32\\win.com";
lFile.initWithPath(lPath);
var process = Components.classes["#mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
process.init(lFile);
var args = ["cmd.exe"];
process.run(false, args, args.length);
Nicer, and works :)
For Linux:
<script>
function callLight2()
{
netscape.security.PrivilegeManager.enablePrivilege(
'UniversalXPConnect'
);
var exe = Components.classes['#mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
// exe.initWithPath(C:\\Windows\\system32\\cmd.exe"");
exe.initWithPath("/usr/bin/gnome-terminal");
var run = Components.classes['#mozilla.org/process/util;1'].createInstance(Components.interfaces.nsIProcess);
run.init(exe);
var parameters = ["-e", "/usr/bin/ip_connect_up.sh 2 2 3 4 5 6"];
// var parameters = ["/C", "regedit.exe"];
// var parameters = ["hi"];
run.run(true, parameters,parameters.length);
}
</script>
start

Categories

Resources