Add events endpoint and event listener

This commit is contained in:
Douglas Barone 2024-01-24 15:13:21 -04:00
parent 5136e6c9c7
commit 69b6953cf8
7 changed files with 83 additions and 5 deletions

View File

@ -0,0 +1,53 @@
import { Request, Response, Router } from 'express'
import { randomUUID } from 'crypto'
import log from '../log.js'
const router = Router()
export class EventsController {
private static clients: { id: string; res: Response }[] = []
static async eventsHandler(req: Request, res: Response) {
const headers = {
'Content-Type': 'text/event-stream',
Connection: 'keep-alive',
'Cache-Control': 'no-cache',
'Access-Control-Allow-Origin': '*'
}
res.writeHead(200, headers)
const clientId = randomUUID()
const newClient = {
id: clientId,
res
}
EventsController.clients.push(newClient)
log.info(new Date().toLocaleString(), `${clientId} Connection opened`)
req.on('close', () => {
log.info(new Date().toLocaleString(), `${clientId} Connection closed`)
EventsController.clients = EventsController.clients.filter(
client => client.id !== clientId
)
})
}
static async sendEvent(event: string, data: any = null) {
this.clients.forEach(client => {
log.info(
new Date().toLocaleString(),
`Sending event ${event} to ${client.id}`
)
client.res.write(`event: ${event}\n`)
client.res.write(`data: ${JSON.stringify(data)}\n\n`)
})
}
}
router.get('/', EventsController.eventsHandler)
export default router

View File

@ -1,11 +1,13 @@
import * as path from 'node:path' import * as path from 'node:path'
import { fileURLToPath } from 'node:url' import { fileURLToPath } from 'node:url'
import Bree from 'bree' import Bree from 'bree'
import { EventsController } from './controllers/EventsController.js'
export const jobs = new Bree({ export const jobs = new Bree({
root: path.join(path.dirname(fileURLToPath(import.meta.url)), 'jobs'), root: path.join(path.dirname(fileURLToPath(import.meta.url)), 'jobs'),
defaultExtension: process.env.NODE_ENV == 'production' ? 'js' : 'ts', defaultExtension: process.env.NODE_ENV == 'production' ? 'js' : 'ts',
logger: false, logger: false,
jobs: [ jobs: [
{ {
name: 'updatePrinterStatus', name: 'updatePrinterStatus',
@ -18,3 +20,8 @@ export const jobs = new Bree({
} }
] ]
}) })
jobs.on('worker deleted', name => {
if (name == 'updatePrinterStatus')
EventsController.sendEvent('printerStatusUpdated', { status: 'success' })
})

View File

@ -1,4 +1,4 @@
import express, { Request, Response } from 'express' import express from 'express'
import bodyParser from 'body-parser' import bodyParser from 'body-parser'
import cors from 'cors' import cors from 'cors'
@ -9,10 +9,16 @@ import LoginRouter from './controllers/LoginController.js'
import PrinterRouter from './controllers/PrinterController.js' import PrinterRouter from './controllers/PrinterController.js'
import PrinterStatusRouter from './controllers/PrinterStatusController.js' import PrinterStatusRouter from './controllers/PrinterStatusController.js'
import PrinterDiscoveryRouter from './controllers/PrinterDiscoveryController.js' import PrinterDiscoveryRouter from './controllers/PrinterDiscoveryController.js'
import EventsRouter from './controllers/EventsController.js'
export const app = express() export const app = express()
app.use(cors()) app.use(
cors({
// Allow all origins
origin: '*'
})
)
app.use(populateUserMiddleware) app.use(populateUserMiddleware)
app.use('/api', loggerMiddleware) app.use('/api', loggerMiddleware)
@ -22,6 +28,7 @@ app.use('/api/login', LoginRouter)
app.use('/api/printer', PrinterRouter) app.use('/api/printer', PrinterRouter)
app.use('/api/status', PrinterStatusRouter) app.use('/api/status', PrinterStatusRouter)
app.use('/api/discovery', PrinterDiscoveryRouter) app.use('/api/discovery', PrinterDiscoveryRouter)
app.use('/api/events', EventsRouter)
app.use('/', express.static('public')) app.use('/', express.static('public'))

View File

@ -1 +1 @@
VITE_BASE_URL=http://localhost:8000/api/ VITE_BASE_API_URL=http://localhost:8000/api/

View File

@ -1 +1 @@
VITE_BASE_URL=https://printers.pp.ifms.edu.br/api/ VITE_BASE_API_URL=https://printers.pp.ifms.edu.br/api/

View File

@ -14,6 +14,7 @@
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useAppStore } from './store/appStore' import { useAppStore } from './store/appStore'
import { onBeforeMount } from 'vue' import { onBeforeMount } from 'vue'
import { BASE_URL } from './api'
const router = useRouter() const router = useRouter()
const appStore = useAppStore() const appStore = useAppStore()
@ -29,5 +30,14 @@ onBeforeMount(async () => {
appStore.selectedCampus = appStore.me?.campus || '' appStore.selectedCampus = appStore.me?.campus || ''
await appStore.fetchPrinters() await appStore.fetchPrinters()
const eventURI = `${BASE_URL}events`
const events = new EventSource(eventURI)
events.onmessage = async event => {
await appStore.fetchPrinters()
console.log('Event:', event)
}
}) })
</script> </script>

View File

@ -1,4 +1,5 @@
const BASE_URL = import.meta.env.VITE_BASE_URL || 'http://localhost:8000/api/' export const BASE_URL =
import.meta.env.VITE_BASE_API_URL || 'http://localhost:8000/api/'
export async function api<T>(endpoint: string, options: any): Promise<T> { export async function api<T>(endpoint: string, options: any): Promise<T> {
const token = localStorage.getItem('token') const token = localStorage.getItem('token')