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
2020-11-18 21:25:57 +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 => {
2021-10-27 15:40:27 +00:00
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
2021-10-27 15:40:27 +00:00
. 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
}
} )
2021-10-27 15:40:27 +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' )
2021-10-27 15:40:27 +00:00
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
}
}
2021-10-27 15:40:27 +00:00
} ,
update : {
... device ,
hostname ,
2022-03-24 18:26:57 +00:00
user : undefined ,
accessPoint : {
connect : {
hostname : device . apName
}
}
2021-10-27 15:40:27 +00:00
}
} )
} 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 } ` ,
2021-10-27 15:40:27 +00:00
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-10-27 15:40:27 +00:00
} )
} )
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 ) => {
2021-11-04 14:31:42 +00:00
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 ( )
2021-11-04 14:31:42 +00:00
await updateDB ( onlineDevices )
2021-11-25 13:27:27 +00:00
const endTimeDB = performance . now ( )
2021-11-04 14:31:42 +00:00
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 `
)
2021-11-04 14:31:42 +00:00
: 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
2021-11-04 14:31:42 +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 `
2021-11-04 14:31:42 +00:00
} )
} 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 }