@carlosbajo/roket-micro
Version:
framework para microservicios con google/pubsub
140 lines (129 loc) • 5.44 kB
JavaScript
const _ = require('lodash');
const fs = require('fs');
const fileKey = fs.readFileSync(process.env.GOOGLE_APPLICATION_CREDENTIALS); // eslint-disable-line
const { name } = require(`${process.cwd()}/package.json`); // eslint-disable-line
const pubsub = require('@google-cloud/pubsub');
const gLogger = require('./google-loggin');
const pubsubClient = pubsub();
const key = JSON.parse(fileKey);
const isLocal = key.client_email.includes('local');
const nameTopic = (topic) => {
let response;
if (isLocal) response = `local.${topic}`;
else response = topic;
return response;
};
module.exports = class Pubsub {
constructor(logger) {
if (logger) this.logger = logger;
}
static async createMessageStreamForTopic(topic) {
const googleTopic = pubsubClient.topic(topic);
const consumerClient = await googleTopic.subscribe(nameTopic(`${name}.${topic}`));
return consumerClient[0];
}
async loadSubscription(pubsub, topic) { // eslint-disable-line
const tmp = [];
const existingTopics = await pubsubClient.getTopics();
const topicNames = existingTopics[0].map(item => item.name);
for (const item of pubsub[topic].response) {
if (!topicNames.includes(`projects/${process.env.GCLOUD_PROJECT}/topics/${nameTopic(item)}`)) {
tmp.push(pubsubClient.createTopic(nameTopic(item)));
}
}
await Promise.all(tmp);
if (!topicNames.includes(`projects/${process.env.GCLOUD_PROJECT}/topics/${nameTopic(topic)}`)) await pubsubClient.createTopic(nameTopic(topic));
const googleTopic = pubsubClient.topic(nameTopic(topic));
const consumerClient = await googleTopic.subscribe(nameTopic(`${name}.${topic}`));
return { topic: googleTopic, consumerClient: consumerClient[0] };
}
static createMessageResponseObject(body, request) {
const messageResponseObject = {
errors: [],
body
};
if (!request.correlation_id) {
messageResponseObject.errors.push(`Invalid Request: Request is missing correlation_id. Request is ${request}`);
} else {
messageResponseObject.correlation_id = request.correlation_id;
}
if (!request.request_id) {
messageResponseObject.errors.push(`Invalid Request: Request is missing request_id. Request is ${request}`);
} else {
messageResponseObject.request_id = request.request_id;
}
if (messageResponseObject.errors.length === 0) {
delete messageResponseObject.errors;
}
return messageResponseObject;
}
writeResponseForRequest(response, request) {
let tmp;
if (!request.response_topic) {
tmp = Promise.reject('Request is missing a response_topic. Request: %j');
} else {
const messageObject = pubsub.createMessageResponseObject(response, request);
tmp = this.writeMessageToTopic(JSON.stringify(messageObject), request.response_topic);
}
return tmp;
}
async writeMessageToTopic(messageString, topic, req) {
const log = gLogger(this.logger);
let isBoom;
const message = JSON.parse(messageString);
if (!isBoom) log(topic, _.get(req, 'usr.id', 'undefined'), message);
return message;
// topic = nameTopic(`${method || 'res'}.${name}.${topic}`);
// const googleTopic = pubsubClient.topic(topic);
// return new Promise((resolve, reject) => {
// if (this.logger) this.logger.info(`Topic: ${topic}, payload: ${messageString}`);
// if (_.isObject(messageString)) {
// isBoom = messageString.isBoom;
// messageString = JSON.stringify(messageString);
// } else {
// message = JSON.parse(messageString);
// isBoom = message.isBoom;
// }
// googleTopic.publish(messageString).then(res => {
// if (!isBoom) log(topic, _.get(req, 'usr.id', 'undefined'), message);
// resolve(res[0]);
// }).catch(err => reject(err));
// });
}
resolve(request, response) {
const opt = { autoAck: true }; // es en milisegundos
const requestTopic = pubsubClient.topic(nameTopic(request));
const responseTopic = pubsubClient.topic(nameTopic(response));
this.logger.info('subscribe to', nameTopic(`${name}.${response}`));
const consumerResponse = responseTopic.subscribe(nameTopic(`${name}.${response}`), opt);
return async (parent, args, ctx) => {
if (ctx.jwt.error) return Promise.reject(ctx.jwt.error.output.payload.message);
const data = {
object: parent,
args: args || {},
jwt: ctx.jwt.usrJwt,
};
requestTopic.publish(JSON.stringify(data))
.catch((error) => this.logger.error(error))
.then((res) => {
this.logger.info(`message sent to ${nameTopic(request)}`, JSON.stringify(args));
this.logger.info(res);
});
let consumer = await consumerResponse;
consumer = consumer[0];
return new Promise((resolve, reject) => {
consumer.on('message', message => {
let val = message.data;
val = (_.isEmpty(val) ? {} : JSON.parse(val));
if (val.isBoom) {
const format = `Request Topic: ${nameTopic(request)}, Response Topic: ${nameTopic(response)}, statusCode: ${val.output.statusCode}, message: ${val.output.payload.message}, Error: ${val.output.payload.error}`;
reject(format);
} else {
resolve(val.payload || val);
}
});
consumer.on('error', error => reject(error));
});
};
}
};