Google Cloud Tasks - Network Error on create multiples tasks - node.js

In this code below I have a client which creates multiples tasks inside a map loop. However, this process doesn't complete and returns the follow network error:
Error: request to https://cloudtasks.googleapis.com/$rpc/google.cloud.tasks.v2.CloudTasks/CreateTask failed, reason: Client network socket disconnected before secure TLS connection was established
How can I fix this?
const { CloudTasksClient } = require('#google-cloud/tasks');
exports.sendTask = (req, res) => {
const data = req.body.data;
const client = new CloudTasksClient({ fallback: true });
const parent = client.queuePath(process.env.PROJECT, process.env.LOCATION, process.env.QUEUE);
const url = process.env.URL;
let counter = 0;
data.map(payload => {
counter += 1;
console.log('preparando task ', counter);
const task = {
httpRequest: {
httpMethod: 'POST',
url,
oidcToken: {
serviceAccountEmail: process.env.SERVICE_ACCOUNT,
},
headers: {
'Content-Type': 'application/json',
},
body: Buffer.from(payload).toString('base64')
}
};
client.createTask({parent, task});
console.log('Task gerada.');
});
res.status(200).send();
}
Exception from task creation

According to documentation - client.createTask is async function, means, your code should wait for it's result somehow. Having a loop here, I guess, you want call all of them asynchronously, not one by one, and wait for result of all of them. I suggest you to use Promise.all
const { CloudTasksClient } = require('#google-cloud/tasks');
exports.sendTask = async (req, res) => {
const data = req.body.data;
const client = new CloudTasksClient({ fallback: true });
const parent = client.queuePath(process.env.PROJECT, process.env.LOCATION, process.env.QUEUE);
const url = process.env.URL;
let counter = 0;
await Promise.all(data.map(payload => {
counter += 1;
console.log('preparando task ', counter);
const task = {
httpRequest: {
httpMethod: 'POST',
url,
oidcToken: {
serviceAccountEmail: process.env.SERVICE_ACCOUNT,
},
headers: {
'Content-Type': 'application/json',
},
body: Buffer.from(payload).toString('base64')
}
};
console.log('Task gerada.');
return client.createTask({parent, task});
}));
console.log('All task were generated.');
res.status(200).send();
}

Related

Paytm Payment Gateway - Returning Invalid payment mode for UPI

