Electron open & keep open cmd.exe - windows

I'm building a little tool that should among other thing allow me to start a Tomcat server.
Pretty easy, I just want a button to launch startup.bat and another to call shutdown.bat.
It works quite well (server start and stop) but completely in ninja mode, I can't manage to get the Tomcat console with the logs.
From a classic command line if I call startup.bat, a Window is opened with logs inside.
I tried exec, execFile, spawn. I tried calling directly the bat, the cmd.exe, even tried start. But I can't get the Window.
I know I can get streams, but I would like not to bother with that.
Also I'm just using the tool on Windows, no need to think about other platform for the moment.
const ipc = require('electron').ipcMain;
const execFile = require('child_process').execFile;
ipc.on('start-local-tomcat', function (event) {
execFile('cmd.exe', ['D:\\DEV\\apache-tomcat-8.0.12\\bin\\startup.bat'],
{env: {'CATALINA_HOME': 'D:\\DEV\\apache-tomcat-8.0.12'}},
function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
})
});
ipc.on('stop-local-tomcat', function (event) {
execFile('cmd.exe',['D:\\DEV\\apache-tomcat-8.0.12\\bin\\shutdown.bat'],
{env: {'CATALINA_HOME': 'D:\\DEV\\apache-tomcat-8.0.12'}},
function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
})
});

Finally I just didn't read the doc enough, there is a parameter called detached that will do exactly what I want:
var child = spawn(
'D:\\DEV\\apache-tomcat-8.0.12\\bin\\startup.bat',
{
env: {'CATALINA_HOME': 'D:\\DEV\\apache-tomcat-8.0.12'},
detached: true
}
);

Related

Collecting Yarn Metrics

I would like to collect metrics on how long yarn commands such as yarn install take to complete and other metrics such as how often the commands don't complete successfully.
My .yarnrc file looks like this:
registry "https://artifactory-content.company.build/artifactory/api/npm/npm"
"--ignore-engines" true
"#sail:registry" "https://artifactory-content.company.build/artifactory/api/npm/npm-local"
"#company-internal:registry" "https://artifactory-content.company.build/artifactory/api/npm/npm-local"
lastUpdateCheck 1617811239383
yarn-path "./yarn-1.19.1.js"
From what I understand, when I run the yarn command, it invokes the yarn-1.19.1.js file. Would it be possible to create a wrapper such that when any yarn command is run, it logs the metrics at the command level and then executes the yarn-1.19.1.js file?
Another approach I ran across was modifying the package.json file and overriding the commands as mentioned here but this doesn't seem scalable as there might be new commands added later on.
Yes, you could create a wrapper script that invokes the Yarn core library. This is exactly what the Node.js that is yarn does:
#!/usr/bin/env node
'use strict';
var ver = process.versions.node;
var majorVer = parseInt(ver.split('.')[0], 10);
if (majorVer < 4) {
console.error('Node version ' + ver + ' is not supported, please use Node.js 4.0 or higher.');
process.exit(1);
} else {
try {
require(__dirname + '/../lib/v8-compile-cache.js');
} catch (err) {
}
var cli = require(__dirname + '/../lib/cli');
if (!cli.autoRun) {
cli.default().catch(function(error) {
console.error(error.stack || error.message || error);
process.exitCode = 1;
});
}
}
You could just edit that script like so:
const start = Date.now();
var cli = require(__dirname + '/../lib/cli');
if (!cli.autoRun) {
cli.default()
.then(function() {
const durationInMs = Date.now() - start;
// It succeeded, do your stuff.
})
.catch(function(error) {
console.error(error.stack || error.message || error);
process.exitCode = 1;
const durationInMs = Date.now() - start;
// It failed, do your stuff.
});
}

