ifms-pti/server/src/lib/wifiDevices.js

273 lines
7.3 KiB
JavaScript
Raw Normal View History

2020-12-17 20:28:09 +00:00
import { subMinutes } from 'date-fns'
2022-04-18 22:29:45 +00:00
import * as unifiController from './unifiController'
import * as ciscoController from './ciscoController'
2020-11-06 13:31:28 +00:00
import prisma from '../prisma'
2020-11-06 13:31:28 +00:00
2022-05-26 19:09:02 +00:00
import { pubsub, USER_PRESENCE_UPDATED, ACCESS_POINTS_UPDATED } from '../pubsub'
2022-06-09 13:29:14 +00:00
import { logError, logInfo, logLow, logSuccess } from './logger'
2020-12-03 21:27:03 +00:00
2021-11-03 15:37:58 +00:00
import { performance } from 'perf_hooks'
2022-03-31 12:17:48 +00:00
const RECENT_THRESHOLD_IN_MINUTES = 2
2020-11-19 15:38:44 +00:00
2022-06-09 13:29:14 +00:00
const OLD_DEVICES_THRESHOLD_IN_DAYS = 90
2021-11-03 15:37:58 +00:00
const TIMEOUT_IN_MILLISECONDS = process.env.TASK_TIMEOUT || 120000
2020-12-02 15:20:27 +00:00
let working = false
2020-11-18 23:51:16 +00:00
2022-04-18 22:29:45 +00:00
const wifiControllers = [unifiController, ciscoController]
2020-12-14 20:42:38 +00:00
async function getOnlineDevices() {
2022-06-14 13:26:01 +00:00
const onlineDevicesPromises = wifiControllers.map(wifiController =>
wifiController.getOnlineWifiDevices()
)
2020-12-14 20:42:38 +00:00
2022-04-18 22:29:45 +00:00
const onlineDevices = (await Promise.all(onlineDevicesPromises)).flat()
2020-12-14 20:42:38 +00:00
return onlineDevices
}
2022-04-20 18:31:38 +00:00
async function updateDevicesStatus(onlineDevices) {
2020-12-21 18:56:59 +00:00
const lastSeenThreshold = subMinutes(new Date(), RECENT_THRESHOLD_IN_MINUTES)
2022-04-20 18:31:38 +00:00
const onlineDevicesMacs = onlineDevices.map(device => device.mac)
2020-12-17 20:28:09 +00:00
const recent = prisma.wifiDevice.updateMany({
where: {
2022-04-20 18:31:38 +00:00
lastSeen: { gt: lastSeenThreshold },
status: 'ONLINE',
mac: { notIn: onlineDevicesMacs }
2020-12-17 20:28:09 +00:00
},
2022-04-20 18:31:38 +00:00
data: { status: 'RECENT' }
2020-12-17 20:28:09 +00:00
})
const offline = prisma.wifiDevice.updateMany({
where: {
2022-04-20 18:31:38 +00:00
lastSeen: { lte: lastSeenThreshold },
status: { not: 'OFFLINE' },
mac: { notIn: onlineDevicesMacs }
2020-12-17 20:28:09 +00:00
},
2022-04-20 18:31:38 +00:00
data: { status: 'OFFLINE' }
2020-12-14 20:42:38 +00:00
})
2020-12-17 20:28:09 +00:00
2021-01-04 21:39:15 +00:00
return prisma.$transaction([recent, offline])
2020-12-14 20:42:38 +00:00
}
2020-12-17 17:15:22 +00:00
async function forceUserDisconnect(mac) {
2021-11-03 14:03:47 +00:00
try {
await prisma.wifiDevice.update({
where: { mac },
data: {
user: {
disconnect: true
}
2021-10-28 16:34:30 +00:00
}
2021-11-03 14:03:47 +00:00
})
} catch (e) {
logError({
tags: ['wifiDevices'],
message: `Erro tentando desconectar o usuário do dispositivo "${mac}".`,
data: { error: e, mac }
})
}
2020-12-17 17:15:22 +00:00
}
2020-12-21 14:17:25 +00:00
function mockHostName({ mac, oui }) {
2021-11-29 14:09:04 +00:00
const shortOui = oui?.split(' ')[0] || 'desc'
2020-12-21 17:38:17 +00:00
const clearMac = mac ? mac.replaceAll(':', '') : ''
2020-12-21 14:17:25 +00:00
return `${shortOui}_${clearMac}`
}
2020-12-15 15:13:18 +00:00
async function updateDB(onlineDevices) {
2022-03-24 18:26:57 +00:00
const devicesUpsertPromises = onlineDevices.map(async device => {
if (!device.user) forceUserDisconnect(device.mac)
2020-12-15 15:13:18 +00:00
const user = device.user
2021-11-29 14:09:04 +00:00
? {
2022-06-14 13:26:01 +00:00
connect: {
sAMAccountName: device.user.replace('IFMS\\', '').toLowerCase()
}
2021-11-29 14:09:04 +00:00
}
2020-12-15 15:13:18 +00:00
: undefined
2020-12-21 17:24:07 +00:00
const hostname = device.hostname || mockHostName(device)
2021-11-25 13:11:06 +00:00
return prisma.wifiDevice
.upsert({
2020-12-15 15:13:18 +00:00
where: { mac: device.mac },
create: {
...device,
2020-12-21 17:24:07 +00:00
hostname,
2020-12-15 15:13:18 +00:00
firstSeen: device.firstSeen || new Date(),
2022-08-08 22:45:48 +00:00
user,
accessPoint: {
connect: {
hostname: device.apName
}
}
2020-12-15 15:13:18 +00:00
},
update: {
...device,
2020-12-21 17:24:07 +00:00
hostname,
2022-03-24 18:26:57 +00:00
user,
accessPoint: {
connect: {
hostname: device.apName
}
}
2020-12-15 15:13:18 +00:00
}
})
.catch(async e => {
// If is a binding problem, probably the device has an user outside of AD, so save it anyway...
2021-10-28 16:22:38 +00:00
if (e.code == 'P2025')
try {
await forceUserDisconnect(device.mac)
await prisma.wifiDevice.upsert({
where: { mac: device.mac },
create: {
...device,
hostname,
firstSeen: device.firstSeen || new Date(),
2022-07-14 16:01:32 +00:00
user: undefined,
accessPoint: {
connect: {
hostname: device.apName
}
}
},
update: {
...device,
hostname,
2022-03-24 18:26:57 +00:00
user: undefined,
accessPoint: {
connect: {
hostname: device.apName
}
}
}
})
} catch (e) {
logError({
tags: ['wifiDevices'],
2022-07-14 16:01:32 +00:00
message: `Erro ao adicionar o dispositivo "${device.mac}" AP: ${device.apMac}. Ele tinha um usuário fora do AD que foi ignorado, mas falhou mesmo assim. ${e.message} `,
data: { error: e, device }
})
}
else
2021-01-11 19:47:22 +00:00
logError({
tags: ['wifiDevices'],
2021-11-25 13:11:06 +00:00
message: `Erro tentando adicionar o dispositivo "${device.mac}: ${e.message}".`,
2021-01-11 19:47:22 +00:00
data: { error: e, device }
})
})
})
2021-11-25 13:11:06 +00:00
2022-03-24 18:26:57 +00:00
return Promise.allSettled(devicesUpsertPromises)
2020-12-15 15:13:18 +00:00
}
2021-11-03 15:37:58 +00:00
function updateDevicesInfo() {
return new Promise(async (resolve, reject) => {
if (working) return reject('A última atualização ainda não terminou')
working = true
const updateTimeout = setTimeout(() => {
reject('A função atingiu seu tempo limite.')
working = false
}, TIMEOUT_IN_MILLISECONDS)
try {
const startTime = performance.now()
const onlineDevices = await getOnlineDevices()
2022-04-20 18:31:38 +00:00
await updateDevicesStatus(onlineDevices)
2021-11-25 13:27:27 +00:00
2021-11-25 13:29:56 +00:00
const endTime = performance.now()
2021-11-25 13:27:27 +00:00
const startTimeDB = performance.now()
await updateDB(onlineDevices)
2021-11-25 13:27:27 +00:00
const endTimeDB = performance.now()
onlineDevices.length > 0
? resolve(
2022-06-14 13:26:01 +00:00
`${onlineDevices.length} atualizados em ${Math.floor(
endTime - startTime
)}ms, DB em ${Math.floor(endTimeDB - startTimeDB)}ms`
)
: reject('Não há dispositivos conectados no momento.')
pubsub.publish(USER_PRESENCE_UPDATED, {
userPresenceUpdated: onlineDevices.length
})
2022-05-26 19:09:02 +00:00
const updatedDbAccessPoints = await prisma.accessPoint.findMany({
include: {
wifiDevices: {
where: {
status: 'ONLINE'
}
}
}
})
2022-06-14 13:26:01 +00:00
pubsub.publish(ACCESS_POINTS_UPDATED, {
accessPointsUpdated: updatedDbAccessPoints
})
2022-05-26 19:09:02 +00:00
logSuccess({
tags: ['wifiDevices'],
2022-04-20 18:34:02 +00:00
message: `${onlineDevices.length} dispositivos Wi-Fi atualizados em
2022-06-14 13:26:01 +00:00
${((endTime - startTime) / 1000).toFixed(2)}s. BD em ${(
(endTimeDB - startTimeDB) /
1000
).toFixed(2)}s`
})
} catch (e) {
logError({
tags: ['wifiDevices'],
message: `Erro atualizando dispositivos Wi-Fi: ${e.message}`,
data: e
})
reject('Não foi possível atualizar as informações dos dispositivos.')
} finally {
working = false
clearTimeout(updateTimeout)
2021-11-03 15:37:58 +00:00
}
})
2020-11-06 13:31:28 +00:00
}
2022-06-09 13:29:14 +00:00
// Delete devices that are offline for more than OLD_DEVICES_THRESHOLD_IN_DAYS days
async function deleteOldDevices() {
2022-06-14 13:26:01 +00:00
const oldDevicesThresholdInMilliseconds =
OLD_DEVICES_THRESHOLD_IN_DAYS * 24 * 60 * 60 * 1000
2022-06-09 13:29:14 +00:00
const oldDevices = await prisma.wifiDevice.deleteMany({
where: {
lastSeen: {
lt: new Date(Date.now() - oldDevicesThresholdInMilliseconds)
},
status: 'OFFLINE'
}
})
if (oldDevices.count > 0)
logInfo({
tags: ['wifiDevices', 'deleteOldDevices'],
message: `${oldDevices.count} dispositivos Wi-Fi não vistos há mais de ${OLD_DEVICES_THRESHOLD_IN_DAYS} dias foram excluídos.`,
data: { oldDevices }
})
else
logInfo({
tags: ['wifiDevices', 'deleteOldDevices'],
message: `Nenhum dispositivo Wi-Fi não visto há mais de ${OLD_DEVICES_THRESHOLD_IN_DAYS} dias foi encontrado.`
})
}
export { updateDevicesInfo, deleteOldDevices }