import db from '@mds-core/mds-db' ; import cache from '@mds-core/mds-agency-cache' ; import { Query } from 'express-serve-static-core' ; import { Audit , AuditEvent , Device , Recorded , Telemetry , Timestamp , UUID , VehicleEvent , TelemetryData , WithGpsProperty , BoundingBox , EVENT_STATUS_MAP , VEHICLE_EVENT , VEHICLE_EVENTS , VEHICLE_STATUSES } from '@mds-core/mds-types' ; import logger from '@mds-core/mds-logger' ; import { now } from '@mds-core/mds-utils' ; export async function deleteAudit ( audit_trip_id ) { const result = await db . deleteAudit ( audit_trip_id ) ; return result ; } export async function readAudit ( audit_trip_id ) { try { const result = await db . readAudit ( audit_trip_id ) ; return result ; } catch ( err ) { return null ; } } export async function readAudits ( query ) { const result = await db . readAudits ( query ) ; return result ; } export async function writeAudit ( audit ) { const result = await db . writeAudit ( audit ) ; return result ; } export async function readAuditEvents ( audit_trip_id ) { const result = await db . readAuditEvents ( audit_trip_id ) ; return result ; } export async function writeAuditEvent ( event ) { const result = await db . writeAuditEvent ( event ) ; return result ; } export async function readDevice ( device_id , provider_id ) { const result = await db . readDevice ( device_id , provider_id ) ; return result ; } export async function readDevicesByVehicleId ( provider_id , vehicle_id ) { try { const start = now ( ) ; const results = await db . readDevicesByVehicleId ( provider_id , vehicle_id , vehicle_id . replace ( /[\W_-]/g , '' ) ) ; const finish = now ( ) ; const timeElapsed = finish - start ; logger . info ( `db.readDevicesByVehicleId ${ provider_id } ${ vehicle_id } time elapsed: ${ timeElapsed }ms` ) ; return results ; } catch ( err ) { return [ ] ; } } export async function readEvent ( device_id ) { if ( ! device_id ) { return null ; } try { const provider_event = await db . readEvent ( device_id ) ; return provider_event ; } catch ( err ) { return null ; } } export async function readEvents ( device_id , start_time , end_time ) { if ( start_time && end_time ) { const result = await db . readEvents ( { device_id , start_time , end_time } ) ; return result . events ; } return [ ] ; } export async function readTelemetry ( device_id , start_time , end_time ) { if ( start_time && end_time ) { const result = await db . readTelemetry ( device_id , start_time , end_time ) ; return result ; } return [ ] ; } export function withGpsProperty < T extends TelemetryData > ( { lat , lng , speed , heading , accuracy , hdop , altitude , satellites , ... props } ) { return { ... props , gps : { lat , lng , speed , heading , accuracy , hdop , altitude , satellites } } ; } export async function getVehicle ( provider_id , vehicle_id ) { const devices = await readDevicesByVehicleId ( provider_id , vehicle_id ) ; if ( devices . length === 0 ) { return null ; } const deviceStatusMap = { active : [ ] , inactive : [ ] } ; await Promise . all ( devices . map ( async ( device ) => { const deviceStatus = ( await cache . readDeviceStatus ( device . device_id ) ) as ( VehicleEvent & Device ) | null ; if ( deviceStatus === null || deviceStatus . event_type === VEHICLE_EVENTS . deregister ) { const { device_id } = device ; logger . info ( 'Bad vehicle status' , { deviceStatus , provider_id , vehicle_id , device_id } ) ; deviceStatusMap . inactive . push ( device ) ; } else { const status = EVENT_STATUS_MAP [ deviceStatus . event_type as VEHICLE_EVENT ] ; const updated = deviceStatus . timestamp ; deviceStatusMap . active . push ( { ... device , ... deviceStatus , status , updated } ) ; } } ) ) ; return deviceStatusMap . active [ 0 ] || deviceStatusMap . inactive [ 0 ] || null ; } export async function getVehicles ( skip , take , url , reqQuery , bbox , strict = true , provider_id ? ) { function fmt ( query ) { const flat = { ... reqQuery , ... query } ; let s = `${ url }?` ; s += Object . keys ( flat ) . map ( key => `${ key }=${ flat [ key ] }` ) . join ( '&' ) ; return s ; } const start = now ( ) ; const statusesSuperset = ( ( await cache . readDevicesStatus ( { bbox , strict } ) ) as ( VehicleEvent & Device ) [ ] ) . filter ( status => EVENT_STATUS_MAP [ status . event_type as VEHICLE_EVENT ] !== VEHICLE_STATUSES . removed && ( ! provider_id || status . provider_id === provider_id ) ) ; const statusesSubset = statusesSuperset . slice ( skip , skip + take ) ; const devices = statusesSubset . reduce ( ( acc , item ) => { const status = EVENT_STATUS_MAP [ item . event_type as VEHICLE_EVENT ] ; const updated = item . timestamp ; return [ ... acc , { ... item , status , updated } ] ; } , [ ] ) ; const finish = now ( ) ; logger . info ( `getVehicles processing ${ JSON . stringify ( bbox ) } provider ${ provider_id } time elapsed: ${ finish - start }ms` ) ; const noNext = skip + take >= statusesSuperset . length ; const noPrev = skip === 0 || skip > statusesSuperset . length ; const lastSkip = take * Math . floor ( statusesSuperset . length / take ) ; return { total : statusesSuperset . length , links : { first : fmt ( { skip : 0 , take } ) , last : fmt ( { skip : lastSkip , take } ) , prev : noPrev ? null : fmt ( { skip : skip - take , take } ) , next : noNext ? null : fmt ( { skip : skip + take , take } ) } , vehicles : devices } ; }