added arkjet :D
This commit is contained in:
16
env.example
Normal file
16
env.example
Normal file
@@ -0,0 +1,16 @@
|
||||
PORT=8082
|
||||
HOST=0.0.0.0
|
||||
DATABASE_URL="postgresql://adm_cowch:Bluish-Tycoon4-Cuddly@localhost:5432/websocketTutorial?sslmode=require&channel_binding=require"
|
||||
|
||||
DATABASE_HOST=localhost
|
||||
DATABASE_PORT=5432
|
||||
DATABASE_USER=adm_cowch
|
||||
DATABASE_PASSWORD=Bluish-Tycoon4-Cuddly
|
||||
DATABASE_DB=websocketTutorial
|
||||
|
||||
# Run Arcjet in development <https://docs.arcjet.com/environment#arcjet-env>.
|
||||
ARCJET_ENV=development
|
||||
# Arcjet key for your site (from <https://app.arcjet.com>).
|
||||
# More info: <https://docs.arcjet.com/environment#arcjet-key>.
|
||||
ARCJET_KEY="ajkey_01kgraw410ey49fv7r7jzxbzcc"
|
||||
ARCJET_MODE=""
|
||||
256
package-lock.json
generated
256
package-lock.json
generated
@@ -9,6 +9,8 @@
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@arcjet/inspect": "^1.1.0",
|
||||
"@arcjet/node": "^1.1.0",
|
||||
"@dotenvx/dotenvx": "^1.52.0",
|
||||
"drizzle-orm": "^0.45.1",
|
||||
"express": "^5.2.1",
|
||||
@@ -28,6 +30,182 @@
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/analyze": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/analyze/-/analyze-1.1.0.tgz",
|
||||
"integrity": "sha512-rbgjTjk4PvoRh8wweerD5Qr0G/xar0XWNiRTvzcmrnJofuhESLjWD87p3Y3Od307gzex8Whtu+jA0LvII1H4DA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@arcjet/analyze-wasm": "1.1.0",
|
||||
"@arcjet/protocol": "1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/analyze-wasm": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/analyze-wasm/-/analyze-wasm-1.1.0.tgz",
|
||||
"integrity": "sha512-CrzSBa9rQFQRfIUofm2FuwVjlnCdWK8hQz3uxbMqYFFLeGPAQftM2noHM7P2p+2Rq6j1p6u462RIpjg2Y2rhXQ==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/body": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/body/-/body-1.1.0.tgz",
|
||||
"integrity": "sha512-ijMcy71ezPtu9aj29Cde6McBd634ugtqD26ufF8r/fb7YH/eYsWJQS4LZBnkEdgangAfb2VO1VEUpKwGSyZmqA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/cache": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/cache/-/cache-1.1.0.tgz",
|
||||
"integrity": "sha512-TFt5PdlQVOngGTL+Q02NLGtv6Ks15m68a5Jksk9rEDM8vVzwoFE6KXawPNPm0pcwow4a/C+GcYwYprDm7MpXlw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/duration": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/duration/-/duration-1.1.0.tgz",
|
||||
"integrity": "sha512-22MVyEnJgRv4RpFol6LefKAjh2ei7ekBIkawPZi+F0YNQtGPTTJP7r+gLT615oUcZFptBxiuogsXk6zhFycSsA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/env/-/env-1.1.0.tgz",
|
||||
"integrity": "sha512-q6GLj4HRBJZy12EHtqre1ihvSJMikl5jwenzIMjBkkAIuyl0bpOpMpnIuaP5bJ4dkVLTpsicIcEYn6aFGZsXOA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/headers": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/headers/-/headers-1.1.0.tgz",
|
||||
"integrity": "sha512-V4PVy84gxc30g8CGZaLl//QAogdaAKJ2Sbtjccd5iUmxeUXXdqW3L0/xwm0xCebwB8rxojwhG7CzD3uv781Zdw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/inspect": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/inspect/-/inspect-1.1.0.tgz",
|
||||
"integrity": "sha512-yaBGbG/iwfpR/mfyiomLGzePjUr7YFzLi2qss/TjDLcX6TvQ4nW+HqOidGzAE5IVqdtl13TG9vD2f2tv9AkIog==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@arcjet/protocol": "1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/ip": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/ip/-/ip-1.1.0.tgz",
|
||||
"integrity": "sha512-mxOqZ/EVhO3bN7NBr36yURyFLE9KEXUzW+Pbq3U9HogqjMoNA4g3rkomVo3cNWhJcNCHNMRKplWbFsvVuyRdHQ==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/logger": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/logger/-/logger-1.1.0.tgz",
|
||||
"integrity": "sha512-QQkDpdevbDOK8Ojy7REQap6y3J0fC1/5D/TE7hlC41Y2Gz6oyXIYzbLxEoyCYkfzMeOnMthHAXXwzI+E2gvdgg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@arcjet/sprintf": "1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/node": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/node/-/node-1.1.0.tgz",
|
||||
"integrity": "sha512-89WpKP3xwvpLuKPhN7hWMAER76EnI6f5tUydVMm+LJF1TKJcZt80L91vEO4nTQU+is28BR57P4/IF7q+voDQSQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@arcjet/body": "1.1.0",
|
||||
"@arcjet/env": "1.1.0",
|
||||
"@arcjet/headers": "1.1.0",
|
||||
"@arcjet/ip": "1.1.0",
|
||||
"@arcjet/logger": "1.1.0",
|
||||
"@arcjet/protocol": "1.1.0",
|
||||
"@arcjet/transport": "1.1.0",
|
||||
"arcjet": "1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/protocol": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/protocol/-/protocol-1.1.0.tgz",
|
||||
"integrity": "sha512-evjUsyOh04bQgH9lWm/xIyqF3C8XkiKvRa/QYuUvMYEpe/J1hndHaOZqzqlzQqkm44cbM5l8s+06SpHyaG/iFg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@arcjet/cache": "1.1.0",
|
||||
"@bufbuild/protobuf": "2.11.0",
|
||||
"@connectrpc/connect": "2.1.1",
|
||||
"typeid-js": "1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/runtime": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/runtime/-/runtime-1.1.0.tgz",
|
||||
"integrity": "sha512-v/7I9n3l9ZHBWGOoSBIxhEZ5WhcLPToWWXz8HBn30H1UFzholJCSDvIKesTogSt/EmxEUVDwxnHFZxZh+EX9Zw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/sprintf": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/sprintf/-/sprintf-1.1.0.tgz",
|
||||
"integrity": "sha512-YA19YrUYnEPxVPS5O41MlkynVLEtBVeu/eqrXGckQHmS7PuyNZEO2h8ZU+6G+ppua9igZUEzgYFVIh6UJRjWpQ==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/stable-hash": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/stable-hash/-/stable-hash-1.1.0.tgz",
|
||||
"integrity": "sha512-JdeLw2r7f4sJKRi48BAypjcqgwlMf8LgcVZs3xH+CjE0N9DAxkl1AY/6Wt03WOz4S0FahC/amzCVNMJ6TlnQfA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@arcjet/transport": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@arcjet/transport/-/transport-1.1.0.tgz",
|
||||
"integrity": "sha512-nv/9HSroy4UxndxFYF39St4t8yXTTKGnaKXqPDhRGBHwPGPMLvLHxvXD4bguDWu5iMSKGazsJFJx/RD/7SwG9Q==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@bufbuild/protobuf": "2.11.0",
|
||||
"@connectrpc/connect": "2.1.1",
|
||||
"@connectrpc/connect-node": "2.1.1",
|
||||
"@connectrpc/connect-web": "2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/biome": {
|
||||
"version": "2.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.13.tgz",
|
||||
@@ -191,6 +369,44 @@
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@bufbuild/protobuf": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.11.0.tgz",
|
||||
"integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==",
|
||||
"license": "(Apache-2.0 AND BSD-3-Clause)"
|
||||
},
|
||||
"node_modules/@connectrpc/connect": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-2.1.1.tgz",
|
||||
"integrity": "sha512-JzhkaTvM73m2K1URT6tv53k2RwngSmCXLZJgK580qNQOXRzZRR/BCMfZw3h+90JpnG6XksP5bYT+cz0rpUzUWQ==",
|
||||
"license": "Apache-2.0",
|
||||
"peerDependencies": {
|
||||
"@bufbuild/protobuf": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@connectrpc/connect-node": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@connectrpc/connect-node/-/connect-node-2.1.1.tgz",
|
||||
"integrity": "sha512-s3TfsI1XF+n+1z6MBS9rTnFsxxR4Rw5wmdEnkQINli81ESGxcsfaEet8duzq8LVuuCupmhUsgpRo0Nv9pZkufg==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@bufbuild/protobuf": "^2.7.0",
|
||||
"@connectrpc/connect": "2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@connectrpc/connect-web": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@connectrpc/connect-web/-/connect-web-2.1.1.tgz",
|
||||
"integrity": "sha512-J8317Q2MaFRCT1jzVR1o06bZhDIBmU0UAzWx6xOIXzOq8+k71/+k7MUF7AwcBUX+34WIvbm5syRgC5HXQA8fOg==",
|
||||
"license": "Apache-2.0",
|
||||
"peerDependencies": {
|
||||
"@bufbuild/protobuf": "^2.7.0",
|
||||
"@connectrpc/connect": "2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@dotenvx/dotenvx": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.52.0.tgz",
|
||||
@@ -1215,6 +1431,24 @@
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/arcjet": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/arcjet/-/arcjet-1.1.0.tgz",
|
||||
"integrity": "sha512-YRzr8kfTLdSdp45W5Xrzf1+TMAvDYELD2D2Gg6jXgLZl0PjM/SoK3TMCTz/CMxohBx2AV17/wSM24YjcDEoHcg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@arcjet/analyze": "1.1.0",
|
||||
"@arcjet/cache": "1.1.0",
|
||||
"@arcjet/duration": "1.1.0",
|
||||
"@arcjet/headers": "1.1.0",
|
||||
"@arcjet/protocol": "1.1.0",
|
||||
"@arcjet/runtime": "1.1.0",
|
||||
"@arcjet/stable-hash": "1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz",
|
||||
@@ -3211,6 +3445,15 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/typeid-js": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/typeid-js/-/typeid-js-1.2.0.tgz",
|
||||
"integrity": "sha512-t76ZucAnvGC60ea/HjVsB0TSoB0cw9yjnfurUgtInXQWUI/VcrlZGpO23KN3iSe8yOGUgb1zr7W7uEzJ3hSljA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"uuid": "^10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
@@ -3241,6 +3484,19 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
|
||||
"integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@arcjet/inspect": "^1.1.0",
|
||||
"@arcjet/node": "^1.1.0",
|
||||
"@dotenvx/dotenvx": "^1.52.0",
|
||||
"drizzle-orm": "^0.45.1",
|
||||
"express": "^5.2.1",
|
||||
|
||||
@@ -4,6 +4,7 @@ import http from "http";
|
||||
// routes
|
||||
import { matchRouter } from "./routes/matches.route.js";
|
||||
import { attachWebsocketServer } from "./ws/server.js";
|
||||
import { securityMiddleware } from "./utils/arkjet.js";
|
||||
|
||||
const PORT = process.env.PORT || 8081;
|
||||
const HOST = process.env.HOST || "0.0.0.0";
|
||||
@@ -18,6 +19,9 @@ app.get("/", (_, res) => {
|
||||
res.send("Hello from express server!");
|
||||
});
|
||||
|
||||
// middleware
|
||||
app.use(securityMiddleware());
|
||||
|
||||
app.use("/matches", matchRouter);
|
||||
|
||||
const { broadcastMatchCreated } = attachWebsocketServer(server);
|
||||
|
||||
57
src/utils/arkjet.js
Normal file
57
src/utils/arkjet.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import arcjet, { detectBot, shield, slidingWindow } from "@arcjet/node";
|
||||
|
||||
const arcjetKey = process.env.ARCJET_KEY;
|
||||
const arcjetMODE = process.env.ARCJET_MODE === "DRY_RUN" ? "DRY_RUN" : "LIVE";
|
||||
|
||||
if (!arcjetKey) throw new Error("ARKJET_KEY environment variable is missing.");
|
||||
|
||||
export const httpArkjet = arcjetKey
|
||||
? arcjet({
|
||||
key: arcjetKey,
|
||||
rules: [
|
||||
shield({ mode: arcjetMODE }),
|
||||
detectBot({
|
||||
mode: arcjetMODE,
|
||||
allow: ["CATEGORY:SEARCH_ENGINE", "CATEGORY:PREVIEW"],
|
||||
}),
|
||||
slidingWindow({ mode: arcjetMODE, interval: "10s", max: 50 }),
|
||||
],
|
||||
})
|
||||
: null;
|
||||
|
||||
export const wsArkjet = arcjetKey
|
||||
? arcjet({
|
||||
key: arcjetKey,
|
||||
rules: [
|
||||
shield({ mode: arcjetMODE }),
|
||||
detectBot({
|
||||
mode: arcjetMODE,
|
||||
allow: ["CATEGORY:SEARCH_ENGINE", "CATEGORY:PREVIEW"],
|
||||
}),
|
||||
slidingWindow({ mode: arcjetMODE, interval: "2s", max: 5 }),
|
||||
],
|
||||
})
|
||||
: null;
|
||||
|
||||
export const securityMiddleware = () => {
|
||||
return async (req, res, next) => {
|
||||
if (!httpArkjet) return next;
|
||||
|
||||
try {
|
||||
const decision = await httpArkjet.protect(req);
|
||||
|
||||
if (decision.isDenied()) {
|
||||
if (decision.reason.isRateLimit()) {
|
||||
return res.status(429).json({ error: "Too Many request" });
|
||||
}
|
||||
|
||||
return res.status(403).json({ error: "Forbidden" });
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("ArkJet middleware error", e);
|
||||
res.status(503).json({ error: "Service Unavailable" });
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import { WebSocket, WebSocketServer } from "ws";
|
||||
import { wsArkjet } from "../utils/arkjet.js";
|
||||
|
||||
const sendJson = (socket, payload) => {
|
||||
if (socket.readyState !== WebSocket.OPEN) {
|
||||
@@ -10,7 +11,7 @@ const sendJson = (socket, payload) => {
|
||||
|
||||
const broadcast = (wss, payload) => {
|
||||
for (const client of wss.clients) {
|
||||
if (client.readyState !== WebSocket.OPEN) return;
|
||||
if (client.readyState !== WebSocket.OPEN) continue;
|
||||
|
||||
client.send(JSON.stringify(payload));
|
||||
}
|
||||
@@ -23,12 +24,48 @@ export const attachWebsocketServer = (server) => {
|
||||
maxPayload: 1024 * 1024, // 1mb
|
||||
});
|
||||
|
||||
wss.on("connection", (socket) => {
|
||||
wss.on("connection", async (socket, req) => {
|
||||
if (wsArkjet) {
|
||||
try {
|
||||
const desision = await wsArkjet.protect(req);
|
||||
|
||||
if (desision.isDenied) {
|
||||
const code = desision.reason.isRateLimit() ? 1013 : 1008;
|
||||
const reason = desision.reason.isRateLimit()
|
||||
? "Rate limit exceedeed"
|
||||
: "Access denied";
|
||||
|
||||
socket.close(code, reason);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("WS connection error", e);
|
||||
socket.close(1011, "Server security error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
socket.isAlive = true;
|
||||
socket.on("pong", () => {
|
||||
socket.isAlive = true;
|
||||
});
|
||||
sendJson(socket, { type: "welcome" });
|
||||
|
||||
socket.on("error", console.error);
|
||||
});
|
||||
|
||||
const interval = setInterval(() => {
|
||||
wss.clients.forEach((ws) => {
|
||||
if (ws.isAlive === false) {
|
||||
ws.terminate();
|
||||
return;
|
||||
}
|
||||
ws.isAlive = false;
|
||||
ws.ping();
|
||||
});
|
||||
}, 30 * 1000);
|
||||
|
||||
wss.on("close", () => clearInterval(interval));
|
||||
|
||||
function broadcastMatchCreated(match) {
|
||||
broadcast(wss, { type: "match_created", data: match });
|
||||
}
|
||||
|
||||
56
testScripts/testRateLimits.js
Normal file
56
testScripts/testRateLimits.js
Normal file
@@ -0,0 +1,56 @@
|
||||
// Import the built-in HTTP module from Node.js
|
||||
// This lets us make HTTP requests without curl or extra packages
|
||||
import http from "http";
|
||||
|
||||
// How many times we want to hit the endpoint
|
||||
const TOTAL_REQUESTS = 60;
|
||||
|
||||
// Counter to keep track of how many requests we've made
|
||||
let count = 0;
|
||||
|
||||
// The URL we are testing
|
||||
const url = "http://localhost:8082/matches";
|
||||
|
||||
// test websocket rate limit
|
||||
const testWS = () => {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const ws = new WebSocket("ws://localhost:8082/ws");
|
||||
ws.onopen = () => console.info(`Socket ${i} opened`);
|
||||
ws.onclose = (e) =>
|
||||
console.info(`Socket ${i} closed: ${e.code} ${e.reason}`);
|
||||
}
|
||||
};
|
||||
|
||||
// This function makes ONE HTTP request
|
||||
function makeRequest() {
|
||||
count++;
|
||||
|
||||
// Create an HTTP GET request
|
||||
const req = http.get(url, (res) => {
|
||||
// res.statusCode is the HTTP response code (200, 404, 500, etc)
|
||||
console.info(res.statusCode);
|
||||
|
||||
// We don't care about the response body, so just discard it
|
||||
res.resume();
|
||||
|
||||
// If we haven't hit our limit yet, make another request
|
||||
if (count < TOTAL_REQUESTS) {
|
||||
makeRequest();
|
||||
}
|
||||
});
|
||||
|
||||
// If something goes wrong (server down, connection refused, etc)
|
||||
req.on("error", (err) => {
|
||||
console.error("Request failed:", err.message);
|
||||
|
||||
// Still continue so we always try 60 times
|
||||
if (count < TOTAL_REQUESTS) {
|
||||
makeRequest();
|
||||
}
|
||||
});
|
||||
|
||||
testWS();
|
||||
}
|
||||
|
||||
// Start the first request
|
||||
makeRequest();
|
||||
Reference in New Issue
Block a user