I'm trying to integrate Paytm's Payment gateway [Custom Checkout]. However, while UPI Integration, after sending the request i'm getting Invalid payment mode response code on the callback url.
As suggested in documentation,
First i'm calling the Initiate Transaction API for token.
initialise(order, res, next) {
const paytmParams = {};
paytmParams.body = {
requestType: 'Payment',
mid: paytm.mid,
websiteName: paytm.website,
orderId: order.orderId,
callbackUrl: paytm.callbackUrl,
txnAmount: {
value: order.amount,
currency: 'INR',
},
userInfo: {
custId: order.custId,
},
};
const paytmChecksum = PaytmChecksum.generateSignature(paytmParams.body, paytm.merchantKey);
paytmChecksum.then(function (checksum) {
paytmParams.head = {
signature: checksum,
};
const post_data = JSON.stringify(paytmParams);
const options = {
hostname: paytm.host,
port: 443,
path: `/theia/api/v1/initiateTransaction?mid=${paytm.mid}&orderId=${order.orderId}`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': post_data.length,
},
};
let response = '';
const post_req = https.request(options, function (post_res) {
post_res.on('data', function (chunk) {
response += chunk;
});
post_res.on('end', function () {
const result = JSON.parse(response);
if (result.body.resultInfo.resultStatus === 'S') {
res.status(200).json({ token: result.body.txnToken, orderId: order.orderId });
} else {
next(new ApiError(httpStatus.EXPECTATION_FAILED, result.body.resultInfo.resultMsg));
}
});
});
post_req.write(post_data);
post_req.end();
});
}
After this i'm taking the user's vpa and validating that via Validate VPA API.
validateUpi(data, res, next) {
const paytmParams = {};
paytmParams.body = {
vpa: data.upiId,
};
paytmParams.head = {
tokenType: 'TXN_TOKEN',
token: data.token,
};
const post_data = JSON.stringify(paytmParams);
const options = {
hostname: paytm.host,
port: 443,
path: `/theia/api/v1/vpa/validate?mid=${paytm.mid}&orderId=${data.orderId}`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': post_data.length,
},
};
let response = '';
const post_req = https.request(options, function (post_res) {
post_res.on('data', function (chunk) {
response += chunk;
});
post_res.on('end', function () {
const result = JSON.parse(response);
if (result.body.resultInfo.resultStatus === 'S') {
res.status(200).json({
action: `https://${paytm.host}/theia/api/v1/processTransaction?mid=${paytm.mid}&orderId=${data.orderId}`,
params: {
mid: paytm.mid,
orderId: data.orderId,
txnToken: data.token,
paymentMode: 'UPI',
payerAccount: data.upiId,
},
});
} else {
next(new ApiError(httpStatus.EXPECTATION_FAILED, result.body.resultInfo.resultMsg));
}
});
});
post_req.write(post_data);
post_req.end();
}
After the successfull response, i'm returning the action URL and the params to the front end to create the form and post it in front end.
const res = await paymentAPI.validateUpiId(body);
paymentHelpers.createFormAndSubmit(res.action, res.params, 'redirect');
export const createFormAndSubmit = (url: string, data: any, type = "") => {
const form = document.createElement("form");
form.method = "POST";
form.action = url;
form.type = type;
Object.keys(data).forEach((key) => {
const input = document.createElement("input");
input.type = "text";
input.name = key;
input.value = data[key];
form.appendChild(input);
});
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
};
But after this form is being submitted, i'm getting redirected to callbackUrl with error message
http://localhost:3000/callback/paytm?retryAllowed=false&errorMessage=Invalid%20payment%20mode&errorCode=317

Axios accepts only static url

