pink-bears
Version:
Intelligent rate limiting middleware with MongoDB integration and caching for Node.js applications
249 lines • 9.27 kB
JavaScript
const {
Storage,
Fetch,
File,
Next,
Batch,
Status,
Email,
Schedule,
Iparams,
Webhook,
Redis
} = require("../sparrowapps-message-dispatcher/index.js");
const $Status = new Status();
const axios = require('axios');
const {
setContext
} = require('../sparrowapps-message-dispatcher/context.js');
class App {
constructor(sparrowAppsDomain, authToken, iframeUrl, productId, traceId, appVersion, userInstalledId, accountId, userId, appId) {
this.sparrowAppsDomain = sparrowAppsDomain;
this.authToken = authToken;
this.iframeUrl = iframeUrl;
this.productId = productId;
this.traceId = traceId;
this.appVersion = appVersion;
this.appId = appId;
this.userInstalledId = userInstalledId;
this.accountId = accountId;
this.userId = userId;
}
initiateInstanceObject(InstanceClass, constructorKeys) {
const client = {};
const instanceObject = new InstanceClass();
Object.getOwnPropertyNames(instanceObject).forEach(key => {
if (typeof instanceObject[key] === "function" && key !== "constructor") {
client[key] = (...args) => {
const constructorArgs = constructorKeys.map(cKey => this[cKey] || cKey);
return new InstanceClass(...constructorArgs)[key](...args);
};
}
});
Object.getOwnPropertyNames(InstanceClass.prototype).forEach(key => {
if (typeof InstanceClass.prototype[key] === "function" && key !== "constructor") {
client[key] = (...args) => {
const constructorArgs = constructorKeys.map(cKey => this[cKey] || cKey);
return new InstanceClass(...constructorArgs)[key](...args);
};
}
});
return client;
}
getFetch() {
return this.initiateInstanceObject(Fetch, ["sparrowAppsDomain", "authToken", "iframeUrl", "productId", "userId"]);
}
getFile() {
return this.initiateInstanceObject(File, [process.env.bucketName]);
}
getEmail() {
return this.initiateInstanceObject(Email, ["sparrowAppsDomain", "authToken", "userId"]);
}
getSchedule() {
return this.initiateInstanceObject(Schedule, ["sparrowAppsDomain", "authToken", "iframeUrl", "productId", "traceId", "appVersion", "userInstalledId", "accountId", "userId"]);
}
getNext() {
return this.initiateInstanceObject(Next, [process.env.rabbitMQurl]);
}
getStorage() {
return this.initiateInstanceObject(Storage, ["accountId", "productId", "appId", "sparrowAppsDomain", "userId"]);
}
getIparams() {
return this.initiateInstanceObject(Iparams, ["accountId", "productId", "appId", "sparrowAppsDomain", "userId"]);
}
getWebhook() {
return this.initiateInstanceObject(Webhook, ["sparrowAppsDomain", "authToken", "productId", "traceId", "userInstalledId", "accountId", "userId"]);
}
getRedis() {
console.log(`Inside getRedis() index`);
return this.initiateInstanceObject(Redis, ["accountId", "productId", "appId", "sparrowAppsDomain", "traceId", "userInstalledId", "authToken", "userId"]);
}
getBatch() {
return new Batch();
}
}
const app = new App();
exports.initHandlers = () => {
return {
$Fetch: app.getFetch(),
$File: app.getFile(),
$Email: app.getEmail(),
$Schedule: app.getSchedule(),
$Next: app.getNext(),
$Storage: app.getStorage(),
$Batch: app.getBatch(),
$Iparams: app.getIparams(),
$Status,
$Webhook: app.getWebhook(),
$Redis: app.getRedis()
};
};
const decodeJwt = token => {
try {
const [header, payload, signature] = token.split('.');
const decodedHeader = Buffer.from(header, 'base64').toString('utf-8');
const decodedPayload = Buffer.from(payload, 'base64').toString('utf-8');
return {
header: JSON.parse(decodedHeader),
payload: JSON.parse(decodedPayload),
signature
};
} catch (error) {
console.error('Error decoding the JWT:', error.message);
return null;
}
};
const isTokenExpired = decodedToken => {
if (!decodedToken || !decodedToken.payload || !decodedToken.payload.exp) {
return false; // Token is considered not expired if there's no expiration claim
}
const expirationTime = decodedToken.payload.exp * 1000; // Convert seconds to milliseconds
return expirationTime < Date.now();
};
exports.handler = async (event, context) => {
setContext(context);
if (event?.path?.split("/")?.[event?.path.split("/").length - 1] === "testing") {
return {
statusCode: 200,
body: JSON.stringify({
message: "success"
})
};
}
let parentLayer;
if (!event.body) {
parentLayer = event;
} else {
parentLayer = event.body && JSON.parse(event.body);
}
try {
if (event) {
const eventPayloadConfig = parentLayer?.appConfig?.extraPayload?.parentLayerConfigObject;
const {
appId,
userInstalledId
} = eventPayloadConfig;
const consoleMethods = ["log", "info", "error", "warn"];
consoleMethods.forEach(method => {
if (!console[`old${method}`]) {
console[`old${method}`] = console[method];
}
console[method] = function (...args) {
const forbiddenWords = args.filter(str => {
if (typeof str == "string") {
return str.includes(process.env.rabbitMQurl);
}
return;
});
let message = "SparrowApps---AppId---" + appId + "---UserInstalledId---" + userInstalledId + "---TraceId---" + parentLayer.traceId + " ";
if (forbiddenWords.length) {
message += `print statement forbidden`;
} else {
message += `${args.join(" ")}`;
}
console[`old${method}`](message);
};
});
app.accountId = eventPayloadConfig.accountId;
app.appVersion = eventPayloadConfig.appVersion;
app.authToken = eventPayloadConfig.authToken;
app.iframeUrl = eventPayloadConfig.iframeUrl;
app.productId = eventPayloadConfig.productId;
app.sparrowAppsDomain = eventPayloadConfig.sparrowAppsDomain;
app.traceId = parentLayer.traceId;
app.userInstalledId = eventPayloadConfig.userInstalledId;
app.userId = eventPayloadConfig.userId;
app.appId = eventPayloadConfig.appId;
const expired = isTokenExpired(decodeJwt(eventPayloadConfig.authToken));
if (expired) {
try {
const response = await axios.post(`${eventPayloadConfig.sparrowAppsDomain}/api/authenticate`, {
productKey: eventPayloadConfig.userId,
productId: eventPayloadConfig.productId
}, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.productToken}`
}
});
app.authToken = response.data.Access_Token;
} catch (error) {
console.error('Error:', error.message);
throw error;
}
}
const appName = eventPayloadConfig.appName?.toLowerCase();
const fileName = `./${appName}/server.js`;
const appServer = require(fileName);
let eventPayload;
const isBackendEvent = ["onSubmissionComplete", "onContactCreate", "onContactUpdate", "onContactDelete", "onTicketCommentCreate", "onTicketCreate", "onTicketUpdate", "onTicketDelete", "onWidgetCreate", "onWidgetUpdate", "onWidgetDelete", "onDashboardCreate", "onDashboardUpdate", "onDashboardDelete", "onReputationReviewCreate", "onReputationAppPlatformCreate", "onEmployeeCreate", "onContactListCreate", "onContactListDelete", "onContactListUpdate", "onQuestionCreate", "onQuestionUpdate", "onQuestionDelete", "onQuestionTypeChanged", "onSectionCreate", "onSectionUpdate", "onSectionDelete", "onChannelCreate", "onChannelUpdate", "onChannelDelete", "onCXChannelCreate", "onCXChannelUpdate", "onCXChannelDelete", "onSurveyCreate", "onSurveyEdit", "onSurveyDelete", "onSurveyMove", "onSurveyClose", "onSurveyRestore", "onSurveyDuplicate", "onSubmissionCreate", "onSubmissionUpdate", "onSubmissionDelete", "onAppInstall", "onAppUninstall", "onExternalEvent", "onIndividualExternalEvent"].includes(eventPayloadConfig.event);
if (isBackendEvent) {
eventPayload = parentLayer.payload;
} else {
eventPayload = {
data: parentLayer.payload,
iparams: eventPayloadConfig.iparams
};
}
const message = {
200: "Success",
401: "UnAuthorized",
500: "Something went wrong"
};
const data1 = await appServer[eventPayloadConfig.event](eventPayload, parentLayer);
if (isBackendEvent) {
return {
statusCode: 200,
body: JSON.stringify({
data: data1 || {}
})
};
}
const data = {
statusCode: data1?.status || 200,
body: JSON.stringify({
data: data1?.data,
message: data1?.status ? message[data1.status] : ""
})
};
return data;
}
return {
statusCode: 500,
body: JSON.stringify({
data: {
message: "something went wrong"
}
})
};
} catch (error) {
const data = {
statusCode: 500,
body: JSON.stringify({
error
})
};
await $Status.changeStatus(JSON.stringify(error), parentLayer.traceId);
return data;
}
};