Files
iistwin/server/gps/traccar.client.ts

96 lines
3.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Клиент Traccar REST API.
* Настройка через env: TRACCAR_API_URL, TRACCAR_USER, TRACCAR_PASSWORD.
* Если переменные не заданы — все методы тихо no-op с логом,
* чтобы GPS-модуль работал и без Traccar (например, только PWA-трекинг).
*/
const TRACCAR_API_URL = process.env.TRACCAR_API_URL;
const TRACCAR_USER = process.env.TRACCAR_USER;
const TRACCAR_PASSWORD = process.env.TRACCAR_PASSWORD;
function isConfigured(): boolean {
return Boolean(TRACCAR_API_URL && TRACCAR_USER && TRACCAR_PASSWORD);
}
function authHeaders(): Record<string, string> {
const basic = Buffer.from(`${TRACCAR_USER}:${TRACCAR_PASSWORD}`).toString("base64");
return {
Authorization: `Basic ${basic}`,
"Content-Type": "application/json",
};
}
interface TraccarDevice {
id: number;
uniqueId: string;
name: string;
}
/** Найти устройство по uniqueId; возвращает null, если не найдено */
async function findDevice(uniqueId: string): Promise<TraccarDevice | null> {
const url = `${TRACCAR_API_URL}/api/devices?uniqueId=${encodeURIComponent(uniqueId)}`;
const res = await fetch(url, { headers: authHeaders() });
if (!res.ok) {
throw new Error(`Traccar GET /api/devices: HTTP ${res.status}`);
}
const devices = (await res.json()) as TraccarDevice[];
return devices.find((d) => d.uniqueId === uniqueId) ?? null;
}
/**
* Создаёт устройство в Traccar, если его ещё нет.
* Возвращает id устройства или null при ошибке/отсутствии конфигурации.
*/
export async function ensureDevice(uniqueId: string, name: string): Promise<number | null> {
if (!isConfigured()) {
console.log("[GPS] Traccar не настроен (TRACCAR_API_URL/USER/PASSWORD), ensureDevice пропущен");
return null;
}
try {
const existing = await findDevice(uniqueId);
if (existing) return existing.id;
const res = await fetch(`${TRACCAR_API_URL}/api/devices`, {
method: "POST",
headers: authHeaders(),
body: JSON.stringify({ uniqueId, name }),
});
if (!res.ok) {
const text = await res.text().catch(() => "");
throw new Error(`Traccar POST /api/devices: HTTP ${res.status} ${text}`);
}
const device = (await res.json()) as TraccarDevice;
console.log(`[GPS] Traccar: создано устройство '${name}' (${uniqueId}), id=${device.id}`);
return device.id;
} catch (err) {
console.error("[GPS] Traccar ensureDevice error:", err);
return null;
}
}
/** Удаляет устройство из Traccar по uniqueId (если существует) */
export async function deleteDevice(uniqueId: string): Promise<void> {
if (!isConfigured()) {
console.log("[GPS] Traccar не настроен, deleteDevice пропущен");
return;
}
try {
const existing = await findDevice(uniqueId);
if (!existing) return;
const res = await fetch(`${TRACCAR_API_URL}/api/devices/${existing.id}`, {
method: "DELETE",
headers: authHeaders(),
});
if (!res.ok && res.status !== 404) {
throw new Error(`Traccar DELETE /api/devices/${existing.id}: HTTP ${res.status}`);
}
console.log(`[GPS] Traccar: удалено устройство ${uniqueId}`);
} catch (err) {
console.error("[GPS] Traccar deleteDevice error:", err);
}
}