mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-09 23:48:36 +01:00
add new service + fix docs links
This commit is contained in:
3
producer/.gitignore
vendored
Normal file
3
producer/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
start_dev.js
|
||||
dist
|
||||
17
producer/ecosystem.config.cjs
Normal file
17
producer/ecosystem.config.cjs
Normal file
@@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'Producer',
|
||||
port: '3000',
|
||||
exec_mode: 'fork',
|
||||
script: './dist/producer/src/index.js',
|
||||
env: {
|
||||
PORT: "8088",
|
||||
REDIS_URL: "redis://litlyx.com",
|
||||
REDIS_USERNAME: "default",
|
||||
REDIS_PASSWORD: "cameriera",
|
||||
STREAM_NAME: "lib-events"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
23
producer/ecosystem.config.example.cjs
Normal file
23
producer/ecosystem.config.example.cjs
Normal file
@@ -0,0 +1,23 @@
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'QueueBroker',
|
||||
port: '3000',
|
||||
exec_mode: 'cluster',
|
||||
instances: '2',
|
||||
script: './dist/broker/src/index.js',
|
||||
env: {
|
||||
EMAIL_SERVICE: "",
|
||||
EMAIL_HOST: "",
|
||||
EMAIL_USER: "",
|
||||
EMAIL_PASS: "",
|
||||
PORT: "",
|
||||
MONGO_CONNECTION_STRING: "",
|
||||
REDIS_URL: "",
|
||||
REDIS_USERNAME: "",
|
||||
REDIS_PASSWORD: "",
|
||||
STREAM_NAME: ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
29
producer/package.json
Normal file
29
producer/package.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.19.2",
|
||||
"ioredis": "^5.4.1",
|
||||
"redis": "^4.6.14",
|
||||
"remove": "^0.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/node": "^20.14.2",
|
||||
"glob": "^10.4.1",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"name": "litlyx-producer",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"dev": "node scripts/start_dev.js",
|
||||
"compile": "tsc",
|
||||
"build": "ts-node scripts/build.ts",
|
||||
"build_all": "scripts/build_all.bat"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Emily",
|
||||
"license": "MIT",
|
||||
"description": "Producer for Litlyx - Saves events to redis stream."
|
||||
}
|
||||
1666
producer/pnpm-lock.yaml
generated
Normal file
1666
producer/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
producer/scripts/build.ts
Normal file
17
producer/scripts/build.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import { globSync } from 'glob';
|
||||
const tsconfigContent = fs.readFileSync('tsconfig.json', 'utf8');
|
||||
const tsconfigObject = JSON.parse(tsconfigContent);
|
||||
const paths = tsconfigObject.compilerOptions.paths;
|
||||
const filesList = globSync('dist/**/*.js');
|
||||
filesList.forEach(file => {
|
||||
let raw = fs.readFileSync(file, 'utf8');
|
||||
for (const path in paths) {
|
||||
const deep = (file.match(/\\|\//g) || []).length;
|
||||
const pathText = path.replace('*', '');
|
||||
const toReplaceText = new RegExp(`"${pathText}(.*?)"`, 'g');
|
||||
raw = raw.replace(toReplaceText, `"${new Array(deep - 2).fill('../').join('')}${paths[path][0].replace('*', '')}${'$1'}"`);
|
||||
}
|
||||
fs.writeFileSync(file, raw);
|
||||
});
|
||||
69
producer/src/index.ts
Normal file
69
producer/src/index.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { requireEnv } from "../../shared/utilts/requireEnv";
|
||||
import { RedisStreamService } from "@services/RedisStreamService";
|
||||
|
||||
import crypto from 'crypto';
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
|
||||
const app = express();
|
||||
app.use(cors());
|
||||
|
||||
const allowAnyType = () => true;
|
||||
const jsonOptions = { limit: '5mb', type: allowAnyType }
|
||||
|
||||
const streamName = requireEnv('STREAM_NAME');
|
||||
|
||||
|
||||
function getIPFromRequest(req: express.Request) {
|
||||
const ip = req.header('X-Real-IP') || req.header('X-Forwarded-For') || '0.0.0.0';
|
||||
return ip;
|
||||
}
|
||||
|
||||
|
||||
export function createSessionHash(website: string, ip: string, userAgent: string) {
|
||||
const dailySalt = new Date().toLocaleDateString('it-IT');
|
||||
const sessionClean = dailySalt + website + ip + userAgent;
|
||||
const sessionHash = crypto.createHash('md5').update(sessionClean).digest("hex");
|
||||
return sessionHash;
|
||||
}
|
||||
|
||||
app.post('/event', express.json(jsonOptions), async (req, res) => {
|
||||
try {
|
||||
const ip = getIPFromRequest(req);
|
||||
const sessionHash = createSessionHash(req.body.website, ip, req.body.userAgent);
|
||||
await RedisStreamService.addToStream(streamName, { ...req.body, _type: 'event', sessionHash, ip });
|
||||
return res.sendStatus(200);
|
||||
} catch (ex: any) {
|
||||
return res.status(500).json({ error: ex.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/visit', express.json(jsonOptions), async (req, res) => {
|
||||
try {
|
||||
const ip = getIPFromRequest(req);
|
||||
const sessionHash = createSessionHash(req.body.website, ip, req.body.userAgent);
|
||||
await RedisStreamService.addToStream(streamName, { ...req.body, _type: 'visit', sessionHash, ip });
|
||||
return res.sendStatus(200);
|
||||
} catch (ex: any) {
|
||||
return res.status(500).json({ error: ex.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/keep_alive', express.json(jsonOptions), async (req, res) => {
|
||||
try {
|
||||
const ip = getIPFromRequest(req);
|
||||
const sessionHash = createSessionHash(req.body.website, ip, req.body.userAgent);
|
||||
await RedisStreamService.addToStream(streamName, { ...req.body, _type: 'keep_alive', sessionHash, ip });
|
||||
return res.sendStatus(200);
|
||||
} catch (ex: any) {
|
||||
return res.status(500).json({ error: ex.message });
|
||||
}
|
||||
});
|
||||
|
||||
async function main() {
|
||||
await RedisStreamService.connect();
|
||||
app.listen(requireEnv("PORT"), () => console.log(`Listening on port ${requireEnv("PORT")}`));
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
28
producer/tsconfig.json
Normal file
28
producer/tsconfig.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "NodeNext",
|
||||
"target": "ESNext",
|
||||
"esModuleInterop": true,
|
||||
"outDir": "dist",
|
||||
"paths": {
|
||||
"@schema/*": [
|
||||
"../shared/schema/*"
|
||||
],
|
||||
"@services/*": [
|
||||
"../shared/services/*"
|
||||
],
|
||||
"@data/*": [
|
||||
"../shared/data/*"
|
||||
],
|
||||
"@functions/*": [
|
||||
"../shared/functions/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user