386 lines
9.7 KiB
PHP
386 lines
9.7 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\Cookie\CookieJar;
|
|
use GuzzleHttp\Exception\GuzzleException;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
class TraccarService
|
|
{
|
|
private Client $client;
|
|
private string $baseUrl;
|
|
private string $username;
|
|
private string $password;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->baseUrl = config('services.traccar.api_url');
|
|
$this->username = config('services.traccar.admin_username');
|
|
$this->password = config('services.traccar.admin_password');
|
|
|
|
$this->client = new Client([
|
|
'timeout' => 30,
|
|
'headers' => [
|
|
'Accept' => 'application/json',
|
|
'User-Agent' => 'Laravel-TraccarService/1.0',
|
|
],
|
|
'verify' => false, // For development only
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Make authenticated request to Traccar API
|
|
*/
|
|
private function makeRequest(string $method, string $endpoint, array $data = []): array
|
|
{
|
|
try {
|
|
$fullUrl = $this->baseUrl . $endpoint;
|
|
|
|
$options = [
|
|
'auth' => [$this->username, $this->password, 'basic'],
|
|
'headers' => [
|
|
'Accept' => 'application/json',
|
|
'User-Agent' => 'Laravel-TraccarService/1.0',
|
|
],
|
|
];
|
|
|
|
if (!empty($data)) {
|
|
$options['json'] = $data;
|
|
$options['headers']['Content-Type'] = 'application/json';
|
|
}
|
|
|
|
$response = $this->client->request($method, $fullUrl, $options);
|
|
$responseBody = $response->getBody()->getContents();
|
|
$result = json_decode($responseBody, true);
|
|
|
|
Log::info("Traccar API Request", [
|
|
'method' => $method,
|
|
'endpoint' => $endpoint,
|
|
'full_url' => $fullUrl,
|
|
'status' => $response->getStatusCode(),
|
|
'response_length' => strlen($responseBody),
|
|
'response_preview' => substr($responseBody, 0, 200),
|
|
'content_type' => $response->getHeaderLine('Content-Type'),
|
|
]);
|
|
|
|
// Handle empty responses or null JSON decode results
|
|
if ($result === null && !empty($responseBody)) {
|
|
Log::warning("Failed to decode JSON response", [
|
|
'raw_response' => $responseBody,
|
|
'content_type' => $response->getHeaderLine('Content-Type'),
|
|
]);
|
|
return [];
|
|
}
|
|
|
|
return $result ?? [];
|
|
} catch (GuzzleException $e) {
|
|
Log::error("Traccar API Error", [
|
|
'method' => $method,
|
|
'endpoint' => $endpoint,
|
|
'full_url' => $this->baseUrl . $endpoint,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
// ===== SERVER METHODS =====
|
|
|
|
/**
|
|
* Get server information
|
|
*/
|
|
public function getServerInfo(): array
|
|
{
|
|
return $this->makeRequest('GET', '/server');
|
|
}
|
|
|
|
// ===== USER METHODS =====
|
|
|
|
/**
|
|
* Get all users
|
|
*/
|
|
public function getUsers(): array
|
|
{
|
|
return $this->makeRequest('GET', '/users');
|
|
}
|
|
|
|
/**
|
|
* Create a new user in Traccar
|
|
*/
|
|
public function createUser(array $userData): array
|
|
{
|
|
return $this->makeRequest('POST', '/users', $userData);
|
|
}
|
|
|
|
/**
|
|
* Update user in Traccar
|
|
*/
|
|
public function updateUser(int $userId, array $userData): array
|
|
{
|
|
return $this->makeRequest('PUT', "/users/{$userId}", $userData);
|
|
}
|
|
|
|
/**
|
|
* Delete user from Traccar
|
|
*/
|
|
public function deleteUser(int $userId): bool
|
|
{
|
|
$this->makeRequest('DELETE', "/users/{$userId}");
|
|
return true;
|
|
}
|
|
|
|
// ===== DEVICE METHODS =====
|
|
|
|
/**
|
|
* Get all devices
|
|
*/
|
|
public function getDevices(?int $userId = null): array
|
|
{
|
|
$endpoint = '/devices';
|
|
if ($userId) {
|
|
$endpoint .= "?userId={$userId}";
|
|
}
|
|
|
|
return $this->makeRequest('GET', $endpoint);
|
|
}
|
|
|
|
/**
|
|
* Create a new device
|
|
*/
|
|
public function createDevice(array $deviceData): array
|
|
{
|
|
return $this->makeRequest('POST', '/devices', $deviceData);
|
|
}
|
|
|
|
/**
|
|
* Update device
|
|
*/
|
|
public function updateDevice(int $deviceId, array $deviceData): array
|
|
{
|
|
return $this->makeRequest('PUT', "/devices/{$deviceId}", $deviceData);
|
|
}
|
|
|
|
/**
|
|
* Delete device
|
|
*/
|
|
public function deleteDevice(int $deviceId): bool
|
|
{
|
|
$this->makeRequest('DELETE', "/devices/{$deviceId}");
|
|
return true;
|
|
}
|
|
|
|
// ===== POSITION METHODS =====
|
|
|
|
/**
|
|
* Get latest positions for all devices
|
|
*/
|
|
public function getPositions(): array
|
|
{
|
|
return $this->makeRequest('GET', '/positions');
|
|
}
|
|
|
|
/**
|
|
* Get latest positions for specific devices
|
|
*/
|
|
public function getDevicePositions(int $deviceId, ?string $from = null, ?string $to = null): array
|
|
{
|
|
$params = ['deviceId' => $deviceId];
|
|
if ($from) $params['from'] = $from;
|
|
if ($to) $params['to'] = $to;
|
|
|
|
$query = http_build_query($params);
|
|
$endpoint = "/positions?{$query}";
|
|
|
|
return $this->makeRequest('GET', $endpoint);
|
|
}
|
|
|
|
/**
|
|
* Get latest positions for multiple devices
|
|
*/
|
|
public function getMultipleDevicePositions(array $deviceIds): array
|
|
{
|
|
if (empty($deviceIds)) {
|
|
return [];
|
|
}
|
|
|
|
// Build query string for multiple device IDs
|
|
$params = [];
|
|
foreach ($deviceIds as $deviceId) {
|
|
$params[] = "deviceId={$deviceId}";
|
|
}
|
|
$query = implode('&', $params);
|
|
|
|
$endpoint = "/positions?{$query}";
|
|
return $this->makeRequest('GET', $endpoint);
|
|
}
|
|
|
|
/**
|
|
* Get real-time positions (latest for all user devices)
|
|
*/
|
|
public function getRealTimePositions(array $deviceIds = []): array
|
|
{
|
|
if (empty($deviceIds)) {
|
|
// Get latest positions for all devices
|
|
return $this->getPositions();
|
|
}
|
|
|
|
// Get positions for specific devices
|
|
return $this->getMultipleDevicePositions($deviceIds);
|
|
}
|
|
|
|
// ===== GEOFENCE METHODS =====
|
|
|
|
/**
|
|
* Get all geofences
|
|
*/
|
|
public function getGeofences(): array
|
|
{
|
|
return $this->makeRequest('GET', '/geofences');
|
|
}
|
|
|
|
/**
|
|
* Create geofence
|
|
*/
|
|
public function createGeofence(array $geofenceData): array
|
|
{
|
|
return $this->makeRequest('POST', '/geofences', $geofenceData);
|
|
}
|
|
|
|
/**
|
|
* Update geofence
|
|
*/
|
|
public function updateGeofence(int $geofenceId, array $geofenceData): array
|
|
{
|
|
return $this->makeRequest('PUT', "/geofences/{$geofenceId}", $geofenceData);
|
|
}
|
|
|
|
/**
|
|
* Delete geofence
|
|
*/
|
|
public function deleteGeofence(int $geofenceId): bool
|
|
{
|
|
$this->makeRequest('DELETE', "/geofences/{$geofenceId}");
|
|
return true;
|
|
}
|
|
|
|
// ===== EVENT METHODS =====
|
|
|
|
/**
|
|
* Get events
|
|
*/
|
|
public function getEvents(?int $deviceId = null, ?string $type = null): array
|
|
{
|
|
$params = [];
|
|
if ($deviceId) $params['deviceId'] = $deviceId;
|
|
if ($type) $params['type'] = $type;
|
|
|
|
$query = http_build_query($params);
|
|
$endpoint = '/events' . ($query ? "?{$query}" : '');
|
|
|
|
return $this->makeRequest('GET', $endpoint);
|
|
}
|
|
|
|
// ===== REPORT METHODS =====
|
|
|
|
/**
|
|
* Get trip reports
|
|
*/
|
|
public function getTripReports(array $deviceIds, string $from, string $to): array
|
|
{
|
|
$params = [
|
|
'deviceId' => $deviceIds,
|
|
'from' => $from,
|
|
'to' => $to
|
|
];
|
|
|
|
$query = http_build_query($params);
|
|
return $this->makeRequest('GET', "/reports/trips?{$query}");
|
|
}
|
|
|
|
/**
|
|
* Get summary reports
|
|
*/
|
|
public function getSummaryReports(array $deviceIds, string $from, string $to): array
|
|
{
|
|
$params = [
|
|
'deviceId' => $deviceIds,
|
|
'from' => $from,
|
|
'to' => $to
|
|
];
|
|
|
|
$query = http_build_query($params);
|
|
return $this->makeRequest('GET', "/reports/summary?{$query}");
|
|
}
|
|
|
|
// ===== COMMAND METHODS =====
|
|
|
|
/**
|
|
* Send command to device
|
|
*/
|
|
public function sendCommand(array $commandData): array
|
|
{
|
|
return $this->makeRequest('POST', '/commands/send', $commandData);
|
|
}
|
|
|
|
/**
|
|
* Get available command types
|
|
*/
|
|
public function getCommandTypes(): array
|
|
{
|
|
return $this->makeRequest('GET', '/commands/types');
|
|
}
|
|
|
|
// ===== PERMISSION METHODS =====
|
|
|
|
/**
|
|
* Link user to device
|
|
*/
|
|
public function linkUserDevice(int $userId, int $deviceId): bool
|
|
{
|
|
$this->makeRequest('POST', '/permissions', [
|
|
'userId' => $userId,
|
|
'deviceId' => $deviceId
|
|
]);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Unlink user from device
|
|
*/
|
|
public function unlinkUserDevice(int $userId, int $deviceId): bool
|
|
{
|
|
$this->makeRequest('DELETE', '/permissions', [
|
|
'userId' => $userId,
|
|
'deviceId' => $deviceId
|
|
]);
|
|
return true;
|
|
}
|
|
|
|
// ===== UTILITY METHODS =====
|
|
|
|
/**
|
|
* Test API connection
|
|
*/
|
|
public function testConnection(): bool
|
|
{
|
|
try {
|
|
$this->getServerInfo();
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear cached data
|
|
*/
|
|
public function clearCache(): void
|
|
{
|
|
Cache::forget('traccar_positions');
|
|
}
|
|
}
|