up
This commit is contained in:
+7
-1
@@ -49,6 +49,9 @@ LABEL maintainer="U-Site.app"
|
|||||||
LABEL description="WhatsApp Bot Manager with Queue Processing"
|
LABEL description="WhatsApp Bot Manager with Queue Processing"
|
||||||
LABEL version="2.0"
|
LABEL version="2.0"
|
||||||
|
|
||||||
|
# Configurar zona horaria Colombia
|
||||||
|
ENV TZ=America/Bogota
|
||||||
|
|
||||||
# Instalar dependencias runtime
|
# Instalar dependencias runtime
|
||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache \
|
||||||
bash \
|
bash \
|
||||||
@@ -64,7 +67,10 @@ RUN apk add --no-cache \
|
|||||||
mysql-client \
|
mysql-client \
|
||||||
redis \
|
redis \
|
||||||
ffmpeg \
|
ffmpeg \
|
||||||
openssl
|
openssl \
|
||||||
|
tzdata \
|
||||||
|
&& cp /usr/share/zoneinfo/America/Bogota /etc/localtime \
|
||||||
|
&& echo "America/Bogota" > /etc/timezone
|
||||||
|
|
||||||
# Copiar extensiones PHP desde builder
|
# Copiar extensiones PHP desde builder
|
||||||
COPY --from=builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
|
COPY --from=builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
|
||||||
|
|||||||
+7
-1
@@ -1,6 +1,9 @@
|
|||||||
# Dockerfile para workers dedicados (sin Nginx)
|
# Dockerfile para workers dedicados (sin Nginx)
|
||||||
FROM php:8.2-cli-alpine
|
FROM php:8.2-cli-alpine
|
||||||
|
|
||||||
|
# Configurar zona horaria Colombia
|
||||||
|
ENV TZ=America/Bogota
|
||||||
|
|
||||||
# Instalar dependencias
|
# Instalar dependencias
|
||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache \
|
||||||
bash \
|
bash \
|
||||||
@@ -13,7 +16,10 @@ RUN apk add --no-cache \
|
|||||||
oniguruma-dev \
|
oniguruma-dev \
|
||||||
mysql-client \
|
mysql-client \
|
||||||
redis \
|
redis \
|
||||||
zlib-dev
|
zlib-dev \
|
||||||
|
tzdata \
|
||||||
|
&& cp /usr/share/zoneinfo/America/Bogota /etc/localtime \
|
||||||
|
&& echo "America/Bogota" > /etc/timezone
|
||||||
|
|
||||||
# Instalar extensiones PHP
|
# Instalar extensiones PHP
|
||||||
RUN docker-php-ext-install -j$(nproc) \
|
RUN docker-php-ext-install -j$(nproc) \
|
||||||
|
|||||||
+95
-58
@@ -125,67 +125,104 @@ try {
|
|||||||
|
|
||||||
// Revisar nuevos mensajes en BD cada 3 segundos
|
// Revisar nuevos mensajes en BD cada 3 segundos
|
||||||
if (time() - $lastCheck >= 3) {
|
if (time() - $lastCheck >= 3) {
|
||||||
// 1. Verificar mensajes nuevos individuales (últimos 10 segundos)
|
// Mantener track de mensajes ya enviados para evitar duplicados
|
||||||
$recentMessages = $db->fetchAll(
|
static $lastMessageId = 0;
|
||||||
"SELECT c.*, u.phone_number, u.name as user_name
|
static $lastConversationCheck = null;
|
||||||
FROM conversations c
|
|
||||||
INNER JOIN users u ON c.user_id = u.id
|
|
||||||
WHERE c.created_at >= DATE_SUB(NOW(), INTERVAL 10 SECOND)
|
|
||||||
AND c.direction = 'incoming'
|
|
||||||
ORDER BY c.created_at DESC
|
|
||||||
LIMIT 10"
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($recentMessages as $msg) {
|
if ($lastConversationCheck === null) {
|
||||||
sendSSEEvent('new_message', [
|
// Primera vez: obtener el ID más alto y timestamp actual de la BD, sin enviar nada
|
||||||
'message_id' => $msg['id'],
|
$maxMsg = $db->fetch("SELECT MAX(id) as max_id FROM conversations");
|
||||||
'user_id' => $msg['user_id'],
|
$lastMessageId = $maxMsg['max_id'] ?? 0;
|
||||||
'phone_number' => $msg['phone_number'],
|
// Usar el timestamp de la BD para evitar problemas de zona horaria
|
||||||
'user_name' => $msg['user_name'],
|
$dbTime = $db->fetch("SELECT NOW() as now");
|
||||||
'content' => $msg['message_content'],
|
$lastConversationCheck = $dbTime['now'] ?? date('Y-m-d H:i:s');
|
||||||
'message_type' => $msg['message_type'] ?? 'text',
|
} else {
|
||||||
'direction' => $msg['direction'],
|
// 1. Verificar mensajes NUEVOS (solo los que tienen ID mayor al último visto)
|
||||||
'created_at' => $msg['created_at'],
|
$recentMessages = $db->fetchAll(
|
||||||
'timestamp' => time()
|
"SELECT c.*, u.phone_number, u.name as user_name
|
||||||
]);
|
FROM conversations c
|
||||||
}
|
INNER JOIN users u ON c.user_id = u.id
|
||||||
|
WHERE c.id > ?
|
||||||
// 2. Verificar si hay nuevas conversaciones desde la última revisión
|
AND c.direction = 'incoming'
|
||||||
$recentConversations = $db->fetchAll(
|
ORDER BY c.id ASC
|
||||||
"SELECT DISTINCT c.user_id, u.phone_number, u.name,
|
LIMIT 10",
|
||||||
MAX(c.created_at) as last_message_time,
|
[$lastMessageId]
|
||||||
COUNT(*) as message_count
|
|
||||||
FROM conversations c
|
|
||||||
INNER JOIN users u ON c.user_id = u.id
|
|
||||||
WHERE c.created_at >= DATE_SUB(NOW(), INTERVAL 10 SECOND)
|
|
||||||
GROUP BY c.user_id
|
|
||||||
ORDER BY last_message_time DESC
|
|
||||||
LIMIT 5"
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($recentConversations as $conv) {
|
|
||||||
sendSSEEvent('new_conversation', [
|
|
||||||
'user_id' => $conv['user_id'],
|
|
||||||
'phone_number' => $conv['phone_number'],
|
|
||||||
'name' => $conv['name'],
|
|
||||||
'message_count' => $conv['message_count'],
|
|
||||||
'timestamp' => $conv['last_message_time']
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verificar notificaciones no leídas
|
|
||||||
try {
|
|
||||||
$notifications = $db->fetchAll(
|
|
||||||
"SELECT id, user_id, type, message, data, is_read, created_at
|
|
||||||
FROM notifications
|
|
||||||
WHERE is_read = 0
|
|
||||||
ORDER BY created_at DESC
|
|
||||||
LIMIT 10"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($notifications && count($notifications) > 0) {
|
foreach ($recentMessages as $msg) {
|
||||||
foreach ($notifications as $notification) {
|
sendSSEEvent('new_message', [
|
||||||
sendSSEEvent('notification', $notification);
|
'message_id' => $msg['id'],
|
||||||
|
'user_id' => $msg['user_id'],
|
||||||
|
'phone_number' => $msg['phone_number'],
|
||||||
|
'user_name' => $msg['user_name'],
|
||||||
|
'content' => $msg['message_content'],
|
||||||
|
'message_type' => $msg['message_type'] ?? 'text',
|
||||||
|
'direction' => $msg['direction'],
|
||||||
|
'created_at' => $msg['created_at'],
|
||||||
|
'timestamp' => time()
|
||||||
|
]);
|
||||||
|
// Actualizar último ID visto
|
||||||
|
if ($msg['id'] > $lastMessageId) {
|
||||||
|
$lastMessageId = $msg['id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Verificar si hay nuevas conversaciones desde la última revisión
|
||||||
|
$recentConversations = $db->fetchAll(
|
||||||
|
"SELECT DISTINCT c.user_id, u.phone_number, u.name,
|
||||||
|
MAX(c.created_at) as last_message_time,
|
||||||
|
COUNT(*) as message_count
|
||||||
|
FROM conversations c
|
||||||
|
INNER JOIN users u ON c.user_id = u.id
|
||||||
|
WHERE c.created_at > ?
|
||||||
|
GROUP BY c.user_id
|
||||||
|
ORDER BY last_message_time DESC
|
||||||
|
LIMIT 5",
|
||||||
|
[$lastConversationCheck]
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($recentConversations as $conv) {
|
||||||
|
sendSSEEvent('new_conversation', [
|
||||||
|
'user_id' => $conv['user_id'],
|
||||||
|
'phone_number' => $conv['phone_number'],
|
||||||
|
'name' => $conv['name'],
|
||||||
|
'message_count' => $conv['message_count'],
|
||||||
|
'timestamp' => $conv['last_message_time']
|
||||||
|
]);
|
||||||
|
// Actualizar timestamp
|
||||||
|
if ($conv['last_message_time'] > $lastConversationCheck) {
|
||||||
|
$lastConversationCheck = $conv['last_message_time'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // Fin del else (primera inicialización vs verificaciones posteriores)
|
||||||
|
|
||||||
|
// Verificar notificaciones NUEVAS (solo las creadas desde la última verificación)
|
||||||
|
// NO enviar notificaciones guardadas - solo las que llegan en tiempo real
|
||||||
|
try {
|
||||||
|
static $lastNotificationCheck = null;
|
||||||
|
if ($lastNotificationCheck === null) {
|
||||||
|
// Primera vez: usar el timestamp de la BD, NO enviar nada
|
||||||
|
$dbTimeNotif = $db->fetch("SELECT NOW() as now");
|
||||||
|
$lastNotificationCheck = $dbTimeNotif['now'] ?? date('Y-m-d H:i:s');
|
||||||
|
} else {
|
||||||
|
// Verificaciones posteriores: solo notificaciones NUEVAS
|
||||||
|
$notifications = $db->fetchAll(
|
||||||
|
"SELECT id, user_id, type, message, data, is_read, created_at
|
||||||
|
FROM notifications
|
||||||
|
WHERE created_at > ?
|
||||||
|
ORDER BY created_at ASC
|
||||||
|
LIMIT 10",
|
||||||
|
[$lastNotificationCheck]
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($notifications && count($notifications) > 0) {
|
||||||
|
foreach ($notifications as $notification) {
|
||||||
|
sendSSEEvent('notification', $notification);
|
||||||
|
// Actualizar timestamp para evitar duplicados
|
||||||
|
if ($notification['created_at'] > $lastNotificationCheck) {
|
||||||
|
$lastNotificationCheck = $notification['created_at'];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
|||||||
+12
-8
@@ -2,26 +2,27 @@
|
|||||||
# Uso: docker-compose -f docker-compose.dev.yml up -d
|
# Uso: docker-compose -f docker-compose.dev.yml up -d
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# MySQL Database
|
# MariaDB Database (compatible con producción)
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql:8.0
|
image: mariadb:10.11
|
||||||
container_name: whatsapp-dev-mysql
|
container_name: whatsapp-dev-mysql
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "3306:3306"
|
- "3306:3306"
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-root_password_2026}
|
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-root_password_2026}
|
||||||
MYSQL_DATABASE: ${DB_NAME:-usite_whatsapp_bot}
|
MARIADB_DATABASE: ${DB_NAME:-usite_whatsapp_bot}
|
||||||
MYSQL_USER: ${DB_USER:-usite_whatsapp_user}
|
MARIADB_USER: ${DB_USER:-usite_whatsapp_user}
|
||||||
MYSQL_PASSWORD: ${DB_PASS:-6q!Vio0fn@PFmsLyHjH5}
|
MARIADB_PASSWORD: ${DB_PASS:-6q!Vio0fn@PFmsLyHjH5}
|
||||||
|
TZ: America/Bogota
|
||||||
volumes:
|
volumes:
|
||||||
- mysql-dev-data:/var/lib/mysql
|
- mysql-dev-data:/var/lib/mysql
|
||||||
- ./database:/docker-entrypoint-initdb.d:ro
|
- ./database:/docker-entrypoint-initdb.d:ro
|
||||||
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --default-time-zone=America/Bogota
|
||||||
networks:
|
networks:
|
||||||
- whatsapp-dev-network
|
- whatsapp-dev-network
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${DB_ROOT_PASSWORD:-root_password_2026}"]
|
test: ["CMD", "mariadb-admin", "ping", "-h", "localhost", "-u", "root", "-p${DB_ROOT_PASSWORD:-root_password_2026}"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
@@ -50,6 +51,9 @@ services:
|
|||||||
- ssl-certs:/etc/nginx/ssl
|
- ssl-certs:/etc/nginx/ssl
|
||||||
- php-socket:/run/php
|
- php-socket:/run/php
|
||||||
environment:
|
environment:
|
||||||
|
# Zona horaria Colombia
|
||||||
|
- TZ=America/Bogota
|
||||||
|
|
||||||
# Entorno de desarrollo
|
# Entorno de desarrollo
|
||||||
- APP_ENV=development
|
- APP_ENV=development
|
||||||
- APP_DEBUG=true
|
- APP_DEBUG=true
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ services:
|
|||||||
- /etc/letsencrypt:/etc/letsencrypt:ro
|
- /etc/letsencrypt:/etc/letsencrypt:ro
|
||||||
- ssl-certs:/etc/nginx/ssl
|
- ssl-certs:/etc/nginx/ssl
|
||||||
environment:
|
environment:
|
||||||
|
# Zona horaria Colombia
|
||||||
|
- TZ=America/Bogota
|
||||||
|
|
||||||
# Entorno
|
# Entorno
|
||||||
- APP_ENV=production
|
- APP_ENV=production
|
||||||
- APP_DEBUG=false
|
- APP_DEBUG=false
|
||||||
@@ -95,6 +98,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./logs:/var/www/html/logs
|
- ./logs:/var/www/html/logs
|
||||||
environment:
|
environment:
|
||||||
|
- TZ=America/Bogota
|
||||||
- APP_ENV=production
|
- APP_ENV=production
|
||||||
- APP_DEBUG=false
|
- APP_DEBUG=false
|
||||||
- DB_HOST=${DB_HOST:-77.37.126.126}
|
- DB_HOST=${DB_HOST:-77.37.126.126}
|
||||||
|
|||||||
+4
-1
@@ -4,7 +4,10 @@
|
|||||||
* Verifica que todos los servicios estén funcionando
|
* Verifica que todos los servicios estén funcionando
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once __DIR__ . '/vendor/autoload.php';
|
// Cargar autoload solo si existe (en desarrollo podría no estar)
|
||||||
|
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
|
||||||
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
}
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user