refactor: isolate SSE setup

This commit is contained in:
josedario87
2025-06-09 15:16:02 -06:00
parent ed30369d3b
commit 031314d662
6 changed files with 110 additions and 5 deletions

View File

@@ -0,0 +1,26 @@
-- Create function and trigger to notify SSE on planilla changes
CREATE OR REPLACE FUNCTION notify_planilla_change() RETURNS trigger AS $$
DECLARE
payload TEXT;
BEGIN
payload := json_build_object(
'table', TG_TABLE_NAME,
'operation', TG_OP,
'old', row_to_json(OLD),
'new', row_to_json(NEW)
)::text;
PERFORM pg_notify('sse_events', payload);
IF TG_OP = 'DELETE' THEN
RETURN OLD;
ELSE
RETURN NEW;
END IF;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS planilla_notify_trigger ON "Planilla";
CREATE TRIGGER planilla_notify_trigger
AFTER INSERT OR UPDATE OR DELETE ON "Planilla"
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
EXECUTE PROCEDURE notify_planilla_change();

View File

@@ -2,6 +2,7 @@ import express from 'express';
import { PrismaClient } from './prisma/generated/client/index.js';
import { Decimal } from '@prisma/client/runtime/library.js';
import cors from 'cors';
import { registerSse } from './sse/index.js';
// Import new routers
import empleadosRouter from './routes/empleados/empleados.js';
@@ -48,6 +49,9 @@ app.use(cors({
origin: ['http://localhost:5173', 'https://planilla.interno.com'],
credentials: true
}));
// --------- Server Sent Events setup ---------
registerSse(app);
// Mount new routers
app.use('/api/empleados', empleadosRouter);
app.use('/api/asistencias', asistenciasRouter);

39
api/sse/index.js Normal file
View File

@@ -0,0 +1,39 @@
import pg from 'pg';
export function registerSse(app) {
const sseClients = [];
app.get('/events', (req, res) => {
res.set({
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive'
});
res.flushHeaders();
res.write(':\n\n');
sseClients.push(res);
res.on('close', () => {
const idx = sseClients.indexOf(res);
if (idx !== -1) sseClients.splice(idx, 1);
res.end();
});
});
const broadcast = (data) => {
const payload = `data: ${data}\n\n`;
sseClients.forEach((client) => client.write(payload));
};
const { Client: PgClient } = pg;
const pgClient = new PgClient({ connectionString: process.env.DATABASE_URL });
pgClient.connect()
.then(() => pgClient.query('LISTEN sse_events'))
.then(() => console.log('🛎️ Listening to Postgres channel sse_events'))
.catch((err) => console.error('PG listen error', err));
pgClient.on('notification', (msg) => {
console.log('Notificación Postgres:', msg.payload);
broadcast(msg.payload);
});
}