Force MicroService to await until RabbitMQ publishes a message , using Cote - node.js

I have a an API-GATEWAY MicroService that manages the entire show , and one of the services is called QueueService.
Here is the API-Gateway
const express = require('express')
const bodyParser = require('body-parser')
const cote = require('cote')
const cors = require('cors');
const app = express()
app.use(bodyParser.json())
app.use(cors());
app.post('/queue-msg', async (req, res, next) => {
let { from, to } = req.body;
const payload = {
from, to
}
const queue = await queueRequester.send({ type: 'create-queue-message', payload })
res.status(200).send({ "message-sent": true, queue });
});
This is thq QueueService :
const cote = require('cote')
const queueProducer = require('./utils/queueProducer');
const queueName = 'pathfinderqueue';
const queueResponder = new cote.Responder({ name: 'queue responder', key: 'deliveries' })
queueResponder.on('*', req => req.type && console.log(req))
const deliveries = []
let idCounter = 0
queueResponder.on('create-queue-message', req => {
async function makeRequest() {
console.log('Got a message from API-GATEWAY!');
let { payload } = req; // get From & To
queueProducer.publishToQueue(queueName, payload); // Publish to Rabbit
const queue = { id: idCounter++, status: 'pending' } // Set the ID
deliveries.push(queue)
return Promise.resolve(queue)
}
const response = makeRequest();
return response;
})
However every time that API-Gateway publishes a message from the React client to the QueueService , the QueueService doesn't awaits in the on event , and sends back a
"message-sent": true
to the client.
How can we force QueueService to await ?

Related

caching query with redis

i need to cache a query with redis and node js , the database is aws s3 ,the problem here as a noob ,i will recive the query as a string, i need to encode the keys in the body request so when i will later try to fetsch the data i will use one of those keys(they need to be seperated with '/') can anyone help me with that and bunch of thanks.
here is what i' tried to do:
const { default: axios } = require('axios');
const express = require('express');
const redisClient = require('./helper/Client')
const app = express();
const port = process.env.PORT || 3000
app.use(express.json());
async function fetchApi(species){
const apiResponse = await axios.get(`https://www.fishwatch.gov/api/species/${species}`)
console.log('request sent successfully');
return apiResponse.data
}
async function getSpeciesData(req, res) {
const species = req.body;
const keys = Object.keys(species);
const encodedParams = {};
for (const key of keys) {
const encodedKey = Buffer.from(key).toString('base64');
encodedParams[encodedKey] = species[key];
}
const key = JSON.stringify(encodedParams);
let resultat;
let isCached = false;
const cachedResponse = await redisClient.get(key);
if (cachedResponse) {
isCached = true;
const decodedResponse = Buffer.from(cachedResponse, 'base64').toString('utf-8');
resultat = JSON.parse(decodedResponse);
res.send({
fromCache: isCached,
data: resultat
});
console.log(cachedResponse);
} else {
const responseData = await fetchApi(keys.join('/'));
const encodedResponseData = Buffer.from(JSON.stringify(responseData)).toString('base64');
redisClient.SETEX(key, 3600, encodedResponseData);
res.send(responseData);
}
}
app.post("/fish", getSpeciesData);
app.listen(port, () => {
console.log(`Listening on ${port}`);
});

webpush not wokring in chrome on localhost

