const fs = require('fs'); const path = require('path'); const DEFAULT_AGHEERA_PUSH_URL = 'https://push-dhl.agheera.com/Telematics/positions'; const DEFAULT_AGHEERA_PUSH_LOG_PATH = '/var/log/agheera_push.log'; let httpClientOverride = null; const getPushUrl = () => String(process.env.AGHEERA_PUSH_URL || DEFAULT_AGHEERA_PUSH_URL).trim(); const getApiKey = () => String(process.env.AGHEERA_API_KEY || '').trim(); const getPushLogPath = () => String(process.env.AGHEERA_PUSH_LOG_PATH || DEFAULT_AGHEERA_PUSH_LOG_PATH).trim(); const appendPushLog = async ({ metadata, url, payload, success, status, responseBody, error }) => { if (process.env.AGHEERA_PUSH_LOGS === '0') { return; } const firstVehicle = Array.isArray(payload?.Vehicles) ? payload.Vehicles[0] : null; const entry = { timestamp: new Date().toISOString(), ...(metadata || {}), url, vehicleId: firstVehicle?.vehicleId ?? null, licensePlate: firstVehicle?.licensePlate ?? null, latitude: firstVehicle?.latitude ?? null, longitude: firstVehicle?.longitude ?? null, measurementTime: firstVehicle?.measurementTime ?? null, payload, success, http_status: status ?? null, response_body: responseBody || '', error: error || null }; try { const logPath = getPushLogPath(); await fs.promises.mkdir(path.dirname(logPath), { recursive: true }); await fs.promises.appendFile(logPath, `${JSON.stringify(entry)} `); } catch (logError) { console.error('Failed to append Agheera push log:', { message: logError.message }); } }; const formatMeasurementTime = (dateValue) => { const date = dateValue instanceof Date ? dateValue : new Date(dateValue); return date.toISOString().replace(/\.\d{3}Z$/, 'Z'); }; const normalizeNumber = (rawValue) => { const numericValue = Number(rawValue); return Number.isFinite(numericValue) ? numericValue : null; }; const getHttpClient = () => { if (typeof httpClientOverride === 'function') { return httpClientOverride; } if (typeof fetch === 'function') { return fetch; } return null; }; const buildPositionPayload = ({ latitude, longitude, vehicleId, licensePlate, measurementTime }) => ({ Vehicles: [ { latitude: normalizeNumber(latitude), longitude: normalizeNumber(longitude), vehicleId: String(vehicleId || '').trim(), licensePlate: String(licensePlate || '').trim(), measurementTime: formatMeasurementTime(measurementTime) } ] }); const pushPosition = async ({ latitude, longitude, vehicleId, licensePlate, measurementTime, metadata }) => { const url = getPushUrl(); const payload = buildPositionPayload({ latitude, longitude, vehicleId, licensePlate, measurementTime }); const httpClient = getHttpClient(); if (!httpClient) { const message = 'Agheera HTTP client unavailable'; await appendPushLog({ metadata, url, payload, success: false, error: message }); throw new Error(message); } const apiKey = getApiKey(); if (!apiKey) { const message = 'Agheera API key missing'; await appendPushLog({ metadata, url, payload, success: false, error: message }); throw new Error(message); } let response; try { response = await httpClient(url, { method: 'POST', headers: { apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); } catch (error) { await appendPushLog({ metadata, url, payload, success: false, error: error.message }); throw error; } const responseBody = typeof response?.text === 'function' ? await response.text() : ''; if (!response?.ok) { const error = new Error('Agheera push failed'); error.status = response?.status || null; error.body = responseBody; await appendPushLog({ metadata, url, payload, success: false, status: error.status, responseBody, error: error.message }); throw error; } await appendPushLog({ metadata, url, payload, success: true, status: response.status, responseBody }); return { status: response.status, body: responseBody }; }; const __setHttpClientForTests = (httpClient) => { httpClientOverride = httpClient; }; const __resetHttpClientForTests = () => { httpClientOverride = null; }; module.exports = { DEFAULT_AGHEERA_PUSH_URL, DEFAULT_AGHEERA_PUSH_LOG_PATH, pushPosition, __setHttpClientForTests, __resetHttpClientForTests };