Im trying to use proto messages with protobuf.js, encode them and send them to a RabbitMQ message broker. I have the following sub-folders inside my project:
- model
- protos
- transactions.proto
- RabitMQ.js
- routes
- rmq-api.js
I added a route which does the following(Using express) in the rmq-api.js file:
const RabbitMQ = require('../model/RabbitMQ');
router.post('/api/transactions' ,function (req,res,next) {
RabbitMQ.PublishTransactionsMessage(DummyMessage).then(() => {
res.status(200).send({message: "OK :)"});
}).catch((e) => {
res.status(500).send({error:e.message});
});
});
In the RabitMQ.js file I have the following code:
module.exports = {
PublishTransactionsMessage: function(message) {
return new Promise((resolve, reject) => {
amqp.connect(RabbitMQConfig.url, function (error, connection) {
if (error) {
console.error("Could not connect to the rabbit message broker on {0} - " +
"Check connection please and try again".format(RabbitMQConfig.url));
console.error("Error message - {0}".format(error));
reject(error)
}
connection.createChannel(function(error, channel) {
if (error) {
console.error("Could Create channel - {0}".format(error.message));
reject(error)
}
const queue = RabbitMQConfig.queue;
channel.assertQueue(queue, {
durable: true
});
// Convert Message to protobuff
protobuf.load("./protos/transactions.proto").then((err, root) => {
if (err) {
reject(err);
}
let ScraperMessageResult = root.lookupType("transactions.ScraperMessageResult");
const errMsg = ScraperMessageResult.verify(message);
if (errMsg)
reject(errMsg);
let buffer = ScraperMessageResult.encode(message).finish();
channel.sendToQueue(queue, buffer);
console.log(`Sent ${message} to queue: ${queue}`);
resolve()
}).catch((err) => {
reject(err);
});
});
});
});
},
};
In the code shown above in the line:
protobuf.load("./protos/transactions.proto").then((err, root) => {
I keep catching the following error:
Inside this catch block:
}).catch((err) => {
reject(err);
});
This seems like a pretty simple problem however I havent found anything on this online so I might be missing something really simple here.
P.S. I tried using __dirname + "/protos/transaction.proto" and still couldnt get this to work.
Please help me figure this out.
The problem is that your function doesn't look at the dist directory,
await protocolBuffer.load(__dirname + '/item.proto'); should look there,
and also you need to copy the file manuly by using copy/cp command, you can add it as part of the package json script like so:
"build": "nest build && COPY src\\reading_list\\protocol_buffer\\*.proto dist\\reading_list\\protocol_buffer\\"
Related
I'm creating a Discord bot, but have some problems catching the errors that my bot sends.
I'm using a custom command handler, that is working pretty well.
Fs.readFile(`./database/prefixes/prefixes.json`, "utf8", (err: Error, data): void => {
data = JSON.parse(data);
const prefix: string = data[message.author.id] == undefined ? "ma!" : data[message.author.id];
const msg: string = message.content;
const args: string[] = message.content.slice(prefix.length).trim().split(" ");
const cmd: string = args.shift().toLowerCase();
if (!msg.startsWith(prefix)) {
return checkCustomCommands();
}
let ops: {} = {
queue: queue
}
try {
require(checkFolders(cmd)).run(Client, message, args, ops); // maybe catching just there?
Logger.log(`${message.author.tag} just used the ${cmd} power in ${message.guild.name}.`);
} catch (err) {
Logger.log(`The command ${message.author.tag} tried to call in ${message.guild.name} doesen't seem to exist.`);
}
});
function checkCustomCommands() {
let content = JSON.parse(Fs.readFileSync('./database/commands/commands.json', 'utf8'));
try {
if (content[message.guild.id][message.content] == undefined) {
return;
} else {
message.channel.send(content[message.guild.id][message.content]);
}
} catch (err) {
return;
}
}
function checkFolders(command) {
let folders = ["moderation", "fun", "music", "info", "game"];
var files: string[];
var finalPath: string;
folders.forEach(folder => {
files = Fs.readdirSync(`./src/commands/${folder}`);
files.forEach(file => {
if (file.split(".")[0] == command) {
return finalPath = `./../commands/${folder}/${file.split(".")[0]}.js`;
}
});
});
return finalPath;
}
But sometimes, my bot sends various errors that I can't catch into the commands files, resulting in my bot being shutdown. Is there any way to prevent that inside the command handler, or anything I can do to catch these errors?
Thanks a lot, I can provide more code if needed, even though the biggest chunk of the command handler is just there ^
I'm quite late to this, but I feel like I should answer my own question, now that I'm able to do so haha
The main way to catch these errors is by listening to the unhandledRejection event, via Node process.
Here's how I did it:
async function handleRejections() {
process.on("unhandledRejection", (error: Error) => {
const errorEmbed: Discord.MessageEmbed = new Discord.MessageEmbed()
.setDescription("<:no:835565213322575963> An error has been detected... \n" + `\`\`\`${error.stack}\`\`\``)
.setTimestamp()
.setFooter(client.user.username, client.user.displayAvatarURL())
.setColor("DARK_RED")
logError(client, errorEmbed);
});
}
Be sure to call the function at the very beginning of the project code, even before the bot starts.
I personally log these errors into a Discord channel, on my server, so that I can check them easily. That's it! Hope that helps. Keep on coding :D
The below code snippet is working fine. But sometimes it's not reading messages from Kafka's topic. I am not getting any errors. At Kafka's side(we are using Aiven Managed Kafka), the consumer group has associated with the topic and consumer script is running nicely.
I need your guidance to resolve the above issue.
Kafka Version - 2.0.1
Node Module Version - "node-rdkafka": "^2.7.0"
Code Ref - https://github.com/Blizzard/node-rdkafka
const Kafka = require('node-rdkafka');
const path = require('path');
console.log(Kafka.features);
const consumer = new Kafka.KafkaConsumer({
'group.id': 'testxyz',
'metadata.broker.list': "kafka-production-url",
'security.protocol': 'SSL',
'ssl.key.password': "password",
'ssl.key.location': '/var/www/html/config/service.key',
'ssl.certificate.location': '/var/www/html/config/service.cert',
'ssl.ca.location': '/var/www/html/config/ca.pem',
'socket.keepalive.enable': true,
'enable.auto.commit': false,
'rebalance_cb': function(err, assignment) {
if (err.code === Kafka.CODES.ERRORS.ERR__ASSIGN_PARTITIONS) {
// Note: this can throw when you are disconnected. Take care and wrap it in
// a try catch if that matters to you
this.assign(assignment);
} else if (err.code == Kafka.CODES.ERRORS.ERR__REVOKE_PARTITIONS){
// Same as above
this.unassign();
} else {
// We had a real error
console.error(err);
}
},
'offset_commit_cb': function (err: any, topicPartitions: any) {
if (err) {
// There was an error committing
console.error("error in commit", err);
} else {
// Commit went through. Let's log the topic partitions
console.log("Success in commit", topicPartitions);
}
}
},
'auto.offset.reset': 'earliest');
consumer.on('ready', {
consumer.subscribe("mytopic");
consumer.consume();
});
// handle the messgae
consumer.on('data', {
console.log(data);
});
consumer.on('disconnected', {
console.log("onDisconnected",args);
});
consumer.connect();
I'm writing the backend for creating audit protocols. The user should be able to create criterias for the audit protocol. For this, i have the following backend-method to make sure, the protocol gets only created completely or the process of creating is canceled. It is possible to set several kinds of forms / criterias. But it could be, that only one kind of form is required. I do check that with the if-statement.
The creating works as expected. But the REST API always returns null to the clients. So i can't do further processing on the frontend regarding to the result of the creation process.
Technologies: Node.js and Sequelize. Frontend in angular / ionic. Database in mySQL.
I tried around with some transaction passing and return statements. I tried to compare it to a similiar code snippet, which works as expected.
exports.setAudit = (req, res, next) => {
trueFalseCriteria = req.body.trueFalseForms;
isShouldCriteria = req.body.isShouldForms;
generalCriteria = req.body.generalForms;
measurementCriteria = req.body.measurementForms;
toolId = req.body.toolId;
// Transaction is used to roll the whole transaction back if something wents wrong
return sequelize
.transaction(t => {
return audit
.create(
{
// Creating an audit referencing the tool
toolId: toolId
},
{ transaction: t }
)
.then(
// Getting the id of the audit that we just created
audit => {
return audit.id;
},
{ transaction: t }
)
.then(auditId => {
// Check wether the kind of form is used or not. If so, sequelize tries to do a bulk insert into the databases.
// Each bulk insert throws an error if it fails to cancel the whole transaction
if (trueFalseCriteria) {
console.log(1);
trueFalseCriteria.forEach(dataEl => {
dataEl.auditId = auditId;
});
trueFalseCriterion.bulkCreate(trueFalseCriteria).catch(err => {
// Throw error to cancel transaction
throw new Error(err);
});
}
if (isShouldCriteria) {
console.log(2);
isShouldCriteria.forEach(dataEl => {
dataEl.auditId = auditId;
});
isShouldCriterion.bulkCreate(isShouldCriteria).catch(err => {
// Throw error to cancel transaction
throw new Error(err);
});
}
if (generalCriteria) {
console.log(3);
generalCriteria.forEach(dataEl => {
dataEl.auditId = auditId;
});
generalCriterion.bulkCreate(generalCriteria).catch(err => {
// Throw error to cancel transaction
throw new Error(err);
});
}
if (measurementCriteria) {
console.log(4);
measurementCriteria.forEach(dataEl => {
dataEl.auditId = auditId;
});
measurementCriterion.bulkCreate(measurementCriteria).catch(err => {
// Throw error to cancel transaction
throw new Error(err);
});
}
}, { transaction: t });
})
.then(data => {
console.log(5);
res.status(200).json(data);
})
.catch(err => {
console.log(6);
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
});
};
Expected result: Http response with status code 200 on success
Actual result: null
I think you are missing a return for the last .then():
.then(auditId => {
// Check wether the kind of form is used or not. If so, sequelize tries to do a bulk insert into the databases.
.....
if (measurementCriteria) {
....
}
// RETURN SOMETHING HERE
}, { transaction: t });
I have a delete route which deletes an image file. Following is the code:
router.delete('/:id', (req, res) => {
let pathForThumb = '';
let pathForImage = '';
Image.findOne({ _id: req.params.id })
.then(getImage => {
pathForThumb = getImage.thumbPath;
pathForImage = getImage.imagePath;
getImage.remove();
})
.then(removeThumb => {
fs.unlink(pathForThumb, (err) => {
if (err) {
req.flash('error_msg', 'There was an error deleting the thumbnail');
res.redirect('/user/userdashboard');
}
});
})
.then(removeMainImage => {
fs.unlink(pathForImage, (err) => {
if (err) {
console.log(err);
req.flash('error_msg', 'There was an error deleting the main image');
res.redirect('/user/userdashboard');
} else {
req.flash('success_msg', 'Image removed');
res.redirect('/user/userdashboard');
}
});
})
.catch(err => {
console.log(err);
});
});
as you can see when I upload a file I store it's path and also generate a thumbnail in the /uploads/thumbs/ folder and store the path of the thumb nail as well. In the above code I first get the image using findOne, store the paths of both images in variables and then call fs.unlink in a promise. What is happening is that my thumbnail gets deleted but I am getting the following error in the removeMainImage then condition:
{ Error: EBUSY: resource busy or locked, unlink 'C:\Users\Amin Baig\Desktop\Teaching\galleryprj\public\uploads\XC6kPqWf9_dphaBmUG__I7SN7PAEl_1531823330941_CEI21.jpg'
errno: -4082,
code: 'EBUSY',
syscall: 'unlink',
path: 'C:\\Users\\Amin Baig\\Desktop\\Teaching\\galleryprj\\public\\uploads\\XC6kPqWf9_dphaBmUG__I7SN7PAEl_1531823330941_CEI21.jpg' }
I am using windows 10 for my dev environment os.
Have been trying to find a solution for this, please help.
In my experience, Windows behaves unpredictable when it comes to file locks. In my projects I fixed errors like this by retrying until it works.
Here's some example code:
/**
* On windows, the file lock behaves unpredictable. Often it claims a databsae file is locked / busy, although
* the file stream is already closed.
*
* The only way to handle this reliably is to retry deletion until it works.
*/
const deleteFile = async (filePath) => {
try {
await unlink(filePath);
} catch (err) {
unlinkRetries--;
if (unlinkRetries > 0) {
await deleteFile();
} else {
throw err;
}
}
}
I revised appium source code, add my code, when i connect to the port that is forwarded to device and send command to port, it comes out:
Error: This socket has been ended by the other party
and my code is like this:
return await new Promise((resolve, reject) => {
try {
this.socketClient = net.connect(this.webSocket);
// Windows: the socket errors out when ADB restarts. Let's catch it to avoid crashing.
this.socketClient.on('error', (err) => {
if (!this.ignoreUnexpectedShutdown) {
//throw new Error(`Android bootstrap socket crashed: ${err}`);
log.debug('//////////////////////////////////')
log.debug(err)
log.debug('//////////////////////////////////')
throw new Error(`Android testbundle socket crashed: ${err}`)
}
});
this.socketClient.once('connect', () => {
log.info("Android bundle socket is now connected");
resolve();
});
} catch (err) {
reject(err);
}
})
after that, I use this.socketClient to send command like this:
async sendCommand(type, extra = {}) {
if (!this.socketClient) {
log.debug('==========socket closed========')
throw new Error('Socket connection closed unexpectedly');
}
return await new B((resolve, reject) => {
let cmd = Object.assign({cmd: type}, extra);
let cmdJson = `${JSON.stringify(cmd)}\n`;
log.debug(`Sending command to android testbundle: ${_.trunc(cmdJson, 1000).trim()}`);
this.socketClient.write(cmdJson);
this.socketClient.setEncoding('utf8');
let streamData = '';
this.socketClient.on('data', (data) => {
try {
streamData = JSON.parse(streamData + data);
// we successfully parsed JSON so we've got all the data,
// remove the socket listener and evaluate
this.socketClient.removeAllListeners('data');
if (streamData.status === 0) {
resolve(streamData.value);
}
log.debug("Received command result from bundle:" + JSON.stringify(streamData));
reject(errorFromCode(streamData.status));
} catch (ign) {
log.debug("Stream still not complete, waiting");
streamData += data;
}
})
})
}
But, I always get the error:
[debug] [bundle] //////////////////////////////////
[debug] [bundle] Error: This socket has been ended by the other party
at Socket.writeAfterFIN [as write] (net.js:291:12)
at ..\../lib/bundle.js:160:31
Anyone can help me...