feat(server service): added in start stop and restart from vms036
This commit is contained in:
77
server/globalUtils/rateLimiter.ts
Normal file
77
server/globalUtils/rateLimiter.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Hono } from "hono";
|
||||
import { type Context, type Next } from "hono";
|
||||
|
||||
const app = new Hono();
|
||||
|
||||
// --- In-Memory Store for Rate Limits ---
|
||||
// This Map will store when each user/key last accessed a rate-limited endpoint.
|
||||
// Key: string (e.g., 'ip_address' or 'user_id_endpoint')
|
||||
// Value: number (timestamp of last access in milliseconds)
|
||||
const rateLimitStore = new Map<string, number>();
|
||||
|
||||
// --- Configuration ---
|
||||
const FIFTEEN_MINUTES_MS = 5 * 60 * 1000; // 15 minutes in milliseconds
|
||||
|
||||
// --- Rate Limiting Middleware ---
|
||||
export const simpleRateLimit = async (c: Context, next: Next) => {
|
||||
// 1. Define a unique key for the rate limit
|
||||
// For simplicity, we'll use a placeholder for user identification.
|
||||
// In a real app:
|
||||
// - If unauthenticated: Use c.req.header('x-forwarded-for') or c.req.ip (if configured/available)
|
||||
// - If authenticated: Get user ID from c.req.user or similar after authentication middleware
|
||||
const userIdentifier = c.req.header("x-forwarded-for") || "anonymous_user"; // Basic IP-like identifier
|
||||
|
||||
// You can also make the key specific to the route to have different limits per route
|
||||
const routeKey = `${userIdentifier}:${c.req.path}`;
|
||||
|
||||
const now = Date.now();
|
||||
const lastAccessTime = rateLimitStore.get(routeKey);
|
||||
|
||||
if (lastAccessTime) {
|
||||
const timeElapsed = now - lastAccessTime;
|
||||
|
||||
if (timeElapsed < FIFTEEN_MINUTES_MS) {
|
||||
// Limit exceeded
|
||||
const timeRemainingMs = FIFTEEN_MINUTES_MS - timeElapsed;
|
||||
const timeRemainingSeconds = Math.ceil(timeRemainingMs / 1000);
|
||||
|
||||
c.status(429); // HTTP 429: Too Many Requests
|
||||
return c.json({
|
||||
error: "Too Many Requests",
|
||||
message: `Please wait ${timeRemainingSeconds} seconds before trying again.`,
|
||||
retryAfter: timeRemainingSeconds, // Standard header for rate limiting clients
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// If no previous access, or the 15 minutes have passed, allow the request
|
||||
// and update the last access time.
|
||||
rateLimitStore.set(routeKey, now);
|
||||
|
||||
// Continue to the next middleware or route handler
|
||||
await next();
|
||||
};
|
||||
|
||||
// --- Apply the Middleware to Specific Routes ---
|
||||
|
||||
app.get("/", (c) => {
|
||||
return c.text("Welcome! This is a public endpoint.");
|
||||
});
|
||||
|
||||
// This endpoint will be rate-limited
|
||||
app.get("/privileged", simpleRateLimit, (c) => {
|
||||
return c.text("You successfully accessed the privileged endpoint!");
|
||||
});
|
||||
|
||||
// Another rate-limited endpoint
|
||||
app.post("/submit-data", simpleRateLimit, async (c) => {
|
||||
// In a real app, you'd process form data or JSON here
|
||||
return c.text("Data submitted successfully (rate-limited).");
|
||||
});
|
||||
|
||||
// Example of an endpoint that is NOT rate-limited
|
||||
app.get("/health", (c) => {
|
||||
return c.text("Server is healthy!");
|
||||
});
|
||||
|
||||
export default app;
|
||||
Reference in New Issue
Block a user