Compare commits
8 Commits
9624a4f45d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17ad42b3b9 | ||
|
|
ac9cd464ff | ||
|
|
dc501566d9 | ||
|
|
98f92b1b2b | ||
|
|
4a7b3bcc3a | ||
|
|
06789a25af | ||
|
|
d815626479 | ||
|
|
d0573f17f0 |
3
.env
Normal file
3
.env
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
NEXTJS_WEBHOOK_URL=https://webmail.ayris.tech/api/webhooks/mail-signal
|
||||
WEBHOOK_SECRET=besiktasK1903*
|
||||
2
.env.example
Normal file
2
.env.example
Normal file
@@ -0,0 +1,2 @@
|
||||
NEXTJS_WEBHOOK_URL=
|
||||
WEBHOOK_SECRET=
|
||||
18
Dockerfile
18
Dockerfile
@@ -1,16 +1,18 @@
|
||||
FROM node:20-alpine
|
||||
# Hafif bir Node.js imajı kullanalım
|
||||
FROM node:20-slim
|
||||
|
||||
# Install docker cli to be able to run 'docker logs' from within the container
|
||||
# Note: You must mount /var/run/docker.sock when running this container
|
||||
RUN apk add --no-cache docker-cli
|
||||
# Docker CLI'ı içine kuruyoruz (Çünkü Worker, Dovecot konteynerine komut gönderecek)
|
||||
RUN apt-get update && apt-get install -y docker.io && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Çalışma dizini
|
||||
WORKDIR /app
|
||||
|
||||
# Paket listelerini kopyala ve bağımlılıkları kur
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
RUN npm install --production
|
||||
|
||||
# Tüm kodları ve .env dosyasını kopyala
|
||||
COPY . .
|
||||
|
||||
RUN npm run build
|
||||
|
||||
CMD ["npm", "start"]
|
||||
# Uygulamayı başlat
|
||||
CMD ["node", "worker.js"]
|
||||
69
README.md
69
README.md
@@ -1,14 +1,61 @@
|
||||
# AyrisTech Worker
|
||||
# AyrisTech Mail Worker (V10.3)
|
||||
|
||||
This worker listens to Mailcow Dovecot logs and publishes incoming mail events to Redis.
|
||||
Mailcow Dovecot loglarını ve dosya sistemini izleyerek yeni gelen mailleri Next.js webhook'una ileten servis.
|
||||
|
||||
## Features
|
||||
- Real-time mail event tracking
|
||||
- Redis Pub/Sub integration
|
||||
- Dockerized deployment
|
||||
## Kurulum (Türkçe)
|
||||
|
||||
## Setup
|
||||
1. Clone the repository
|
||||
2. Install dependencies: `npm install`
|
||||
3. Configure `.env` file
|
||||
4. Run the worker: `npm start`
|
||||
### 1. Dosyaları Hazırlayın
|
||||
Örnek dosyayı kopyalayın ve bilgilerinizi girin:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
### 2. Çalıştırma (Docker Compose)
|
||||
En kolay ve tavsiye edilen yöntem:
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
### 3. Manuel Çalıştırma (Geliştirme)
|
||||
```bash
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# AyrisTech Mail Worker (V10.3) - English
|
||||
|
||||
Service that monitors Mailcow Dovecot logs and filesystem to forward new incoming emails to a Next.js webhook.
|
||||
|
||||
## Installation (English)
|
||||
|
||||
### 1. Prepare Files
|
||||
Copy the example file and enter your details:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
### 2. Execution (Docker Compose)
|
||||
The easiest and recommended method:
|
||||
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
### 3. Manual Run (Development)
|
||||
```bash
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Önemli Notlar / Important Notes
|
||||
- **TR**: Servis `docker exec` komutu kullandığı için `/var/run/docker.sock` erişimine ihtiyaç duyar.
|
||||
- **EN**: The service requires access to `/var/run/docker.sock` to execute `docker exec` commands.
|
||||
- **TR**: Mailcow mail dosyaları `/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/` yolunda olmalıdır.
|
||||
- **EN**: Mailcow email files must be located at `/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/`.
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { Redis } from 'ioredis';
|
||||
import { spawn } from 'child_process';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379';
|
||||
const CONTAINER_NAME = process.env.MAILCOW_CONTAINER_NAME || 'mailcowdockerized-dovecot-mailcow-1';
|
||||
|
||||
const redis = new Redis(REDIS_URL);
|
||||
|
||||
console.log("🚀 AyrisTech Worker Bağlanıyor...");
|
||||
|
||||
// Dovecot loglarını dinliyoruz
|
||||
const logProcess = spawn('docker', ['logs', '-f', CONTAINER_NAME]);
|
||||
|
||||
logProcess.stdout.on('data', async (data) => {
|
||||
const line = data.toString();
|
||||
|
||||
// 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}`);
|
||||
|
||||
// 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()
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
14
docker-compose.yml
Normal file
14
docker-compose.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
ayristech-worker:
|
||||
build: .
|
||||
container_name: ayristech-worker
|
||||
restart: always
|
||||
volumes:
|
||||
# Mail dosyalarını okumak için vmail volume'unu bağlıyoruz
|
||||
- /var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data:/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data:ro
|
||||
# Docker içinde docker komutu çalıştırabilmek için socket'i bağlıyoruz
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
env_file:
|
||||
- .env
|
||||
161
package-lock.json
generated
161
package-lock.json
generated
@@ -1,161 +0,0 @@
|
||||
{
|
||||
"name": "ayristech-worker",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ayristech-worker",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"ioredis": "^5.10.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.7.0",
|
||||
"typescript": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@ioredis/commands": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.1.tgz",
|
||||
"integrity": "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "25.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.7.0.tgz",
|
||||
"integrity": "sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cluster-key-slot": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
||||
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/denque": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/ioredis": {
|
||||
"version": "5.10.1",
|
||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.10.1.tgz",
|
||||
"integrity": "sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ioredis/commands": "1.5.1",
|
||||
"cluster-key-slot": "^1.1.0",
|
||||
"debug": "^4.3.4",
|
||||
"denque": "^2.1.0",
|
||||
"lodash.defaults": "^4.2.0",
|
||||
"lodash.isarguments": "^3.1.0",
|
||||
"redis-errors": "^1.2.0",
|
||||
"redis-parser": "^3.0.0",
|
||||
"standard-as-callback": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.22.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/ioredis"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash.defaults": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isarguments": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/redis-errors": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/redis-parser": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
|
||||
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"redis-errors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/standard-as-callback": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
|
||||
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
|
||||
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.21.0.tgz",
|
||||
"integrity": "sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
22
package.json
22
package.json
@@ -1,22 +1,16 @@
|
||||
{
|
||||
"name": "ayristech-worker",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "dist/apps/worker/main.js",
|
||||
"description": "AyrisTech Mailcow Worker",
|
||||
"main": "worker.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"
|
||||
"start": "node worker.js",
|
||||
"dev": "node --watch worker.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"axios": "^1.16.1",
|
||||
"chokidar": "^5.0.0",
|
||||
"dotenv": "^17.4.2",
|
||||
"ioredis": "^5.10.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.7.0",
|
||||
"typescript": "^6.0.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
// Visit https://aka.ms/tsconfig to read more about this file
|
||||
"compilerOptions": {
|
||||
// File Layout
|
||||
"rootDir": "./",
|
||||
"outDir": "./dist",
|
||||
|
||||
// Environment Settings
|
||||
// See also https://aka.ms/tsconfig/module
|
||||
"module": "nodenext",
|
||||
"target": "esnext",
|
||||
"types": [],
|
||||
// For nodejs:
|
||||
// "lib": ["esnext"],
|
||||
// "types": ["node"],
|
||||
// and npm install -D @types/node
|
||||
|
||||
// Other Outputs
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
|
||||
// Stricter Typechecking Options
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
|
||||
// Style Options
|
||||
// "noImplicitReturns": true,
|
||||
// "noImplicitOverride": true,
|
||||
// "noUnusedLocals": true,
|
||||
// "noUnusedParameters": true,
|
||||
// "noFallthroughCasesInSwitch": true,
|
||||
// "noPropertyAccessFromIndexSignature": true,
|
||||
|
||||
// Recommended Options
|
||||
"strict": true,
|
||||
"jsx": "react-jsx",
|
||||
"verbatimModuleSyntax": true,
|
||||
"isolatedModules": true,
|
||||
"noUncheckedSideEffectImports": true,
|
||||
"moduleDetection": "force",
|
||||
"skipLibCheck": true,
|
||||
}
|
||||
}
|
||||
65
worker.js
Normal file
65
worker.js
Normal file
@@ -0,0 +1,65 @@
|
||||
require('dotenv').config();
|
||||
const chokidar = require('chokidar');
|
||||
const axios = require('axios');
|
||||
const { exec } = require('child_process');
|
||||
|
||||
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/';
|
||||
|
||||
console.log("🚀 AyrisTech Güvenli Dekoder (V10.3) Başlatıldı...");
|
||||
|
||||
const watcher = chokidar.watch(vmailPath, {
|
||||
ignored: /(^|[\/\\])\../,
|
||||
persistent: true,
|
||||
ignoreInitial: true,
|
||||
depth: 5
|
||||
});
|
||||
|
||||
watcher.on('add', (filePath) => {
|
||||
if (filePath.includes('/new/')) {
|
||||
const parts = filePath.split('/');
|
||||
const fullEmail = `${parts[8]}@${parts[7]}`;
|
||||
|
||||
console.log(`📩 Yeni şifreli mail: ${fullEmail}. Çözülüyor...`);
|
||||
|
||||
// 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`;
|
||||
|
||||
setTimeout(() => {
|
||||
exec(cmd, async (error, stdout, stderr) => {
|
||||
if (error || stderr) {
|
||||
console.error("❌ Doveadm Hatası:", error ? error.message : stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user