docs: finalize installation instructions and infrastructure for overhauled worker

This commit is contained in:
AyrisAI
2026-05-14 19:14:43 +03:00
parent d815626479
commit 06789a25af
5 changed files with 101 additions and 63 deletions

6
.env.example Normal file
View File

@@ -0,0 +1,6 @@
# Webhook Configuration
NEXTJS_WEBHOOK_URL=https://your-nextjs-app.com/api/webhooks/mail-signal
WEBHOOK_SECRET=besiktasK1903*
# Redis (Optional, if used in other parts)
REDIS_URL=redis://localhost:6379

View File

@@ -1,6 +1,6 @@
FROM node:20-alpine FROM node:20-alpine
# Install docker cli to be able to run 'docker logs' from within the container # Install docker cli to be able to run 'docker exec' from within the container
# Note: You must mount /var/run/docker.sock when running this container # Note: You must mount /var/run/docker.sock when running this container
RUN apk add --no-cache docker-cli RUN apk add --no-cache docker-cli
@@ -11,6 +11,5 @@ RUN npm install
COPY . . COPY . .
RUN npm run build # Run using the start script (tsx apps/worker/main.ts)
CMD ["npm", "start"] CMD ["npm", "start"]

View File

@@ -1,14 +1,42 @@
# AyrisTech Worker # AyrisTech Worker (V10.3)
This worker listens to Mailcow Dovecot logs and publishes incoming mail events to Redis. This worker monitors Mailcow vmail volumes and triggers Next.js webhooks when new mail arrives.
## Features ## Features
- Real-time mail event tracking - Real-time filesystem monitoring with `chokidar`
- Redis Pub/Sub integration - Automatic mail decoding via `doveadm`
- Dockerized deployment - Next.js Webhook integration
- Secure secret-based authentication
## Setup ## Setup Instructions
1. Clone the repository
2. Install dependencies: `npm install` ### 1. Configuration
3. Configure `.env` file Create a `.env` file in the root directory (copy from `.env.example` if available):
4. Run the worker: `npm start` ```env
NEXTJS_WEBHOOK_URL=https://your-nextjs-app.com/api/webhooks/mail-signal
WEBHOOK_SECRET=your_secret_here
```
### 2. Local Installation
```bash
npm install
npm start
```
### 3. Docker Deployment
To run as a container, you must provide access to the Docker socket and the Mailcow volumes:
```bash
docker build -t ayristech-worker .
docker run -d \
--name ayristech-worker \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/:/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/ \
--env-file .env \
ayristech-worker
```
## Important Notes
- **Docker Socket**: The worker runs `docker exec` commands, so `/var/run/docker.sock` must be mounted.
- **Vmail Path**: The worker watches `/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/`. Ensure this volume exists and is mounted at the exact same path inside the container.

View File

@@ -1,35 +1,65 @@
import { Redis } from 'ioredis'; require('dotenv').config();
import { spawn } from 'child_process'; const chokidar = require('chokidar');
import dotenv from 'dotenv'; const axios = require('axios');
const { exec } = require('child_process');
dotenv.config(); const NEXTJS_WEBHOOK_URL = process.env.NEXTJS_WEBHOOK_URL;
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
const vmailPath = '/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/';
const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379'; console.log("🚀 AyrisTech Güvenli Dekoder (V10.3) Başlatıldı...");
const CONTAINER_NAME = process.env.MAILCOW_CONTAINER_NAME || 'mailcowdockerized-dovecot-mailcow-1';
const redis = new Redis(REDIS_URL); const watcher = chokidar.watch(vmailPath, {
ignored: /(^|[\/\\])\../,
persistent: true,
ignoreInitial: true,
depth: 5
});
console.log("🚀 AyrisTech Worker Bağlanıyor..."); watcher.on('add', (filePath) => {
if (filePath.includes('/new/')) {
const parts = filePath.split('/');
const fullEmail = `${parts[8]}@${parts[7]}`;
// Dovecot loglarını dinliyoruz console.log(`📩 Yeni şifreli mail: ${fullEmail}. Çözülüyor...`);
const logProcess = spawn('docker', ['logs', '-f', CONTAINER_NAME]);
logProcess.stdout.on('data', async (data) => { // Komutu daha garantici bir hale getirdik
const line = data.toString(); const cmd = `docker exec mailcowdockerized-dovecot-mailcow-1 doveadm fetch -u "${fullEmail}" "hdr.from hdr.subject body.snippet" ALL`;
// Mailcow'un mail teslimat logunu yakala setTimeout(() => {
if (line.includes('saved mail to INBOX')) { exec(cmd, async (error, stdout, stderr) => {
const match = line.match(/user=<([^>]+)>/); if (error || stderr) {
if (match) { console.error("❌ Doveadm Hatası:", error ? error.message : stderr);
const email = match[1]; return;
console.log(`📩 Mail Geldi: ${email}`); }
// Olayı Redis'e fırlat (Pub/Sub) if (!stdout.trim()) {
// Bu sayede Next.js veya diğer servisler bu haberi alabilir console.log("⚠️ Mail içeriği henüz hazır değil (Stdout boş).");
await redis.publish('NEW_MAIL_EVENT', JSON.stringify({ return;
to: email, }
time: new Date().toISOString()
})); let mailData = { to: fullEmail, from: 'Bilinmiyor', subject: 'Konu Yok', snippet: '' };
}
// Satır satır parse etme
const lines = stdout.split('\n');
lines.forEach(line => {
const l = line.trim();
if (l.toLowerCase().startsWith('hdr.from:')) mailData.from = l.split(':').slice(1).join(':').trim();
if (l.toLowerCase().startsWith('hdr.subject:')) mailData.subject = l.split(':').slice(1).join(':').trim();
if (l.toLowerCase().startsWith('body.snippet:')) mailData.snippet = l.split(':').slice(1).join(':').trim();
});
console.log(`✨ İçerik Çözüldü: ${mailData.subject}`);
try {
await axios.post(NEXTJS_WEBHOOK_URL, mailData, {
headers: { 'x-ayristech-secret': WEBHOOK_SECRET }
});
console.log(`✅ Webhook Next.js'e başarıyla ulaştı.`);
} catch (err) {
console.error("❌ Webhook Hatası:", err.message);
}
});
}, 2500); // Mailin DB'ye tam işlenmesi için süreyi biraz artırdık
} }
}); });

View File

@@ -1,25 +0,0 @@
{
"name": "ayristech-worker",
"version": "1.0.0",
"description": "",
"type": "module",
"main": "dist/apps/worker/main.js",
"scripts": {
"build": "tsc",
"start": "node dist/apps/worker/main.js",
"dev": "tsx apps/worker/main.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"dotenv": "^16.4.7",
"ioredis": "^5.10.1"
},
"devDependencies": {
"@types/node": "^25.7.0",
"tsx": "^4.19.2",
"typescript": "^6.0.3"
}
}