I'm trying to create a simple script to run a few node files, these files are just api's for a quote database , Authentication , and a twitch bot.
The Quote and Authentication work just find however they twitch bot does not it says its connected to the server but when it goes to execute any commands it gets a unhandled promise rejection or some such error
However when I run the twitch bot separately in its own terminal session and not from the script it works just fine with no thrown errors.
Why will it work from a separate session that I create but not from a child_process?
note: I have had the child_process start up a new shell and its still the same issue
The process script:
const exec = require('child_process').exec;
const spawn = require('child_process').spawn
// I think twtich bot process has an issue without how much
//data is being passed to stdout or stderr and I need
//to specify how much data is allowed
twitchBot = exec('node ./twitchbot-api/index.js',
function(error, stdout, stderr){
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if(error !== null){
console.log('exec error: ' + error);
}
})
twitchBot.stdout.on('data', (data) => {
console.log(`twitchBot stdout:\n${data}`);
});
//whenver I recieve an error from quoteDataBase it also displays in the parent process
twitchBot.stderr.on('data', (data) => {
console.error(`twitchBot stderr:\n${data}`);
});
//this throws an error the first time I try a command saying not connected to server , I think I need to do this as exec
// let twitchBot = spawn('node ./twitchbot-api/index.js',{
// stdio: 'inherit',
// shell: true,
// detached: true,
// })
// //twitchBot.unref();
// twitchBot.on('error', (error)=>{
// console.log(`the erorr ${error}`)
// })
//starts up a child exec process for my quotes database
let quoteDataBase = exec('node ./quotes-api/index.js',
function(error, stdout, stderr){
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if(error !== null){
console.log('exec error: ' + error);
}
})
//whatever the child exec process quoteDatabase pushs to the standard out (console) displays on the parent process
// aka the terminal I run apiStart from
quoteDataBase.stdout.on('data', (data) => {
console.log(`quoteDataBase stdout:\n${data}`);
});
//whenver I recieve an error from quoteDataBase it also displays in the parent process
quoteDataBase.stderr.on('data', (data) => {
console.error(`quoteDataBase stderr:\n${data}`);
});
//starts up a child process for my user Authentication
let AuthenDataBase = exec('node ./authen-api/index.js',
function(error, stdout, stderr){
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if(error !== null){
console.log('exec error: ' + error);
}
})
And then the twitch bot code:
const tmi = require('tmi.js')
const haikudos = require('haikudos')
require('dotenv').config()
require('es6-promise').polyfill();
require('isomorphic-fetch');
// Valid commands start with:
let commandPrefix = '!'
// Define configuration options:
let opts = {
identity: {
username: process.env.user,
password: process.env.pass
},
channels: [
"dshrops1"
]
}
// These are the commands the bot knows (defined below):
let knownCommands = { echo, haiku, quote }
// Function called when the "echo" command is issued:
function echo (target, context, params) {
// If there's something to echo:
if (params.length) {
// Join the params into a string:
const msg = params.join(' ')
// Send it back to the correct place:
sendMessage(target, context, msg)
} else { // Nothing to echo
console.log(`* Nothing to echo`)
}
}
// Function called when the "haiku" command is issued:
function haiku (target, context) {
// Generate a new haiku:
haikudos((newHaiku) => {
// Split it line-by-line:
newHaiku.split('\n').forEach((h) => {
// Send each line separately:
sendMessage(target, context, h)
})
})
}
async function quote (target, context){
//cant deploy this on AWS yet Untill I deploy my database api as well.
let quote = await fetch('http://localhost:3006/random').then(resp =>resp.text())
sendMessage(target,context,quote)
}
// Helper function to send the correct type of message:
function sendMessage (target, context, message) {
if (context['message-type'] === 'whisper') {
client.whisper(target, message)
} else {
client.say(target, message)
}
}
// Create a client with our options:
let client = new tmi.client(opts)
// Register our event handlers (defined below):
client.on('message', onMessageHandler)
client.on('connected', onConnectedHandler)
client.on('disconnected', onDisconnectedHandler)
// Connect to Twitch:
client.connect()
// Called every time a message comes in:
function onMessageHandler (target, context, msg, self) {
if (self) { return } // Ignore messages from the bot
// This isn't a command since it has no prefix:
if (msg.substr(0, 1) !== commandPrefix) {
console.log(`[${target} (${context['message-type']})] ${context.username}: ${msg}`)
return
}
// Split the message into individual words:
const parse = msg.slice(1).split(' ')
// The command name is the first (0th) one:
const commandName = parse[0]
// The rest (if any) are the parameters:
const params = parse.splice(1)
// If the command is known, let's execute it:
if (commandName in knownCommands) {
// Retrieve the function by its name:
const command = knownCommands[commandName]
// Then call the command with parameters:
command(target, context, params)
console.log(`* Executed ${commandName} command for ${context.username}`)
} else {
console.log(`* Unknown command ${commandName} from ${context.username}`)
}
}
// Called every time the bot connects to Twitch chat:
function onConnectedHandler (addr, port) {
console.log(`* Connected to ${addr}:${port}`)
}
// Called every time the bot disconnects from Twitch:
function onDisconnectedHandler (reason) {
console.log(`Womp womp, disconnected: ${reason}`)
process.exit(1)
}
Sorry About any formatting issues
Despite all the issues that might be wrong with the twitch bot it does work fine when I run it from a separate terminal I am curious as to why it does work from the script and what I can do.
notes: I figured it might have to do with the twitch api being a IRC.
Related
I have been trying to convert my existing Node JS code from function callback to Async Await, because a new SDK came out and callbacks are deprecated. These are the related codes. The code is communicating and publishing to a mqtt broker.
First here I call the ToggleX method
super.controlToggleX(channel, value, (err, res) => {
if (err) {
this.log(`Toggle Response: err: ${err}`);
}
this.log(`Toggle Response: res: ${JSON.stringify(res)}`);
});
After that in the controlToggleX method I set the payload for the message and make the publlish to the broker.
controlToggleX(channel, onoff, callback) {
const payload = { togglex: { channel, onoff: onoff ? 1 : 0 } };
return this.publishMessage('SET', 'Appliance.Control.ToggleX', payload, callback);
}
In the publishMessage I compile the message to the broker and publish it. After publishing I waiting for the response and to keep track of the ongoing messages I create the waitingMessageIds array.
publishMessage(method, namespace, payload, callback) {
this.clientResponseTopic = `/app/${this.userId}-${appId}/subscribe`;
const messageId = crypto.createHash('md5').update(generateRandomString(16)).digest('hex');
const timestamp = Math.round(new Date().getTime() / 1000); // int(round(time.time()))
const signature = crypto.createHash('md5').update(messageId + this.key + timestamp).digest('hex');
const data = {
header: {
from: this.clientResponseTopic,
messageId,
method,
namespace,
payloadVersion: 1,
sign: signature,
timestamp,
},
payload,
};
this.client.publish(`/appliance/${this.uuid}/subscribe`, JSON.stringify(data));
if (callback) {
this.waitingMessageIds[messageId] = {};
this.waitingMessageIds[messageId].callback = callback;
this.waitingMessageIds[messageId].timeout = setTimeout(() => {
// this.log('TIMEOUT');
if (this.waitingMessageIds[messageId].callback) {
this.waitingMessageIds[messageId].callback(new Error('Timeout'));
}
delete this.waitingMessageIds[messageId];
}, 20000);
}
this.emit('rawSendData', data);
return messageId;
}
When a new message comes from the broker I check the waitingMessageIds array, the messageId is in the array? If yes I delete the Timer and process the message with the callback coming from the publishing.
this.client.on('message', (topic, message) => {
if (!message) return;
// message is Buffer
try {
message = JSON.parse(message.toString());
} catch (err) {
this.emit('error', `JSON parse error: ${err}`);
return;
}
if (message.header.from && !message.header.from.includes(this.uuid)) return;
if (this.waitingMessageIds[message.header.messageId]) {
if (this.waitingMessageIds[message.header.messageId].timeout) {
clearTimeout(this.waitingMessageIds[message.header.messageId].timeout);
}
this.waitingMessageIds[message.header.messageId].callback(null, message.payload || message);
delete this.waitingMessageIds[message.header.messageId];
} else if (message.header.method === 'PUSH') {
const namespace = message.header ? message.header.namespace : '';
this.log('Found message');
this.emit('data', namespace, message.payload || message);
}
this.emit('rawData', message);
});
mqtt package is working with callback, but the async-mqtt is returning Promise so it is going to be good for me.
I was successfull to publish with it, and after that point I put the messageId to the array and start a timer, but when the reply came i was not been able to proocess the waitingMessageIds and return to the original point (super.controlToggleX).
Could somebody please help me. Thank
Edit:
I tried to rewrite PublishMessage with async-mqtts and it looks like this:
async publishMessage(method, namespace, payload) {
.
.
.
try {
await this.client.publish(`/appliance/${this.uuid}/subscribe`, JSON.stringify(data));
} catch (err) {
return new Error(err);
}
this.waitingMessageIds[messageId] = {};
// this.waitingMessageIds[messageId].callback = callback;
this.waitingMessageIds[messageId].timeout = setTimeout(() => {
// this.log('TIMEOUT');
if (this.waitingMessageIds[messageId].callback) {
this.waitingMessageIds[messageId].callback(new Error('Timeout'));
}
delete this.waitingMessageIds[messageId];
}, 20000);
this.emit('rawSendData', data);
return messageId;
}
Because with the await publish waits for the response I do not need check if it is a callback, i just put the messageId into the waitingmessageIds array.
When I process the incoming message in this.client.on('message' I don not know how to change this -> this.waitingMessageIds[message.header.messageId].callback(null, message.payload || message);
I would like to send "Hello world" from one nodejs server to another using node-serialport. I have verified that the radios connecting the two are connected and sending info because they keep displaying buffer information after running my current code.
here is what I have so far.
server1
// Import dependencies
const SerialPort = require("serialport");
const Readline = require("#serialport/parser-readline");
var sf = require('sf');
//SerialPort.list(function (err, results) {
// if (err) {
// throw err;
// }
SerialPort.list().then(ports => {
ports.forEach(function(port) {
console.log(port.path);
console.log(port.pnpId);
console.log(port.manufacturer);
});
});
// Defining the serial port
const port = new SerialPort('COM3',{baudRate: 9600}, function (err) {
if (err) {
return console.log('Port Error: ', err.message)
}
})
port.write('main screen turn on', function(err) {
if (err) {
return console.log('Error on write: ', err.message)
}
console.log('message written')
})
// Read data that is available but keep the stream in "paused mode"
port.on('readable', function () {
console.log('Data:', port.read())
})
// Switches the port into "flowing mode"
port.on('data', function (data) {
console.log('Data:', data)
})
// Pipe the data into another stream (like a parser or standard out)
const lineStream = port.pipe(new Readline())
lineStream.on('data', console.log)
server 2
// Import dependencies
// in Ubuntu need to run command: sudo chmod 666 /dev/ttyS0 to open port for use
const SerialPort = require("serialport");
const Readline = require("#serialport/parser-readline");
var stoploop = true;
// Defining the serial port
const port = new SerialPort('/dev/ttyUSB0', function (err) {
if (err) {
return console.log('Error: ', err.message)
}
})
port.write('chicken butt', function(err) {
if (err) {
return console.log('Error on write: ', err.message)
}
console.log('message written')
})
// port.write("hello?");
// Read data that is available but keep the stream in "paused mode"
port.on('readable', function () {
console.log('Data:', port.read())
})
// Switches the port into "flowing mode"
port.on('data', function (data) {
console.log('Data:', data)
})
// Pipe the data into another stream (like a parser or standard out)
const lineStream = port.pipe(new Readline())
any help or even an example of how to send hello world between the two would be greatly appreciated! please let me know if any more info is needed.
edit : I recently tried doing something like
port.on('data', (data) => {
try {
console.log(data.toString());
} catch (err) {
console.log('Oops');
}
});
this is taking data that used to appear as <buffer # # # # #> and turning it into an odd string like "(
)))) ) ) )))
!)☺)!))) ) )
)(☺!�"
I found the answer myself!
I was using the wrong baudRate, and also needed to stringify the data being sent as a JSON string
Is it possible to run cmd.exe and execute some command with Electron.js?
If yes then how can I do this?
In your main.js file, you can put the following code:
//Uses node.js process manager
const electron = require('electron');
const child_process = require('child_process');
const dialog = electron.dialog;
// This function will output the lines from the script
// and will return the full combined output
// as well as exit code when it's done (using the callback).
function run_script(command, args, callback) {
var child = child_process.spawn(command, args, {
encoding: 'utf8',
shell: true
});
// You can also use a variable to save the output for when the script closes later
child.on('error', (error) => {
dialog.showMessageBox({
title: 'Title',
type: 'warning',
message: 'Error occured.\r\n' + error
});
});
child.stdout.setEncoding('utf8');
child.stdout.on('data', (data) => {
//Here is the output
data=data.toString();
console.log(data);
});
child.stderr.setEncoding('utf8');
child.stderr.on('data', (data) => {
// Return some data to the renderer process with the mainprocess-response ID
mainWindow.webContents.send('mainprocess-response', data);
//Here is the output from the command
console.log(data);
});
child.on('close', (code) => {
//Here you can get the exit code of the script
switch (code) {
case 0:
dialog.showMessageBox({
title: 'Title',
type: 'info',
message: 'End process.\r\n'
});
break;
}
});
if (typeof callback === 'function')
callback();
}
Now, you can execute arbitary command (the example is from windows command prompt, but the funtion is universal) by calling:
run_script("dir", ["/A /B /C"], null);
The parameters of your command are in fact an array ["/A /B /C"], and the last parameter is callback to be executed, you can provide null as parameter, if special callback function is not needed.
it is possible by using node child_process , You can use this function:
const exec = require('child_process').exec;
function execute(command, callback) {
exec(command, (error, stdout, stderr) => {
callback(stdout);
});
};
// call the function
execute('ping -c 4 0.0.0.0', (output) => {
console.log(output);
});
and there are many packages in npm for this topic to .
I am using node.js to monitor a website's API for commands and choose the appropriate child process based on the said command. Only one child process should be running at a time. As of now, child process 1 begins on startup of the node.js script (good). Then, when a command is heard child process 2 starts up (also good), but along with child process 1 still running in the background (not good).
How can I get child process 1 to be terminated on the start of child process 2? I am currently using ("child_process").exec; and my code is mostly working, should I be using ("child_process").fork; or ("child_process").spawn; instead?
I have tried using execFile.kill('SIGTERM'); on startup of child process 2, as well as an else/if statement without any luck. (I'll cut down on the non-essential code below).
const tmi = require('tmi.js');
var exec = require("child_process").exec;
var execFile = require('child_process').exec;
.
.
.
(edited out)
.
.
.
// Register our event handlers (defined below)
client.on('connected', (address, port) => {
client.action('account', 'phrase');
execFile('/path/script.py, function(error, stdout, stderr) {
if (error) {
throw error;
return;
}
});
});
client.on('chat', (channel, user, message, self) => {
if (message === '!exec') {
execFile.kill('SIGTERM'); //to try and terminate child process 1 above
exec('/path/script.py , function(error, stdout, stderr) {
if (error) {
console.error(`exec error: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
});
}
});
I have worked on this issue for a while without much progress. Any and all insight is appreciated!
const tmi = require('tmi.js');
var exec = require("child_process").exec;
var execFile = require('child_process').exec;
var child;
.
.
.
(edited out)
.
.
.
// Register our event handlers (defined below)
client.on('connected', (address, port) => {
client.action('account', 'phrase');
child = execFile('/path/script.py, function(error, stdout, stderr) {
if (error) {
throw error;
return;
}
});
});
client.on('chat', (channel, user, message, self) => {
if (message === '!exec') {
child.kill(); //kills the child process.
}
});
Here is the example code. The below code starts the mongo server with child process and after 10 secs it will get killed.
const child = require('child_process');
const ls = child.exec('mongod --dbpath ~/Documents/myown/learning/mongo', (err, stdout, stderr) => {
if(err) {
console.log(err);
}
else {
console.log(stdout);
}
});
setTimeout(() => {
ls.kill();
}, 10000);
I am currently building a Web based SSH client. I am using node and SSH2 module to connect to Linux machine . The issue is trying to identify when the server is waiting for a response from the client say "sudo" .
this.onWsMessage = function(packet) {
log('Message Received from ');
if (cmd != '') {
log('----------------------------------------->' + cmd);
source[this.getId()].sshStream.write(cmd + '\n');
}
};
var client = clients[cid];
sshClient
.on('ready', function() {
console.log('CONNECTED');
sshClient.shell({pty: true}, function(err, stream) {
_shellHandler(err, stream, client);
});
})
.on('error', function(err) {
console.log('ERROR', err);
})
.connect(serverInfo);
}
function _shellHandler(err, stream, client) {
source[client.getId()].sshStream = stream;
stream
.on('close', function() {
log('ssh connection close');
//sshClient.end();
this._client.end();
})
.on('data', function(data) {
console.log(stream);
var msg = data.toString().replace(msgPattern, '');
this.sendUTF(msg, 'ssh');
}.bind(client));
}
I have been going through the documentation and i was unable to identify any event that trigger as a result.
There is no easy way to do this. Basically you have to either buffer stream output and continually search that buffer for expected (sudo) prompts or use a module like streamsearch to search the stream for a particular string without explicitly buffering and continual searching.