So I'm working on an electron app that should launch an external application when a button is pressed. It works, but if I close that app and press the button again, it'll start several instances of the process. Here's the code:
ipcMain.on("run_crystal", () => {
var cp = require("child_process");
executablePath = crystal + "\\CrystalDM\\Server\\CrystalDMServer.exe";
var Server_child = cp.spawn(executablePath);
executablePath = crystal + "\\CrystalDM\\Game\\CrystalDM.exe";
var parameters = ["test"];
var options = {cwd:crystal+"\\CrystalDM\\Game"};
console.log("a intrat in start game si urmeaza sa ruleze " + executablePath)
var Game_child = cp.execFile(executablePath, parameters, options, (error, stdout, stderr) =>{
console.log(stdout)
Game_child.kill("SIGINT");
Server_child.kill("SIGINT");
delete Game_child;
delete Server_child;
delete cp;
});
});
This piece of code might be called multiple time, and you forgot to remove the event listener after things done. I don't know extractly how to fix it, but try this:
ipcMain.once("run_crystal", () => {
[your code here]
});
Or:
ipcMain.on("run_crystal", () => {
[your code here]
ipcMain.removeAllListeners("run_crystal");
});
For now, I used this solution:
ipcMain.on("run_crystal", () => {
if(if_started == 0){
if_started = 1;
var cp = require("child_process");
console.log("mesajul a ajuns");
executablePath = crystal + "\\CrystalDM\\Server\\CrystalDMServer.exe";
var Server_child = cp.spawn(executablePath);
executablePath = crystal + "\\CrystalDM\\Game\\CrystalDM.exe";
var parameters = ["test"];
var options = {cwd:crystal+"\\CrystalDM\\Game"};
var Game_child = cp.execFile(executablePath, parameters, options,
(error, stdout, stderr) =>{
Game_child.kill("SIGINT");
Server_child.kill("SIGINT");
delete Game_child;
delete Server_child;
delete cp;
delete parameters;
delete options;
if_started = 0;
});
}
});
If you don't want to start a process multiple times, you have to keep track of already started processes.
let runningProcesses = {};
ipcMain.on("run_crystal", (event, arg) => {
var cp = require("child_process");
executablePath = crystal + "\\CrystalDM\\Server\\CrystalDMServer.exe";
if (runningProcesses[executablePath]){ // boolean value for a single process or int if you want to allow multiple instances runningProcesses[executablePath] < maxProcessCounts
event.sender.send('process-running', { process: executablePath })
} else {
runningProcesses[executablePath] = true; // boolean value for a single process or int if you want to allow multiple instances
var Server_child = cp.spawn(executablePath);
Server_child.on('close', (code, signal) => {
runningProcesses[executablePath] = false; // or delete runningProcesses[executablePath];
});
event.sender.send('process-started', { process: executablePath })
executablePath = crystal + "\\CrystalDM\\Game\\CrystalDM.exe";
var parameters = ["test"];
var options = {cwd:crystal+"\\CrystalDM\\Game"};
console.log("a intrat in start game si urmeaza sa ruleze " + executablePath)
var Game_child = cp.execFile(executablePath, parameters, options,(error, stdout, stderr) =>{
console.log(stdout)
Game_child.kill("SIGINT");
Server_child.kill("SIGINT");
delete Game_child;
delete Server_child;
delete cp;
});
}
});
Related
i have a problem, my Command Handler only recognize the top Folder inside my Commands Directory. Its supposed to show all of the available Folder in Commands Directory but it only showed the 'test' category which is the top one. any help would be really appreciated.
Folder/Directory Construction:
console.log output:
Command Handler Code:
const {readdirSync} = require('fs');
const ascii = require('ascii-table');
let table = new ascii("Commands");
table.setHeading('Category', 'Command', ' Load status');
var logged = false;
const path = require('node:path')
module.exports = (client) => {
readdirSync('./Commands/').forEach(dir => {
var commands = readdirSync(`./Commands/${dir}/`).filter(file => file.endsWith('.js'));
for(let file of commands){
let pull = require(`../Commands/${dir}/${file}`);
if(pull.name){
client.commands.set(pull.name, pull);
table.addRow(dir,file,'✔️ -> Command Loaded')
} else {
table.addRow(dir,file,'❌ -> Command Error')
continue;
}
if(pull.aliases && Array.isArray(pull.aliases)) pull.aliases.forEach(alias => client.aliases.set(alias, pull.name))
}
if(!logged) {
console.log(table.toString())
console.log(`[Command] Command Handler is Ready! | Total Commands: ${commands.length}`)
logged = true
}
});
}
I believe you are overwriting the commands variable after each folder has been looped through. Try this:
const {readdirSync} = require('fs');
const ascii = require('ascii-table');
let table = new ascii("Commands");
table.setHeading('Category', 'Command', ' Load status');
var logged = false;
const path = require('node:path')
module.exports = (client) => {
readdirSync('./Commands/').forEach(dir => {
var commands = []
commands.push(readdirSync(`./Commands/${dir}/`).filter(file => file.endsWith('.js')));
for(let file of commands){
let pull = require(`../Commands/${dir}/${file}`);
if(pull.name){
client.commands.set(pull.name, pull);
table.addRow(dir,file,'✔️ -> Command Loaded')
} else {
table.addRow(dir,file,'❌ -> Command Error')
continue;
}
if(pull.aliases && Array.isArray(pull.aliases)) pull.aliases.forEach(alias => client.aliases.set(alias, pull.name))
}
if(!logged) {
console.log(table.toString())
console.log(`[Command] Command Handler is Ready! | Total Commands: ${commands.length}`)
logged = true
}
});
}
If this doesn't help than it might still be that issue I referred to above but the edits I made might not be compatible with your code.
I have an app that, when it is starting, loads a bunch of files from a directory in the underlying OS, after this it presents a page (generated with PUG, if it makes any difference) that shows the the list of loaded files to the user and if one is clicked it shows the contents. One of the buttons on the page allows the user to create a new file (by spawning a system command based on the user's input).
My question is how do I reload the main page after the new file is created so that the web page now shows the new file that was added. In the future there will be a feature to delete a file as well, so I will also need to reload after this to show that the file has been deleted.
TIA for any assistance.
Code is short enough that I can include it here (please let me know if I am doing this the long difficult way, I am jut learning)
index.js
const express = require('express')
const app = express();
const port = 8000;
app.use(express.json());
app.use(express.static(__dirname + "/public"));
app.set('view engine', 'pug');
const { exec } = require('child_process');
// Read profile names
const profileFolder = '/home/pi/configs/';
const fs = require('fs');
var profiles = [];
function init() {
profiles = fs.readdirSync(profileFolder);
for (var i = 0; i < profiles.length; i++) {
try {
profile = fs.readFileSync(profileFolder + profiles[i], 'utf8');
profiles[i] = {
pname: profiles[i].split('.')[0],
profile: profile
};
}
catch (err) {
console.error(err);
}
};
}
app.get('/', function(req, res) {
init();
res.render(__dirname + '/views/index.pug', {vpnprofiles: profiles});
});
app.get('/addnew', function(req, res) {
let pname = req.query.newprofile;
console.log(`Adding new profile: ${pname}`);
exec("pivpn -a -n "+pname, (error, stdout, stderr) => {
if (error) {
console.log(`ERROR: ${error.message}`);
return;
}
if (stderr) {
console.log(`STDERR: ${stderr}`);
return;
}
console.log(`${stdout}`);
res.send("Done!");
});
return;
});
app.listen(port, () => {
console.log(`Server started on port ${port}!`)
});
/public/script.js
function genQRcode(p, n) {
const nl = '\n';
const rep = '<br>'
document.getElementById("qrcode").innerHTML = "";
document.getElementById("profile").innerHTML = "";
document.getElementById("title").innerHTML = "Profile Details (" + n + ")";
new QRCode(document.getElementById("qrcode"), p);
document.getElementById("profile").style.padding = "10px";
document.getElementById("profile").innerHTML = p.replaceAll(nl, rep);
}
// Create a new profile
function addn(pn) {
console.log(pn);
var newname = prompt("Enter profile name:", "");
if ((newname != null) && (newname != "")) {
var found = false;
for (var i = 0; i < pn.length; i++) {
if (pn[i]['pname'] == newname) {
found = true;
}
}
if (!found) {
fetch(`/addnew?newprofile=${newname}`).then((messages) => {console.log("messages");});
}
else { alert("profile already exists"); }
}
window.location = "http://192.168.1.3:8000/";
window.location.reload(true);
//return failse;
}
and finally the pug file
doctype html
html
head
meta(charset='utf-8')
title PiVPN Profiles
script !{addnew}
script(src='../scripts/qrcode.js')
script(src='../scripts/script.js')
link(rel="stylesheet", type="text/css", href="../styles/style.css")
body
.grid
.box.nav
a(href='/') Home
.btn(onclick=`addn(${JSON.stringify(vpnprofiles)});`) New Profile
.box.sidebar
h2 Profiles
ul
each prof in vpnprofiles
li(onclick=`genQRcode(${JSON.stringify(prof.profile)},${JSON.stringify(prof.pname)})`)=prof.pname
.box.content
h1#title Profile Details
p.qrcode#qrcode
p.profile#profile
.box.footer
p.small Version: 0.1a
Maybe I am reading this wrong, but can you make use of window.location = 'yourpage' (a client-side JS solution) or similar page refresh techniques?
I'm running the below node-rdkafka code in Eclipse as Node.js application. This is the sample code from https://blizzard.github.io/node-rdkafka/current/tutorial-producer_.html
I want to run this in a test server and call from iOS Mobile application.
I knew about running node.js app in AWS.
Question I: Is there any other options to run in a free test server environment like Tomcat?
Question II: Even If I am able to run this node.js app in a server, how do i call from a mobile application? Do I need to call producer.on('ready', function(arg) (or) What function i need to call from Mobile app?
var Kafka = require('node-rdkafka');
//console.log(Kafka.features);
//console.log(Kafka.librdkafkaVersion);
var producer = new Kafka.Producer({
'metadata.broker.list': 'localhost:9092',
'dr_cb': true
});
var topicName = 'MyTest';
//logging debug messages, if debug is enabled
producer.on('event.log', function(log) {
console.log(log);
});
//logging all errors
producer.on('event.error', function(err) {
console.error('Error from producer');
console.error(err);
});
//counter to stop this sample after maxMessages are sent
var counter = 0;
var maxMessages = 10;
producer.on('delivery-report', function(err, report) {
console.log('delivery-report: ' + JSON.stringify(report));
counter++;
});
//Wait for the ready event before producing
producer.on('ready', function(arg) {
console.log('producer ready.' + JSON.stringify(arg));
for (var i = 0; i < maxMessages; i++) {
var value = new Buffer('MyProducerTest - value-' +i);
var key = "key-"+i;
// if partition is set to -1, librdkafka will use the default partitioner
var partition = -1;
producer.produce(topicName, partition, value, key);
}
//need to keep polling for a while to ensure the delivery reports are received
var pollLoop = setInterval(function() {
producer.poll();
if (counter === maxMessages) {
clearInterval(pollLoop);
producer.disconnect();
}
}, 1000);
});
/*
producer.on('disconnected', function(arg) {
console.log('producer disconnected. ' + JSON.stringify(arg));
});*/
//starting the producer
producer.connect();
First of all, you need an HTTP server. ExpressJS can be used. Then, just tack on the Express code basically at the end, but move the producer loop into the request route.
So, start with what you had
var Kafka = require('node-rdkafka');
//console.log(Kafka.features);
//console.log(Kafka.librdkafkaVersion);
var producer = new Kafka.Producer({
'metadata.broker.list': 'localhost:9092',
'dr_cb': true
});
var topicName = 'MyTest';
//logging debug messages, if debug is enabled
producer.on('event.log', function(log) {
console.log(log);
});
//logging all errors
producer.on('event.error', function(err) {
console.error('Error from producer');
console.error(err);
});
producer.on('delivery-report', function(err, report) {
console.log('delivery-report: ' + JSON.stringify(report));
counter++;
});
//Wait for the ready event before producing
producer.on('ready', function(arg) {
console.log('producer ready.' + JSON.stringify(arg));
});
producer.on('disconnected', function(arg) {
console.log('producer disconnected. ' + JSON.stringify(arg));
});
//starting the producer
producer.connect();
Then, you can add this in the same file.
var express = require('express')
var app = express()
app.get('/', (req, res) => res.send('Ready to send messages!'))
app.post('/:maxMessages', function (req, res) {
if (req.params.maxMessages) {
var maxMessages = parseInt(req.params.maxMessages);
for (var i = 0; i < maxMessages; i++) {
var value = new Buffer('MyProducerTest - value-' +i);
var key = "key-"+i;
// if partition is set to -1, librdkafka will use the default partitioner
var partition = -1;
producer.produce(topicName, partition, value, key);
} // end for
} // end if
}); // end app.post()
app.listen(3000, () => console.log('Example app listening on port 3000!'))
I don't think the poll loop is necessary since you don't care about the counter anymore.
Now, connect your mobile app to http://<your server IP>:3000/ and send test messages with a POST request to http://<your server IP>:3000/10, for example, and adjust to change the number of messages to send
I might be late on this but this is how I did using promises and found it better than have a time out etc.
const postMessageToPublisher = (req, res) => {
return new Promise((resolve, reject) => {
producer.connect();
producer.setPollInterval(globalConfigs.producerPollingTime);
const actualBody = requestBody.data;
const requestBody = req.body;
const topicName = req.body.topicName;
const key = requestBody.key || uuid();
const partition = requestBody.partition || undefined;
const data = Buffer.from(JSON.stringify(udpatedBody));
/**
* Actual messages are sent here when the producer is ready
*/
producer.on(kafkaEvents.READY, () => {
try {
producer.produce(
topic,
partition,
message,
key // setting key user provided or UUID
);
} catch (error) {
reject(error);
}
});
// Register listener for debug information; only invoked if debug option set in driver_options
producer.on(kafkaEvents.LOG, log => {
logger.info('Producer event log notification for debugging:', log);
});
// Register error listener
producer.on(kafkaEvents.ERROR, err => {
logger.error('Error from producer:' + JSON.stringify(err));
reject(err);
});
// Register delivery report listener
producer.on(kafkaEvents.PUBLISH_ACKNOWLEDGMENT, (err, ackMessage) => {
if (err) {
logger.error(
'Delivery report: Failed sending message ' + ackMessage.value
);
logger.error('and the error is :', err);
reject({ value: ackMessage.value, error: err });
} else {
resolve({
teamName: globalConfigs.TeamNameService,
topicName: ackMessage.topic,
key: ackMessage.key.toString()
});
}
});
});
};
Please note that kafkaEvents contains my constants for the events we listen to and it is just a reference such as kafkaEvents.LOG is same as event.log
and also the calling function is expecting this to a promise and accordingly we user .then(data => 'send your response to user from here') and .catch(error => 'send error response to user
this is how I achieved it using promises
I've been able to create the database and query it. Using Microsoft's tutorial on using node.js to query, I have been able to accomplish this with this code:
// Simple Query
"use strict";
var documentClient = require("documentdb").DocumentClient;
var config = require("./config");
var url = require('url');
// use the previously saved config.endpoint and config.primaryKey to create a new DocumentClient
var client = new documentClient(config.endpoint, { "masterKey": config.primaryKey });
// These urls are how the DocumentDB client will find the right database and collection.
var HttpStatusCodes = { NOTFOUND: 404 };
var databaseUrl = `dbs/${config.database.id}`;
var collectionUrl = `${databaseUrl}/colls/${config.collection.id}`;
// Query JSON document collection
function queryCollection() {
console.log(`Querying collection through index:\n${config.collection.id}`);
return new Promise((resolve, reject) => {
client.queryDocuments(
collectionUrl,
'SELECT VALUE gd.NFL FROM GamblersDenDB gd WHERE gd.id = "SanDiego"'
).toArray((err, results) => {
if (err) reject(err)
else {
for (var queryResult of results) {
let resultString = JSON.stringify(queryResult);
console.log(`\tQuery returned ${resultString}`);
}
console.log();
resolve(results);
}
});
});
};
queryCollection()
Running that js file in my command prompt works! It results in the output:
C:\Users\kenv\Desktop\DocDB Test>node SimpleQuery.js
Querying collection through index:
GamblersDenColl
Query returned {"ID":"SDC","name":"Chargers"}
Great. So now I've transferred my code to my project's folder and try to run in the app with
taco run android --device
When I pull up the console, the first error that sticks out to me is
Uncaught ReferenceError: require is not defined(…)
It's pointing to the line var documentClient = require("documentdb").DocumentClient; in my code.
Here is my complete js file code that's throwing the error:
(function () {
"use strict";
document.addEventListener( 'deviceready', onDeviceReady.bind( this ), false );
function onDeviceReady() {
navigator.splashscreen.hide();
console.log("Cordova is READY!");
// Handle the Cordova pause and resume events
document.addEventListener( 'pause', onPause.bind( this ), false );
document.addEventListener( 'resume', onResume.bind( this ), false );
$(".btnURL").on("click", function(){loadURL($(this))});
function loadURL(theObj) {
cordova.InAppBrowser.open(theObj.data("url"), "_blank", "location=yes");
}
//********* jQuery VARIABLES ***************//
var $elBtnSaveName= $("#btnSaveName"),
$elShowClients= $("#btnShowClients"),
$elDivShow= $("#divShow"),
$elFormClient= $("#formClient");
//********** EVENT HANDLERS *****************//
$elShowClients.on("click", queryCollection);
//********************* DOCUMENT DB SECTION *********************************************************/
var documentClient = require("documentdb").DocumentClient;
var config = require("./config");
var url = require('url');
// use the previously saved config.endpoint and config.primaryKey to create a new DocumentClient
var client = new documentClient(config.endpoint, { "masterKey": config.primaryKey });
// These urls are how the DocumentDB client will find the right database and collection.
var HttpStatusCodes = { NOTFOUND: 404 };
var databaseUrl = `dbs/${config.database.id}`;
var collectionUrl = `${databaseUrl}/colls/${config.collection.id}`;
// Query JSON document collection
function queryCollection() {
console.log(`Querying collection through index:\n${config.collection.id}`);
return new Promise((resolve, reject) => {
client.queryDocuments(
collectionUrl,
'SELECT VALUE gd.NFL FROM GamblersDenDB gd WHERE gd.id = "SanDiego"'
).toArray((err, results) => {
if (err) reject(err)
else {
for (var queryResult of results) {
let resultString = JSON.stringify(queryResult);
console.log(`\tQuery returned ${resultString}`);
}
console.log();
resolve(results);
fnShowClientsTable(result.rows);
}
});
});
};
function fnShowClientsTable(data){
var str = "<p><table id='tableResults'";
str += "<tr><th>ID</th><th>Name</th><th class='thEmpty'> </th></tr>" //added class to <th> for formatting
for(var i = 0; i < data.length; i++) { // For X number of times worth of data...
str += "<tr><td>" + data[i].doc.ID +
"</td><td>" + data[i].doc.name +
"</td><td class='btnPencil'>✎</td></tr>";
}
str += "</table></p>"; // END table
$elDivShow.html(str); //Show string as HTML on screen
} // END fnShowClientsTable
//************************* END DOCUMENT DB SECTION ******************************************************/
}; // END onDeviceReady()
function onPause() {
// TODO: This application has been suspended. Save application state here.
};
function onResume() {
// TODO: This application has been reactivated. Restore application state here.
};
} )();
I realize my other function to push it to a string for display in HTML is probably wrong (which I will most certainly have another post about that one :)) but right now I'm trying to determine how I can get past this first error.
I am trying to write console log to a file. I tried this way and a log file is created but no contents are appended to it.Calling it at the start of the app. Am i doing something wrong.
function startFileLog() {
// choose where the file will be stored:
var fileDestination = Windows.Storage.ApplicationData.current.localFolder;
var logger = new WinJS.Promise(function (complete) {
var logfilename = new Date().toISOString().replace(/[:-]/g, "");
logfilename = "log-" + logfilename + ".log";
fileDestination.createFileAsync(logfilename,
Windows.Storage.CreationCollisionOption.generateUniqueName)
.done(function (file) {
complete(file);
});
});
var actionFn = function (message, tag, type) {
logger.then(function (file) {
var m = WinJS.Utilities.formatLog(message, tag, type);
Windows.Storage.FileIO.appendTextAsync(file, m).done();
});
};
WinJS.Utilities.startLog({ action: actionFn });
}