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
# 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
RUN apk add --no-cache docker-cli
@@ -11,6 +11,5 @@ RUN npm install
COPY . .
RUN npm run build
# Run using the start script (tsx apps/worker/main.ts)
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
- Real-time mail event tracking
- Redis Pub/Sub integration
- Dockerized deployment
- Real-time filesystem monitoring with `chokidar`
- Automatic mail decoding via `doveadm`
- Next.js Webhook integration
- Secure secret-based authentication
## Setup
1. Clone the repository
2. Install dependencies: `npm install`
3. Configure `.env` file
4. Run the worker: `npm start`
## Setup Instructions
### 1. Configuration
Create a `.env` file in the root directory (copy from `.env.example` if available):
```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';
import { spawn } from 'child_process';
import dotenv from 'dotenv';
require('dotenv').config();
const chokidar = require('chokidar');
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';
const CONTAINER_NAME = process.env.MAILCOW_CONTAINER_NAME || 'mailcowdockerized-dovecot-mailcow-1';
console.log("🚀 AyrisTech Güvenli Dekoder (V10.3) Başlatıldı...");
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
const logProcess = spawn('docker', ['logs', '-f', CONTAINER_NAME]);
console.log(`📩 Yeni şifreli mail: ${fullEmail}. Çözülüyor...`);
logProcess.stdout.on('data', async (data) => {
const line = data.toString();
// Komutu daha garantici bir hale getirdik
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
if (line.includes('saved mail to INBOX')) {
const match = line.match(/user=<([^>]+)>/);
if (match) {
const email = match[1];
console.log(`📩 Mail Geldi: ${email}`);
setTimeout(() => {
exec(cmd, async (error, stdout, stderr) => {
if (error || stderr) {
console.error("❌ Doveadm Hatası:", error ? error.message : stderr);
return;
}
// Olayı Redis'e fırlat (Pub/Sub)
// Bu sayede Next.js veya diğer servisler bu haberi alabilir
await redis.publish('NEW_MAIL_EVENT', JSON.stringify({
to: email,
time: new Date().toISOString()
}));
}
if (!stdout.trim()) {
console.log("⚠️ Mail içeriği henüz hazır değil (Stdout boş).");
return;
}
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"
}
}