I'm building a website with node.js and I' m making some push notifications and it doesn' t send them on chrome version 109.0.5414.120 . I tried running it on opera gx and it worked there. I have to use chrome because its for a school project and all my teachers use chrome and the don't want to download new programms
the code;
app.js
const express = require("express")
const webpush = require('web-push')
const app = express()
app.use(express.json());
const path = require("path")
app.use(express.static(path.join(__dirname, 'client')))
const publicKey = "BL2QpTNn-CZARUqJhm4tDPPful3TMIjugZdyi1WNIcaps21w7KJFy4cjilMNk-NbeEIwWVA5ddCXpOStd6RTuXA"
const privateKey = "dWcFCcnNS-uBYS6GISodobLXht-9KpOQmeHh1h89T7w"
webpush.setVapidDetails("mailto:thdegroote18#gmail.com", publicKey, privateKey)
app.post("/subscribe", async (req, res) => {
try {
// Subscription Details From the client side , We would get back to this
const subscription = req.body;
subscribers.push(subscription);
// Save the new subscrber to the subscribers file
fs.writeFileSync("./subscribers.json", JSON.stringify(subscribers));
res.status(201).send("Subscription Saved");
} catch (error) {
console.error(error);
}
});
const subscribers = require("./subscribers.json")
const fs = require("fs")
async function sendPushNotificaiton() {
for (let i = 0; i < subscribers.length; i++) {
const subscription = subscribers[i];
//Notification Payload, this could contain more information about the notification
const payload = {
title: "Push Test",
body: " Push Notification Message",
icon: "https://blog.mensaiah.com/assets/round_logo.png",
};
//Pass object into sendNotification
await webpush.sendNotification(subscription, JSON.stringify(payload));
}
}
//Send Notification Every Minute
const durationInMillisecond = 60 * 10000
setInterval(sendPushNotificaiton,durationInMillisecond);
const port = 1999
app.listen(port, () => {
console.log(`server started on port ${port}`)
})
client.js
const publicVapidKey = "BL2QpTNn-CZARUqJhm4tDPPful3TMIjugZdyi1WNIcaps21w7KJFy4cjilMNk-NbeEIwWVA5ddCXpOStd6RTuXA";
async function subscribeToPush() {
console.log("Registering service worker...");
const register = await navigator.serviceWorker.register("/worker.js", {
scope: "/"
});
console.log("Service Worker Registered...");
console.log("Registering Push...");
const subscription = await register.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(publicVapidKey)
});
console.log("Push Registered...");
console.log("Subscribing for Push ...");
await fetch("http://localhost:1999/subscribe", {
method: "POST",
body: JSON.stringify(subscription),
headers: {
"Content-Type":"application/json"
}
});
}
function urlBase64ToUint8Array(base64String) {
const padding = "=".repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, "+")
.replace(/_/g, "/");
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
if ('serviceWorker' in navigator) {
subscribeToPush().catch(console.log);
}
worker.js
self.addEventListener("push", e => {
// Data from service
const data = e.data.json();
console.log("Push Recieved...");
self.registration.showNotification(data.title, {
body: data.body,
icon: data.icon,
});
});

Stripe webook signature verification failed using express