[InvalidStateError: "setRemoteDescription needs to called before addIceCandidate" code: 11

I create a simple video calling app by using web Rtc and websockets.
But when i run the code, the following error occured.
DOMException [InvalidStateError: "setRemoteDescription needs to called before addIceCandidate"
code: 11
I don't know how to resolve this error.
Here is my code below:
enter code here
var localVideo;
var remoteVideo;
var peerConnection;
var uuid;
var localStream;
var peerConnectionConfig = {
'iceServers': [
{'urls': 'stun:stun.services.mozilla.com'},
{'urls': 'stun:stun.l.google.com:19302'},
]
};
function pageReady() {
uuid = uuid();
console.log('Inside Page Ready');
localVideo = document.getElementById('localVideo');
remoteVideo = document.getElementById('remoteVideo');
serverConnection = new WebSocket('wss://' + window.location.hostname +
':8443');
serverConnection.onmessage = gotMessageFromServer;
var constraints = {
video: true,
audio: true,
};
if(navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia(constraints)
.then(getUserMediaSuccess).catch(errorHandler);
}else
{
alert('Your browser does not support getUserMedia API');
}
}
function getUserMediaSuccess(stream) {
localStream = stream;
localVideo.src = window.URL.createObjectURL(stream);
}
function start(isCaller) {
console.log('Inside isCaller');
peerConnection = new RTCPeerConnection(peerConnectionConfig);
peerConnection.onicecandidate = gotIceCandidate;
peerConnection.onaddstream = gotRemoteStream;
peerConnection.addStream(localStream);
if(isCaller) {
console.log('Inside Caller to create offer');
peerConnection.createOffer().
then(createdDescription).catch(errorHandler);
}
}
function gotMessageFromServer(message) {
console.log('Message from Server');
if(!peerConnection)
{
console.log('Inside !Peer Conn');
start(false);
}
var signal = JSON.parse(message.data);
// Ignore messages from ourself
if(signal.uuid == uuid) return;
if(signal.sdp) {
console.log('Inside SDP');
peerConnection.setRemoteDescription(new
RTCSessionDescription(signal.sdp)).then(function() {
// Only create answers in response to offers
if(signal.sdp.type == 'offer') {
console.log('Before Create Answer');
peerConnection.createAnswer().then(createdDescription)
.catch(errorHandler);
}
}).catch(errorHandler);
} else if(signal.ice) {
console.log('Inside Signal Ice');
peerConnection.addIceCandidate(new
RTCIceCandidate(signal.ice)).catch(errorHandler);
}
}
function gotIceCandidate(event) {
console.log('Inside Got Ice Candi');
if(event.candidate != null) {
serverConnection.send(JSON.stringify({'ice': event.candidate,
'uuid': uuid}));
}
}
function createdDescription(description) {
console.log('got description');
peerConnection.setLocalDescription(description).then(function() {
console.log('Inside Setting ');
serverConnection.send(JSON.stringify({'sdp':
peerConnection.localDescription, 'uuid': uuid}));
}).catch(errorHandler);
}
function gotRemoteStream(event) {
console.log('got remote stream');
remoteVideo.src = window.URL.createObjectURL(event.stream);
}
function errorHandler(error) {
console.log(error);
}
// Taken from http://stackoverflow.com/a/105074/515584
// Strictly speaking, it's not a real UUID, but it gets the job done here
function uuid() {
function s4() {
return Math.floor((1 + Math.random()) *
0x10000).toString(16).substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() +
s4() + s4();
}
This is my code, I don't know how to arrange the addIceCandidate and addRemoteDescription function.
You need to make sure that
peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice))
is called after description is set.
You have sitution where you receive ice candidate and try to add it to peerConnection before peerConnection has completed with setting description.
I had similar situation, and I created array for storing candidates that arrived before setting description is completed, and a variable that checks if description is set. If description is set, I would add candidates to peerConnection, otherwise I would add them to array. (when you set your variable to true, you can also go through array and add all stored candidates to peerConnection.
The way WebRTC works (as much as i understand) is you have to make two peers to have a deal to how to communicate eachother in the order of give an offer to your peer get your peers answer and select an ICE candidate to communicate on then if you want to send your media streams for an video conversation
for you to have a good exampe to look on how to implemet those funcitons and in which order you can visit https://github.com/alexan1/SignalRTC he has a good understading of how to do this.
you might already have a solution to your problem at this time but im replying in case you do not.
EDIT: As I have been told, this solution is an anti-pattern and you should NOT implement it this way. For more info on how I solved it while still keeping a reasonable flow, follow this answer and comment section: https://stackoverflow.com/a/57257449/779483
TLDR: Instead of calling addIceCandidate as soon as the signaling information arrives, add the candidates to a queue. After calling setRemoteDescription, go through candidates queue and call addIceCandidate on each one.
--
From this answer I learned that we have to call setRemoteDescription(offer) before we add the Ice Candidates data.
So, expanding on #Luxior answer, I did the following:
When signaling message with candidate arrives:
Check if remote was set (via a boolean flag, ie: remoteIsReady)
If it was, call addIceCandidate
If it wasn't, add to a queue
After setRemoteDescription is called (in answer signal or answer client action):
Call a method to go through the candidates queue and call addIceCandidate on each one.
Set boolean flag (remoteIsReady) to true
Empty queue

How to do composite with gm node.js?

How to do 'gm composite -gravity center change_image_url base_image_url' with GM Node.js?
How to call gm().command() & gm().in() or gm().out() to achieve the above?
After struggling for an hour, here is my solution for your question:
gm composite -gravity center change_image_url base_image_url
gm()
.command("composite")
.in("-gravity", "center")
.in(change_image_url)
.in(base_image_url)
.write( output_file, function (err) {
if (!err)
console.log(' hooray! ');
else
console.log(err);
});
Good luck! Hope it will be helpful to others as well :)
Install gm, (make sure you already install graphicsmagick
npm install gm
following is my example code to merge two image together (use gm.in)
var gm = require('gm');
gm()
.in('-page', '+0+0')
.in('bg.jpg')
.in('-page', '+10+20') // location of smallIcon.jpg is x,y -> 10, 20
.in('smallIcon.jpg')
.mosaic()
.write('tesOutput.jpg', function (err) {
if (err) console.log(err);
});
i am doing that this way:
var exec = require('child_process').exec
var command = [
'-composite',
'-watermark', '20x50',
'-gravity', 'center',
'-quality', 100,
'images/watermark.png',
'images/input.jpg', //input
'images/watermarked.png' //output
];
// making watermark through exec - child_process
exec(command.join(' '), function(err, stdout, stderr) {
if (err) console.log(err);
});
Why does nobody use composite command? (https://github.com/aheckmann/gm)
var gm = require('gm');
var bgImage = 'bg.jpg',
frontImage = 'front.jpg',
resultImage = 'result.jpg',
xy = '+100+150';
gm(bgImage)
.composite(frontImage)
.geometry(xy)
.write(resultImage, function (err) {
if (!err) console.log('All done');
});
UPDATE Oh, I watched history of source of this method. It becomes available only on 2014
If you want to resize and merge, you can use this:
gm()
.in('-geometry', '+0+0')
.in('./img/img1.png')
.in('-geometry', '300x300+100+200')
.in('./img/img2.png')
.flatten()
.write('resultGM.png', function (err) {
if (err) console.log(err);
});
Having the pleasure of being confined to a windows machine for the moment I solved this problem eventually by not using the "gm" module at all. For some reason, even though I have installed graphics-magick via its installer the node module refused to find it in my environment variables. But that could have something to do with the fact that I am trying to make an application with Electron.js (which is similar to Node.js but has its "gotcha's").
var exec = require("child_process").execSync;
var commandArray = [
__dirname + "/bin/graphicsMagick/gm.exe", // the relative path to the graphics-magick executable
"-composite",
"-gravity",
"center",
__dirname + "/data/images/qr/logo-small.png", // relative paths to the images you want to composite
__dirname + "/data/images/qr/qr-webpage.png",
__dirname + "/data/images/qr/qr-webpage-logo.png" // relative path to the result
];
var returnValue = exec(commandArray.join(" "));
For windows I think this is the correct portable way to do it.

How to send CONTROL+C at spawn in nodejs

I run CMD to spawn, but if you'll send me a ping command, I can not get out of it, how can I send the console control + c, to avoid this? THANKS!
var fs = require('fs');
var iconv = require('iconv-lite');
function sendData (msg) {
console.log('write msg ', msg);
cmd.stdin.write(msg + "\r\n");
}
function execCommand() {
console.log('start command line')
var s = {
e : 'exec_command',
d : {
data : {}
}
};
cmd = require('child_process').spawn('cmd', ['/K']);
cmd.stdout.on('data', function (data) {
console.log(iconv.decode(data, 'cp866'));
});
}
execCommand();
sendData('ping e1.ru -t');
sendData( EXIT ??? )
?????
I want to make a console, a full-fledged console through node.js.
sendData('dir');
sendData('cd /d Windows');
sendData('ping 8.8.8.8 -t');
senData( CONTROL + C );
senData('dir')
You'll want to explicitly call:
cmd.kill();
that'll do the trick. If you require the equivalent of CTRL-C then call:
cmd.kill('SIGINT');
See child_process.kill docs for more info.

Using sockets (nsIServerSocket) in XPCOM component (Firefox Extension) (sockets + new window = seg faults)

PLEASE READ THE UPDATE #2 BELOW IF YOU ARE INTERESTED IN THIS PROBLEM ;)
Say I put this code into the JS of my extension.
var reader = {
onInputStreamReady : function(input) {
var sin = Cc["#mozilla.org/scriptableinputstream;1"]
.createInstance(Ci.nsIScriptableInputStream);
sin.init(input);
sin.available();
var request = '';
while (sin.available()) {
request = request + sin.read(512);
}
console.log('Received: ' + request);
input.asyncWait(reader,0,0,null);
}
}
var listener = {
onSocketAccepted: function(serverSocket, clientSocket) {
console.log("Accepted connection on "+clientSocket.host+":"+clientSocket.port);
input = clientSocket.openInputStream(0, 0, 0).QueryInterface(Ci.nsIAsyncInputStream);
output = clientSocket.openOutputStream(Ci.nsITransport.OPEN_BLOCKING, 0, 0);
input.asyncWait(reader,0,0,null);
}
}
var serverSocket = Cc["#mozilla.org/network/server-socket;1"].
createInstance(Ci.nsIServerSocket);
serverSocket.init(-1, true, 5);
console.log("Opened socket on " + serverSocket.port);
serverSocket.asyncListen(listener);
Then I run Firefox and connect to the socket via telnet
telnet localhost PORT
I send 5 messages and they get printed out, but when I try to send 6th message I get
firefox-bin: Fatal IO error 11 (Resource temporarily unavailable) on X server :0.0.
Even worse, when I try to put this same code into an XPCOM component (because that's where I actually need it), after I try sending a message via telnet I get
Segmentation fault
or sometimes
GLib-ERROR **: /build/buildd/glib2.0-2.24.1/glib/gmem.c:137: failed to allocate 32 bytes
aborting...
Aborted
printed to the terminal from which I launched firefox.
This is really weird stuff.. Can you spot something wrong with the code I've pasted or is smth wrong with my firefox/system or is the nsIServerSocket interface deprecated?
I'm testing with Firefox 3.6.6.
I would really appreciate some answer. Perhaps you could point me to a good example of using Sockets within an XPCOM component. I haven't seen many of those around.
UPDATE
I just realised that it used to work so now I think that my Console
component breaks it. I have no idea how this is related. But if I
don't use this component the sockets are working fine.
Here is the code of my Console component. I will try to figure out
what's wrong and why it interferes and I'll post my findings later.
Likely I'm doing something terribly wrong here to cause Segmentation
faults with my javascript =)
Voodoo..
components/Console.js:
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
Console.prototype = (function() {
var win;
var initialized = false;
var ready = false;
var _log = function(m, level, location) {
if (initialized&&ready) {
var prefix = "INFO: ";
switch (level) {
case "empty":
prefix = ""
break;
case "error":
prefix = "ERORR: "
break;
case "warning":
prefix = "WARNING: "
break;
}
win.document.getElementById(location).value =
win.document.getElementById(location).value + prefix + m + "\n";
win.focus();
} else if (initialized&&!ready) {
// Now it is time to create the timer...
var timer = Components.classes["#mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
// ... and to initialize it, we want to call
event.notify() ...
// ... one time after exactly ten second.
timer.initWithCallback(
{ notify: function() { log(m); } },
10,
Components.interfaces.nsITimer.TYPE_ONE_SHOT
);
} else {
init();
log(m);
}
}
var log = function(m, level) {
_log(m, level, 'debug');
}
var poly = function(m, level) {
_log(m, "empty", 'polyml');
}
var close = function() {
win.close();
}
var setReady = function() {
ready = true;
}
var init = function() {
initialized = true;
var ww = Components.classes["#mozilla.org/embedcomp/window-
watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
win = ww.openWindow(null, "chrome://polymlext/content/
console.xul",
"console", "chrome,centerscreen,
resizable=no", null);
win.onload = setReady;
return win;
}
return {
init: init,
log : log,
poly : poly,
}
}());
// turning Console Class into an XPCOM component
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
function Console() {
this.wrappedJSObject = this;
}
prototype2 = {
classDescription: "A special Console for PolyML extension",
classID: Components.ID("{483aecbc-42e7-456e-b5b3-2197ea7e1fb4}"),
contractID: "#ed.ac.uk/poly/console;1",
QueryInterface: XPCOMUtils.generateQI(),
}
//add the required XPCOM glue into the Poly class
for (attr in prototype2) {
Console.prototype[attr] = prototype2[attr];
}
var components = [Console];
function NSGetModule(compMgr, fileSpec) {
return XPCOMUtils.generateModule(components);
}
I'm using this component like this:
console = Cc["#ed.ac.uk/poly/console;1"].getService().wrappedJSObject;
console.log("something");
And this breaks the sockets :-S =)
UPDATE #2
Ok, if anyone is interested in checking this thing out I would really
appreciate it + I think this is likely some kind of bug (Seg fault
from javascript shouldn't happen)
I've made a minimal version of the extension that causes the problem,
you can install it from here:
http://dl.dropbox.com/u/645579/segfault.xpi
The important part is chrome/content/main.js:
http://pastebin.com/zV0e73Na
The way my friend and me can reproduce the error is by launching the
firefox, then a new window should appear saying "Opened socket on
9999". Connect using "telnet localhost 9999" and send a few messages.
After 2-6 messages you get one of the following printed out in the
terminal where firefox was launched:
1 (most common)
Segmentation fault
2 (saw multiple times)
firefox-bin: Fatal IO error 11 (Resource temporarily unavailable) on
X
server :0.0.
3 (saw a couple of times)
GLib-ERROR **: /build/buildd/glib2.0-2.24.1/glib/gmem.c:137: failed
to
allocate 32 bytes
aborting...
Aborted
4 (saw once)
firefox-bin: ../../src/xcb_io.c:249: process_responses: Assertion
`(((long) (dpy->last_request_read) - (long) (dpy->request)) <= 0)'
failed.
Aborted
If you need any more info or could point me to where to post a bug
report :-/ I'll be glad to do that.
I know this is just one of the many bugs... but perhaps you have an
idea of what should I do differently to avoid this? I would like to
use that "console" of mine in such way.
I'll try doing it with buffer/flushing/try/catch as people are suggesting, but I wonder whether try/catch will catch the Seg fault...
This is a thread problem. The callback onInputStreamReady happened to be executed in a different thread and accessing UI / DOM is only allowed from the main thread.
Solution is really simple:
change
input.asyncWait(reader,0,0,null);
to
var tm = Cc["#mozilla.org/thread-manager;1"].getService();
input.asyncWait(reader,0,0,tm.mainThread);

Resources