I'm writing a NodeJS Backend with express and axios where I fetch data from Strapi CMS and send a server-side-rendered HTML-document to the client.
There I encountered the strange behaviour that the first piece of code gets a response from strapi with data.data.length = 0, which isn't expected. The second piece of code returns data.data.length = 1, which is the same as I retrieve with Postman. I can't find the difference since both url's compile to the same string. My expectation is that both requests should be returning the same response.
app.get(`/blog/:URL_Identifier`, async (req, res) => {
let data;
let params = req.params;
console.log(params.URL_Identifier);
let string = hostname + ":" + strapiport + `/api/blogposts?filters[URL_Identifier][$in][0]=${params.URL_Identifier}&populate=*`;
//string prints to https://127.0.0.1:1337/api/blogposts?filters[URL_Identifier][$in][0]=Blogpost1&populate=*
data = await axios.get(string, {
headers: {
'Authorization': 'Bearer ' + token
}
});
//data = JSON.parse(data.data);
console.log(data);
res.render('pages/post', {
data: data
})
})
Whereas the following code returns a data.data.length = 1 with the expected data inside.
data = await axios.get("https://127.0.0.1:1337/api/blogposts?filters[URL_Identifier][$in][0]=Blogpost1&populate=*", {
headers: {
'Authorization': 'Bearer ' + token
}
});
Is this a bug in Axios? I can't see the difference...
EDIT:
I tried the same with the http module from node and found out, thatthe request object from express might be the issue.
app.get(`/blog/:URL_Identifier`, async (req, res) => {
let data;
let doesWork = "http://127.0.0.1:1337/api/blogposts?filters[URL_Identifier][$in][0]=Blogpost1&populate=*";
let doesNotWork = `http://127.0.0.1:1337/api/blogposts?filters[URL_Identifier][$in][0]=${req.params}&populate=*`;
var options = {
headers: {
'Authorization': 'Bearer ' + token
}
};
callback = function(response) {
var str = ''
response.on('data', function (chunk) {
str += chunk;
});
response.on('end', function () {
console.log(str);
data = JSON.parse(str);
console.log(data);
});
}
var req1 = await http.request(doesNotWork, options, callback);
req1.end();
This still gets me this as response
{
data: [],
meta: { pagination: { page: 1, pageSize: 25, pageCount: 0, total: 0 } }
}
Whereas var req1 = await http.request(doesWork, options, callback);
gets me
{
data: [ { id: 1, attributes: [Object] } ],
meta: { pagination: { page: 1, pageSize: 25, pageCount: 1, total: 1 } }
}

Keep getting pending request when trying to call endpoint, what's wrong?

I have made an endpoint to get token for paytm payment integration. In backend when i'm calling api i'm getting reqdata json but in frontend when i'm logging await transactionAPI, i'm getting only pending promise. i've tried using then in backend in PaytmChecksum.generateSignature method & in frontend in fetch but nothing is working. Keep getting the same result. Pls help.
Frontend code:
const makePayment = async () => {
const data = {
oid: String(new Date().valueOf()),
amount: '1.00',
email: 'abc#gmail.com',
};
let transactionAPI = fetch('http://localhost:3000/api/pretransact', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
console.log(await transactionAPI);
}
Backend code:
const https = require('https');
const PaytmChecksum = require('./PaytmChecksum');
export default async function handler(req, res) {
if (req.method == 'POST') {
const { oid, amount, email } = req.body;
let mid = process.env.PAYTM_MID;
let paytmParams = {};
paytmParams.body = {
requestType: 'Payment',
mid,
websiteName: process.env.WEBSITE,
orderId: oid,
callbackUrl: 'http://localhost:3000/api/callback',
txnAmount: {
value: amount,
currency: 'INR',
},
userInfo: {
custId: email,
},
};
const checksum = await PaytmChecksum.generateSignature(
JSON.stringify(paytmParams.body),
process.env.MERCHANT_KEY
);
paytmParams.head = {
signature: checksum,
};
var post_data = JSON.stringify(paytmParams);
const requestAsync = () => {
return new Promise((resolve, reject) => {
var options = {
hostname: 'securegw-stage.paytm.in',
// hostname: 'securegw.paytm.in',
port: 443,
path: `/theia/api/v1/initiateTransaction?mid=${mid}&orderId=${oid}`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': post_data.length,
},
};
var response = '';
var post_req = https.request(options, function (post_res) {
post_res.on('data', function (chunk) {
response += chunk;
});
post_res.on('end', function () {
resolve(response);
});
});
post_req.write(post_data);
post_req.end();
});
};
const reqdata = await requestAsync();
res.send(200).json(reqdata);
}
}

Node.JS multiple new Class only last executed (http & socket.io-client)

First sorry for my bad english.
I tried connect to server using http token authentication with socket.io as exchange data. When socket.io got an error then request token by http and try to connect again.
I put the connection function in the class then call it from main program. My problem is when I create multiple client why only last work, here my code
call the class
const SocketHttpClient = require('./class/socket-http-client')
let ioClient_1 = new SocketHttpClient('localhost', 3001, 'admin', 'admin', '/login')
let ioClient_2 = new SocketHttpClient('localhost', 3002, 'admin', 'admin', '/login')
let ioClient_3 = new SocketHttpClient('localhost', 3003, 'admin', 'admin', '/login')
connection class
// =================================================================================================
// INCLUDE LIBRARY
// =================================================================================================
const ioClient = require('socket.io-client')
const http = require('http')
const cookie = require('cookie')
const log = require('./log-custom')
// =================================================================================================
// VARIABLE
// =================================================================================================
let data
let httpOption
ioOption = {
transportOptions: {
polling: {
extraHeaders: {
Cookie: 'hello=world'
}
}
}
}
module.exports = class Socket {
constructor(ioHostname, ioPort, httpUsername, httpPassword, loginPath) {
data = {
username: httpUsername,
password: httpPassword
}
data = JSON.stringify(data)
httpOption = {
hostname: ioHostname,
port: ioPort,
path: loginPath,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
}
log(`Connecting to "${httpOption.hostname}:${httpOption.port}"`)
this.io = ioClient(`http://${httpOption.hostname}:${httpOption.port}`, ioOption)
this.io.on('connect', () => {
log(`Connected to socket "${httpOption.hostname}:${httpOption.port}"`)
})
this.io.on('disconnect', () => {
log(`Disconnected to socket "${httpOption.hostname}:${httpOption.port}"`)
log('Reconnecting...')
})
this.io.on('error', () => {
console.log(`error: ${httpOption.hostname}:${httpOption.port}`)
// When error then try to reconnect...
setTimeout(() => {
this.io.disconnect()
this.io.close()
this.req = http.request(httpOption, res => {
this.c = cookie.parse(res.headers['set-cookie'][0])
ioOption.transportOptions.polling.extraHeaders.Cookie = `sid=${this.c.sid}`
this.io.io.opts.query = ioOption
})
this.req.write(data)
this.req.end()
this.req.on('error', err => {
})
// delay to reconnect
setTimeout(() => {
this.io.connect()
}, 1000)
}, 1000)
})
}
}
the result:
ioClient_1 => not working
ioClient_2 => not working
ioClient_3 => working fine as expected
Where I doing wrong here? Need advice from you guys. Thank you in advanced.

aws elastic search http request , error 'The bulk request must be terminated by a newline'

I have used this link to create a bulk http request using a JSON.stringified(body) like this:
const body = [ { index: { _index: 'image_2', _type: '_doc', _id: 0 } },
{ imageKey: 'test' },
{ index: { _index: 'image_2', _type: '_doc', _id: 1 } },
{ imageKey: 'test2' } ]
but I keep getting the error
{ statusCode: 400,
body: '{"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"The bulk request must be terminated by a newline [\\\\n]"}],"type":"illegal_argument_exception","reason":"The bulk request must be terminated by a newline [\\\\n]"},"status":400}' }
I already tried this below and it is not working either:
const body = `${JSON.stringified(body)\n}`;
any ideas are appreciated :)
here is my aws elastic search function:
function elasticsearchFetch(elasticsearchDomain, endpointPath, options = {}, region = process.env.AWS_REGION) {
return new Promise((resolve, reject) => {
const { body, method = 'GET' } = options;
const endpoint = new AWS.Endpoint(elasticsearchDomain);
const request = new AWS.HttpRequest(endpoint, region);
request.method = method;
request.path += endpointPath;
request.headers.host = elasticsearchDomain;
if (body) {
request.body = body;
request.headers['Content-Type'] = 'application/json';
request.headers['Content-Length'] = request.body.length;
}
const credentials = new AWS.EnvironmentCredentials('AWS');
const signer = new AWS.Signers.V4(request, 'es');
signer.addAuthorization(credentials, new Date());
const client = new AWS.HttpClient();
client.handleRequest(request, null, (res) => {
res.on('data', (chunk) => {
chunks += chunk;
});
res.on('end', () => resolve({ statusCode: res.statusCode, body: chunks }));
}, error => reject(error));
});
}
and here is the code for my lambda function using the above request signer:
const elasticsearchFetch = require('rms-library/fetch');
exports.handler = async ({ imageID, bulk, products }) => {
if (!Array.isArray(products) || !imageID) {
throw new Error('error in bulk operation');
}
const bulkList = [];
products.forEach((product, i) => {
bulkList.push({ index: { _index: imageID, _type: '_doc', _id: i } });
bulkList.push(product);
});
bulkList.push('');
console.log('bulkList', bulkList);
const result = await elasticsearchFetch.elasticsearch(
process.env.ELASTIC_SEARCH_DOMAIN,
'_bulk',
{ method: 'PUT', body: JSON.stringify(bulkList) },
);
console.log(result);
};
Ok, first of all you need to use POST instead of PUT with the _bulk endpoint and the body cannot be a stringified JSON array.
Try like this instead:
const result = await elasticsearchFetch.elasticsearch(
process.env.ELASTIC_SEARCH_DOMAIN,
'_bulk',
{ method: 'POST', body: bulkList.map(json => {return JSON.stringify(json);}).join('\n') + '\n' },
);

Resources