feat: Add TeleCart Pulse heartbeat telemetry
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
APP_DEBUG=true
|
||||
PULSE_API_HOST=http://host.docker.internal:8086/api/
|
||||
PULSE_HEARTBEAT_SECRET=c5261f5d-529e-45ad-a69c-9778b755b7cb
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
APP_DEBUG=false
|
||||
PULSE_API_HOST=http://host.docker.internal:8086/api/
|
||||
PULSE_HEARTBEAT_SECRET=c5261f5d-529e-45ad-a69c-9778b755b7cb
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
APP_DEBUG=false
|
||||
PULSE_API_HOST=https://pulse.telecart.pro/api/
|
||||
PULSE_HEARTBEAT_SECRET=c5261f5d-529e-45ad-a69c-9778b755b7cb
|
||||
|
||||
@@ -6,25 +6,41 @@ use Carbon\Carbon;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Openguru\OpenCartFramework\Cache\CacheInterface;
|
||||
use Openguru\OpenCartFramework\Support\Arr;
|
||||
use Openguru\OpenCartFramework\Support\Utils;
|
||||
use Openguru\OpenCartFramework\Telegram\TelegramInitDataDecoder;
|
||||
use Openguru\OpenCartFramework\Telegram\TelegramService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
|
||||
class TeleCartPulseService
|
||||
{
|
||||
private TelegramInitDataDecoder $initDataDecoder;
|
||||
private PayloadSigner $payloadSigner;
|
||||
private TelegramService $telegramService;
|
||||
private CacheInterface $cache;
|
||||
private LoggerInterface $logger;
|
||||
private ?string $apiKey;
|
||||
private ?PayloadSigner $heartbeatPayloadSigner;
|
||||
private ?string $moduleVersion = null;
|
||||
|
||||
public function __construct(
|
||||
TelegramInitDataDecoder $initDataDecoder,
|
||||
PayloadSigner $payloadSigner,
|
||||
?string $apiKey = null
|
||||
TelegramService $telegramService,
|
||||
CacheInterface $cache,
|
||||
LoggerInterface $logger,
|
||||
?string $apiKey = null,
|
||||
?PayloadSigner $heartbeatPayloadSigner = null
|
||||
) {
|
||||
$this->initDataDecoder = $initDataDecoder;
|
||||
$this->payloadSigner = $payloadSigner;
|
||||
$this->telegramService = $telegramService;
|
||||
$this->cache = $cache;
|
||||
$this->logger = $logger;
|
||||
$this->apiKey = $apiKey;
|
||||
$this->heartbeatPayloadSigner = $heartbeatPayloadSigner;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,6 +84,65 @@ class TeleCartPulseService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function handleHeartbeat(): void
|
||||
{
|
||||
if ($this->cache->get('telecart_pulse_heartbeat')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->cache->set('telecart_pulse_heartbeat', time(), 3600);
|
||||
$me = $this->telegramService->getMe();
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->warning(
|
||||
'TeleCart Pulse heartbeat prerequisites failed: ' . $e->getMessage(),
|
||||
['exception' => $e]
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$botName = $me['username'] ?? 'unknown';
|
||||
|
||||
$moduleVersion = $this->getModuleVersion();
|
||||
|
||||
$payload = [
|
||||
'event' => 'HEARTBEAT',
|
||||
'meta' => [
|
||||
'domain' => Utils::getCurrentDomain(),
|
||||
'bot_name' => $botName,
|
||||
'php_version' => PHP_VERSION,
|
||||
'module_version' => $moduleVersion,
|
||||
'opencart_version' => defined('VERSION') ? VERSION : 'unknown',
|
||||
'opencart_version_core' => defined('VERSION_CORE') ? VERSION_CORE : 'unknown',
|
||||
],
|
||||
'timestamp' => Carbon::now('UTC')->toJSON(),
|
||||
];
|
||||
|
||||
if (! $this->heartbeatPayloadSigner) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$signature = $this->heartbeatPayloadSigner->sign($payload);
|
||||
} catch (PayloadSignException $exception) {
|
||||
$this->logger->warning(
|
||||
'TeleCart Pulse heartbeat signing failed: ' . $exception->getMessage(),
|
||||
['exception' => $exception]
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$dataToSend = [
|
||||
'payload' => $payload,
|
||||
'signature' => $signature,
|
||||
];
|
||||
|
||||
$this->pushHeartbeat($dataToSend);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws PayloadSignException
|
||||
* @throws GuzzleException
|
||||
@@ -109,13 +184,53 @@ class TeleCartPulseService
|
||||
'timeout' => env('PULSE_TIMEOUT', 5.0),
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer ' . $this->apiKey,
|
||||
'X-TELECART-VERSION' => '2.0.0',
|
||||
'X-TELECART-VERSION' => $this->getModuleVersion(),
|
||||
],
|
||||
]);
|
||||
|
||||
$client->post('events', compact('json'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
private function pushHeartbeat(array $json): void
|
||||
{
|
||||
$baseUri = rtrim(env('PULSE_API_HOST', 'http://localhost'), '/') . '/';
|
||||
|
||||
$client = new Client([
|
||||
'base_uri' => $baseUri,
|
||||
'timeout' => env('PULSE_TIMEOUT', 2.0),
|
||||
'headers' => [
|
||||
'X-TELECART-VERSION' => $this->getModuleVersion(),
|
||||
],
|
||||
]);
|
||||
|
||||
$client->post('heartbeat', compact('json'));
|
||||
}
|
||||
|
||||
private function getModuleVersion(): string
|
||||
{
|
||||
if ($this->moduleVersion !== null) {
|
||||
return $this->moduleVersion;
|
||||
}
|
||||
|
||||
$moduleVersion = 'unknown';
|
||||
$composerPath = __DIR__ . '/../../composer.json';
|
||||
|
||||
if (file_exists($composerPath)) {
|
||||
$composerRaw = @file_get_contents($composerPath);
|
||||
if ($composerRaw !== false) {
|
||||
$composer = json_decode($composerRaw, true);
|
||||
if (is_array($composer) && isset($composer['version'])) {
|
||||
$moduleVersion = (string)$composer['version'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->moduleVersion = $moduleVersion;
|
||||
}
|
||||
|
||||
private function handleOrderCreated(array $data, array $deserialized): void
|
||||
{
|
||||
if (isset($deserialized['campaign_id'], $deserialized['tracking_id'])) {
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
|
||||
namespace Openguru\OpenCartFramework\TeleCartPulse;
|
||||
|
||||
use Openguru\OpenCartFramework\Cache\CacheInterface;
|
||||
use Openguru\OpenCartFramework\Container\Container;
|
||||
use Openguru\OpenCartFramework\Container\ServiceProvider;
|
||||
use Openguru\OpenCartFramework\Telegram\TelegramInitDataDecoder;
|
||||
use Openguru\OpenCartFramework\Telegram\TelegramService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class TeleCartPulseServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -17,10 +20,17 @@ class TeleCartPulseServiceProvider extends ServiceProvider
|
||||
});
|
||||
|
||||
$this->container->singleton(TeleCartPulseService::class, function (Container $app) {
|
||||
$heartbeatSecret = $app->getConfigValue('pulse.heartbeat_secret') ?? env('PULSE_HEARTBEAT_SECRET');
|
||||
$heartbeatSigner = $heartbeatSecret ? new PayloadSigner($heartbeatSecret) : null;
|
||||
|
||||
return new TeleCartPulseService(
|
||||
$app->get(TelegramInitDataDecoder::class),
|
||||
$app->get(PayloadSigner::class),
|
||||
$app->get(TelegramService::class),
|
||||
$app->get(CacheInterface::class),
|
||||
$app->get(LoggerInterface::class),
|
||||
$app->getConfigValue('pulse.api_key'),
|
||||
$heartbeatSigner,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,14 +9,20 @@ use Openguru\OpenCartFramework\Http\Request;
|
||||
use Openguru\OpenCartFramework\Http\Response;
|
||||
use Openguru\OpenCartFramework\TeleCartPulse\PulseIngestException;
|
||||
use Openguru\OpenCartFramework\TeleCartPulse\TeleCartPulseService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
|
||||
class TelemetryHandler
|
||||
{
|
||||
private TeleCartPulseService $teleCartPulseService;
|
||||
private LoggerInterface $logger;
|
||||
|
||||
public function __construct(TeleCartPulseService $teleCartPulseService)
|
||||
{
|
||||
public function __construct(
|
||||
TeleCartPulseService $teleCartPulseService,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->teleCartPulseService = $teleCartPulseService;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,4 +34,15 @@ class TelemetryHandler
|
||||
|
||||
return new JsonResponse([], Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
public function heartbeat(): JsonResponse
|
||||
{
|
||||
try {
|
||||
$this->teleCartPulseService->handleHeartbeat();
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->warning('TeleCart Pulse Heartbeat failed: ' . $e->getMessage(), ['exception' => $e]);
|
||||
}
|
||||
|
||||
return new JsonResponse(['status' => 'ok']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ return [
|
||||
'getForm' => [FormsHandler::class, 'getForm'],
|
||||
'health' => [HealthCheckHandler::class, 'handle'],
|
||||
'ingest' => [TelemetryHandler::class, 'ingest'],
|
||||
'heartbeat' => [TelemetryHandler::class, 'heartbeat'],
|
||||
'manifest' => [SettingsHandler::class, 'manifest'],
|
||||
'processBlock' => [BlocksHandler::class, 'processBlock'],
|
||||
'product_show' => [ProductsHandler::class, 'show'],
|
||||
|
||||
Reference in New Issue
Block a user