diff --git a/.gitignore b/.gitignore index 91e971a..4fc57d0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules lib dist Cache +a.js diff --git a/.npmignore b/.npmignore index b548c97..8928f78 100644 --- a/.npmignore +++ b/.npmignore @@ -17,4 +17,5 @@ CODE_OF_CONDUCT.md CONTRIBUTING.md LEARN.md SECURITY.md -.circleci \ No newline at end of file +.circleci +a.js \ No newline at end of file diff --git a/README.md b/README.md index d85a132..534fd21 100644 --- a/README.md +++ b/README.md @@ -455,9 +455,34 @@ app.use("/api", Middleware.JWTValidator("FieldName", Token), MainRouter); // use // You can pass as many as you want methods in the first parameter of the function +## Count the Number of Requests in NodeJS + +```javascript +const { Middleware } = require("outers"); // import the package + +app.use( + "/api", + Middleware.RequestCounter(true, true, true, true, true), + MainRouter, +); // count the number of requests in NodeJS with the Middleware function ``` +- Note : You can pass true/false in all parameters of the function, by default it is set to true, if you set it to true then it will count the number of requests in the console + +- Note : The First Parameter is SaveIP which is used to save the IP Address in the Request Object, by default it is set to true, if you set it to true then it will save the IP Address in the Request Object + +- Note : The Second Parameter is SaveUserAgent which is used to save the User Agent in the Request Object, by default it is set to true, if you set it to true then it will save the User Agent in the Request Object + +- Note : The Third Parameter is SaveRequestTime which is used to save the Request Time in the Request Object, by default it is set to true, if you set it to true then it will save the Request Time in the Request Object + +- Note : The Fourth Parameter is SaveContentType which is used to save the Content Type in the Request Object, by default it is set to true, if you set it to true then it will save the Content Type in the Request Object + +- Note : The Fifth Parameter is SaveMethod which is used to save the Method in the Request Object, by default it is set to true, if you set it to true then it will save the Method in the Request Object + ## License MIT + +``` + ``` diff --git a/package-lock.json b/package-lock.json index 9523ad6..d13869e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "outers", - "version": "8.2.15", + "version": "8.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "outers", - "version": "8.2.15", + "version": "8.3.0", "license": "MIT", "dependencies": { "crypto-js": "^4.2.0", diff --git a/package.json b/package.json index facc83a..06a99e0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "outers", - "version": "8.2.15", + "version": "8.3.0", "description": "outers - a all in one package for your day to day use", "main": "./lib/Config/outer.js", "types": "./lib/Config/outer.d.ts", diff --git a/source/Cluster/class/CreateClusterByClass.method.ts b/source/Cluster/class/CreateClusterByClass.method.ts index 65271fb..d259f9a 100644 --- a/source/Cluster/class/CreateClusterByClass.method.ts +++ b/source/Cluster/class/CreateClusterByClass.method.ts @@ -24,6 +24,7 @@ export default class CreateClusterByClass { #AfterListenFunctions: any[]; // Any Functions to run after listen #FunctionMiddlewares: any[]; // Any Middlewares to apply #GlobalResponseObject: ResponseObject; // Any ResponseObject + #EnableTrustProxy: boolean; // Enable Trust Proxy // Constructor /** @@ -60,6 +61,7 @@ export default class CreateClusterByClass { TotalAfterFunctions: this.#AfterListenFunctions.length, ActiveMiddlewares: this.#FunctionMiddlewares, }; + this.#EnableTrustProxy = true; // Enable Trust Proxy } // Start Server Method @@ -137,6 +139,13 @@ export default class CreateClusterByClass { yellow(`Worker ${worker.process.pid} is listening`); }); } else { + // Enable trust proxy for Express Server + this.#EnableTrustProxy === true + ? this.#ExpressServer.set("trust proxy", true) + : yellow( + "Trust Proxy is not enabled, if you are working behind a proxy, please enable it to get the real IP Address", + ); + // Apply Function Middlewares to Express Server Instance like CORS, Body Parser, etc. if ( this.#FunctionMiddlewares.length > 0 || @@ -279,4 +288,26 @@ export default class CreateClusterByClass { this.#FunctionMiddlewares.push(FunctionToRun); // Add Function to Function Middlewares } + + // Enable Trust Proxy Method + /** + * Controls the Trust Proxy setting. + * @param {boolean} Status - The value indicating whether to enable or disable Trust Proxy. + * @throws {Error} If Trust Proxy is already enabled. + * @throws {Error} If the provided value is not a boolean. + */ + public ControlTrustProxy(Status: boolean): void { + // Check if Trust Proxy is already enabled or not + if (this.#EnableTrustProxy === true) { + throw new Error("Trust Proxy is already enabled"); // Error Message for Server Start + } + + // Check inserted value is boolean or not + if (typeof Status !== "boolean") { + throw new Error("TPlease provide a boolean value to enable Trust Proxy"); // Error Message for Server Start + } + + // Enable Trust Proxy + this.#EnableTrustProxy = Status; // Enable Trust Proxy + } } diff --git a/source/Cluster/function/CreateClusterByFunction.method.ts b/source/Cluster/function/CreateClusterByFunction.method.ts index b6a9d6a..92c7e29 100644 --- a/source/Cluster/function/CreateClusterByFunction.method.ts +++ b/source/Cluster/function/CreateClusterByFunction.method.ts @@ -16,6 +16,7 @@ import { ResponseObject } from "../../Config/Interfaces/Cluster/CreateClusterByF * @param ExpressServer - The main Express server instance. * @param PORT - The port number to listen on. * @param NumberOfWorkers - The number of worker copies to create. + * @param EnableTrustProxy - Whether to enable trust proxy or not. * @param BeforeListenFunctions - Any functions to run before listening. * @param AfterListenFunctions - Any functions to run after listening. * @param FunctionMiddlewares - Any middlewares to apply to the Express server instance. @@ -26,6 +27,7 @@ export default async function Config( ExpressServer: Express = express(), // Main Express Server Instance PORT = 3000, // Port Number to Listen NumberOfWorkers: number = cpus().length, // Number of Copies of Workers + EnableTrustProxy: boolean = true, // Enable Trust Proxy BeforeListenFunctions: any[] = [], // Any Functions to run before listen AfterListenFunctions: any[] = [], // Any Functions to run after listen FunctionMiddlewares: any[] = [], // Any Middlewares to apply @@ -98,6 +100,13 @@ export default async function Config( yellow(`Worker ${worker.process.pid} is listening`); }); } else { + // Enable trust proxy for Express Server + EnableTrustProxy + ? ExpressServer.set("trust proxy", () => true) + : yellow( + "Trust Proxy is not enabled, if you are working behind a proxy, please enable it to get the real IP Address", + ); + // Apply Function Middlewares to Express Server Instance like CORS, Body Parser, etc. if (FunctionMiddlewares.length > 0 || FunctionMiddlewares !== undefined) { FunctionMiddlewares.forEach((FunctionMiddleware) => { diff --git a/source/Config/Constant/Middleware.Constant.ts b/source/Config/Constant/Middleware.Constant.ts index 219c5a1..65e9f05 100644 --- a/source/Config/Constant/Middleware.Constant.ts +++ b/source/Config/Constant/Middleware.Constant.ts @@ -126,3 +126,6 @@ export const IPAllowedMethods = ["PUT", "POST", "PATCH", "DELETE"]; // Allowed M // Constants for Allowed HTTP Methods in Request Controller Middleware export const AllowedMethods = [...IPAllowedMethods, "OPTIONS"]; // Allowed Methods + +// Constants for Request Counter Storage +export const TodayDate = new Date().toLocaleDateString(); // Get Today's Date diff --git a/source/Config/outer.ts b/source/Config/outer.ts index 314925d..6e80784 100644 --- a/source/Config/outer.ts +++ b/source/Config/outer.ts @@ -70,6 +70,7 @@ import IP_Controller from "../Middlewares/IP Controller/Base.middleware"; // Imp import UserAccessController from "../Middlewares/User Agent Controller/Base.middleware"; // Import User Access Controller Module import RequestController from "../Middlewares/Request Controller/Base.middleware"; // Import Request Controller Module import JWTValidator from "../Middlewares/JWT Validator/Base.middleware"; // Import JWT Validator Middleware +import RequestCounter from "../Middlewares/User Counter/Base.middleware"; // Import Request Counter Middleware // Import Functions Related Modules import IPChecker from "../Functions/IP Type Checker.function"; // Import IP Type Checker Module @@ -108,6 +109,7 @@ export const Middleware = Object.freeze({ User_AgentController: UserAccessController, // Export User Access Controller Module as Middleware MethodsController: RequestController, // Export Request Controller Module as Middleware JWTValidator, // Export JWT Validator Middleware + RequestCounter, // Export Request Counter Middleware }); // Export IP Injector Module as Middleware // Export All Class based with Freeze diff --git a/source/Middlewares/User Counter/Base.middleware.ts b/source/Middlewares/User Counter/Base.middleware.ts index e69de29..d4fc421 100644 --- a/source/Middlewares/User Counter/Base.middleware.ts +++ b/source/Middlewares/User Counter/Base.middleware.ts @@ -0,0 +1,89 @@ +import { Request, Response, NextFunction } from "express"; // Importing express types +import Storage from "../../Storage Management/ShortStorage.storage"; // Importing ShortStorage +import { TodayDate } from "../../Config/Constant/Middleware.Constant"; // Importing Today's Date +import { StatusCode } from "../../StatusCode/Code"; // Importing Status Code +import { Serve } from "../../Config/outer"; // Importing Serve + +// Create new ShortStorage instance +export const StorageInstance = new Storage( + "Request-Counter-details-for-nodejs", + 999999, // 999999 MB = 1TB + "Request-Counter-details-for-nodejs", +); + +// Main middleware function +export default function ( + SaveIP: boolean = true, + SaveUserAgent: boolean = true, + SaveRequestTime: boolean = true, + SaveContentType: boolean = true, + SaveMethod: boolean = true, +) { + return async (Request: Request, Response: Response, Next: NextFunction) => { + const GetPreviousData = await StorageInstance.Get(TodayDate); // Get previous data + + // Check if previous data is available or not + if (GetPreviousData.status === StatusCode.NOT_FOUND) { + const SaveStatus = await StorageInstance.Save(TodayDate, { + TotalRequest: 0, + TotalDetails: [ + { + RequestDate: TodayDate, + RequestTime: SaveRequestTime ? new Date().getTime() : undefined, + RequestIP: SaveIP ? Request.ip : undefined, + RequestUserAgent: SaveUserAgent + ? Request.headers["user-agent"] + : undefined, + RequestContentType: SaveContentType + ? Request.headers["content-type"] + : undefined, + RequestMethod: SaveMethod ? Request.method : undefined, + }, + ], + }); + + // Check if data is saved or not + SaveStatus.status === StatusCode.OK + ? Next() + : Serve.JSON({ + response: Response, + status: false, + message: "Unable to process your request, please try again later", + Title: "Error", + statusCode: StatusCode.INTERNAL_SERVER_ERROR, + data: undefined, + }); + } else { + const UpdateStatus = await StorageInstance.Update(TodayDate, { + TotalRequest: GetPreviousData.Data[0].Data.TotalRequest + 1, + TotalDetails: [ + ...GetPreviousData.Data[0].Data.TotalDetails, + { + RequestDate: TodayDate, + RequestTime: SaveRequestTime ? new Date().getTime() : undefined, + RequestIP: SaveIP ? Request.ip : undefined, + RequestUserAgent: SaveUserAgent + ? Request.headers["user-agent"] + : undefined, + RequestContentType: SaveContentType + ? Request.headers["content-type"] + : undefined, + RequestMethod: SaveMethod ? Request.method : undefined, + }, + ], + }); + + // Check if data is updated or not + UpdateStatus.status === StatusCode.OK + ? Next() + : Serve.JSON({ + response: Response, + status: false, + message: "Unable to process your request, please try again later", + Title: "Error", + statusCode: StatusCode.INTERNAL_SERVER_ERROR, + data: undefined, + }); + } + }; +}