Hey stack overflow so I am using webooks with stripe. For some reason I am getting the error "Stripe webook signature verification failed". Here is my source code below. Any ideas on how I can get it working? I know it has something to do with the bodyparser. But I am not able to figure out a workaround to get the stripe webhooks working.
Error Message:
Webhook signature verification failed. No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? https://github.com/stripe/stripe-node#webhook-signing
require("dotenv").config();
const express = require("express");
var cors = require('cors')
const axios = require("axios");
const bodyParser = require("body-parser");
const Stripe = require('stripe');
const stripe = Stripe('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
const invoiceDescription = require('./constants');
const endpointSecret = "whsec_w5Qipi3Wz0fm8sSCHcJIHwWfobS0kfYe";
const { TOKEN, SERVER_URL, BOTTOKEN } = process.env;
const TELEGRAM_API = `https://api.telegram.org/bot${TOKEN}`;
const URI = `/webhook/${TOKEN}`;
const WEBHOOK_URL = SERVER_URL + URI;
const app = express();
app.use(cors());
app.use(bodyParser.json());
const init = async () => {
const res = await axios.get(`${TELEGRAM_API}/setWebhook?url=${WEBHOOK_URL}`);
console.log(res.data);
};
app.post('/webhook', express.raw({type: 'application/json'}), (request, response) => {
let event = request.body;
// Only verify the event if you have an endpoint secret defined.
// Otherwise use the basic event deserialized with JSON.parse
if (endpointSecret) {
// Get the signature sent by Stripe
console.log(request.headers)
const signature = request.headers['stripe-signature'];
try {
event = stripe.webhooks.constructEvent(
request.body,
signature,
endpointSecret
);
} catch (err) {
console.log(`⚠️ Webhook signature verification failed.`, err.message);
return response.sendStatus(400);
}
}
// Handle the event
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`);
// Then define and call a method to handle the successful payment intent.
// handlePaymentIntentSucceeded(paymentIntent);
console.log('payment intent is', paymentIntent)
break;
case 'payment_method.attached':
const paymentMethod = event.data.object;
// Then define and call a method to handle the successful attachment of a PaymentMethod.
// handlePaymentMethodAttached(paymentMethod);
console.log('payment method is', paymentMethod)
break;
default:
// Unexpected event type
console.log(`Unhandled event type ${event.type}.`);
}
// Return a 200 response to acknowledge receipt of the event
response.send();
});
app.post(URI, async (req, res) => {
let text = "", chatId = "", userObjectForTable = {};
if(req.body.message?.chat?.id && req.body.message?.text && req.body.message?.text === "Start"){
chatId = req.body.message.chat.id;
text = invoiceDescription;
const message = await axios.post(`${TELEGRAM_API}/sendMessage`, {
chat_id: chatId,
text: text,
reply_markup: {
inline_keyboard: [[{
text: 'Pay $65.00',
web_app: {url: 'https://buy.stripe.com/test_14kbKj3Gd0AGeRi7ss' }
}]]
}
});
}
return res.send();
});
app.listen(process.env.PORT || 5050, async () => {
console.log("🚀 app running on port", process.env.PORT || 5050);
await init();
});

How to deal with the different type of errors that returns from the cloud function?

I have written the cloud functions which sends the response either with the statuscode 200 or 400 but sometimes I am getting this error
Function execution took 219 ms, finished with status: 'connection error'
Error: function crashed out of request scope Function invocation was interrupted.
So the problem is I need to know send this error message with some statuscode as the response of the cloud function.
const functions = require('firebase-functions');
const dialogflow = require('dialogflow');
const admin = require('firebase-admin');
const Firestore = require('#google-cloud/firestore');
const firestore = new Firestore();
admin.initializeApp();
var db = admin.firestore();
const {WebhookClient} = require('dialogflow-fulfillment');
var UID = new Object();
exports.fulfillmenttext = functions.https.onRequest((req,res) =>{
const answer1 = req.body.Text;
const uid = answer1.substring(0,28);
const answer = answer1.substring(28);
const sessionId = uid;
var count,questvalue;
const promise = db.collection("***").doc('***').collection("**").doc("uid").get();
promise.then(doc => {
snapshot.forEach(function(doc) {
if (doc.exists) {
count = doc.data().count;
if(count == 1){
var updatequest = title[questvalue];
res.status(200).send({"question":updatequest,"question_number":questvalue});
return;
}
else{
runSample();
}
}
else {
console.log("No such document!");
}
});
}).catch(function(error) {
console.log("Error getting document:", error);
});
async function runSample() {
const languageCode = 'en-US';
const projectId = 'xxxxxxx';
const credentials = {
client_email: 'xxxxxxx',
private_key:
'xxxxxxx',
};
//Instantiate a DialogFlow client.
const dialogflow = require('dialogflow');
const sessionClient = new dialogflow.SessionsClient({
projectId,
credentials,
});
// Define session path
const sessionPath = sessionClient.sessionPath(projectId, sessionId);
// The text query request.
const request = {
//session: context1,
session: sessionPath,
queryInput: {
text: {
text: answer,
languageCode,
},
},
};
const responses = await sessionClient.detectIntent(request);
const result = responses[0].queryResult;
let action = result.action;
if (result.intent) {
const question = result.fulfillmentText;
console.log("question is",question);
const actionHandlers = {
'early': () => {
console.log('earlyaction1', action);
let name1 = JSON.stringify(result.parameters.fields.Name.stringValue);
name1 = name1.toString().replace(/"/g,"");
var data1 = {
Name: name1
};
var setDoc1 = admin.firestore().collection('**').doc('uid').collection("***").doc('uid').collection('**').doc('**').update(data1);
},
};
if (action === 'early') {
console.log('1');
actionHandlers[action]();
}
res.status(200).send({"question":result.fulfillmentText,"action":action,"question_number":title.indexOf(question)});
} else {
console.log(` No intent matched.`);
res.status(400).send({"action":"empty"});
}
}
});
That message is telling you that you have some async code that was still running after the function terminated normally by sending a response to the client. That bit of async code crashed. Since the function already terminated by sending a response, there's nothing you can do to send another response. There can only be one response per function invocation.
What you'll have to do is review your code and make sure you're 1) handling promises correctly and 2) not intentionally trying to leave any work going after sending the response, since Cloud Functions does not support that.

App refused to connect (NodeJs & Express)

I've created an app in the Partners panel, and I followed this documentation (using Nodejs and Express).
I can get the JSON format for the products' object without any problem. However, when I add to the scopes variable "read_price_rules" I get this error message: "express-example-app refused to connect."
Is this issue caused by the app's permissions?
My app can: Read products, variants, and collections.
Here is the index.js file:
const dotenv = require('dotenv').config();
const express = require('express');
const app = express();
const crypto = require('crypto');
const cookie = require('cookie');
const nonce = require('nonce')();
const querystring = require('querystring');
const request = require('request-promise');
const apiKey = process.env.SHOPIFY_API_KEY;
const apiSecret = process.env.SHOPIFY_API_SECRET;
const scopes = 'read_products,read_price_rules';
const forwardingAddress = "https://53b16008.ngrok.io";
app.listen(3000, () => {
console.log('Example app listening on port 3000!');
});
app.get('/shopify', (req, res) => {
const shop = req.query.shop;
if (shop) {
const state = nonce();
const redirectUri = forwardingAddress + '/shopify/callback';
const installUrl = 'https://' + shop + '/admin/oauth/authorize?client_id=' + apiKey + '&scope=' + scopes + '&state=' + state + '&redirect_uri=' + redirectUri;
res.cookie('state', state);
res.redirect(installUrl);
}
else { return res.status(400).send('Missing shop parameter. Please add ?shop=your-development-shop.myshopify.com to your request'); }
});
app.get('/shopify/callback', (req, res) => {
const { shop, hmac, code, state } = req.query;
const stateCookie = cookie.parse(req.headers.cookie).state;
if (state !== stateCookie) { return res.status(403).send('Request origin cannot be verified'); }
if (shop && hmac && code) {
// DONE: Validate request is from Shopify
const map = Object.assign({}, req.query);
delete map['signature'];
delete map['hmac'];
const message = querystring.stringify(map);
const providedHmac = Buffer.from(hmac, 'utf-8');
const generatedHash = Buffer.from(crypto.createHmac('sha256', apiSecret).update(message).digest('hex'), 'utf-8');
let hashEquals = false;
try { hashEquals = crypto.timingSafeEqual(generatedHash, providedHmac) }
catch (e) { hashEquals = false; };
if (!hashEquals) { return res.status(400).send('HMAC validation failed'); }
// DONE: Exchange temporary code for a permanent access token
const accessTokenRequestUrl = 'https://' + shop + '/admin/oauth/access_token';
const accessTokenPayload = {
client_id: apiKey,
client_secret: apiSecret,
code,
};
request.post(accessTokenRequestUrl, { json: accessTokenPayload })
.then((accessTokenResponse) => {
const accessToken = accessTokenResponse.access_token;
// DONE: Use access token to make API call to 'shop' endpoint
const shopRequestUrl = 'https://' + shop + '/admin/api/2019-04/discount_codes/lookup.json?code=20OFF';
const shopRequestHeaders = { 'X-Shopify-Access-Token': accessToken, };
request.get(shopRequestUrl, { headers: shopRequestHeaders })
.then((shopResponse) => {
res.status(200).end(shopResponse);
})
.catch((error) => {
res.status(error.statusCode).send(error.error.error_description);
});
})
.catch((error) => {
res.status(error.statusCode).send(error.error.error_description);
});
} else {
res.status(400).send('Required parameters missing');
}
});
I Just had to reinstall the app after adding an extra scope in the index.js file.

Resources