Update car monitor asset reload and telemetry

This commit is contained in:
seo committed 2026-08-12 21:35:21 +09:00
1 parent 6f965f8f3e
commit 5d75ad81bd
8 files changed
+4334 -4366

No files matched your search

+66 -66
View File
@@ -44,37 +44,37 @@ if (($params['log'] ?? '') == '1') {
$cmdRequested = $params['cmd'] ?? 'se'; $cmdRequested = $params['cmd'] ?? 'se';
$cmd = normalize_cmd($cmdRequested); $cmd = normalize_cmd($cmdRequested);
if ($cmd === 'se') { if ($cmd === 'se') {
$latest = db_latest($pdo); $latest = db_latest($pdo);
if (!$latest) { if (!$latest) {
json_exit([ json_exit([
'request_id' => $requestId, 'request_id' => $requestId,
'error' => 'no_latest_data' 'error' => 'no_latest_data'
], 500); ], 500);
} }
$ageSeconds = max(0, time() - strtotime((string)$latest['ts'])); $ageSeconds = max(0, time() - strtotime((string)$latest['ts']));
$latestUsage = db_latest_usage($pdo); $latestUsage = db_latest_usage($pdo);
$staleReason = null; $staleReason = null;
if ($ageSeconds > 30 && $latestUsage && (int)$latestUsage['tcp_ok'] === 0) { if ($ageSeconds > 30 && $latestUsage && (int)$latestUsage['tcp_ok'] === 0) {
$staleReason = (string)($latestUsage['tcp_error'] ?? 'tcp_failed'); $staleReason = (string)($latestUsage['tcp_error'] ?? 'tcp_failed');
} }
json_exit([ json_exit([
'request_id' => $requestId, 'request_id' => $requestId,
'cmd_requested' => 'se', 'cmd_requested' => 'se',
'cmd' => $latest['cmd'], 'cmd' => $latest['cmd'],
'ts' => $latest['ts'], 'ts' => $latest['ts'],
'meta' => [ 'meta' => [
'age_seconds' => $ageSeconds, 'age_seconds' => $ageSeconds,
'stale' => $ageSeconds > 30, 'stale' => $ageSeconds > 30,
'stale_reason' => $staleReason, 'stale_reason' => $staleReason,
'latest_tcp' => $latestUsage, 'latest_tcp' => $latestUsage,
], ],
'raw_full' => $latest['raw_full'], 'raw_full' => $latest['raw_full'],
'raw_trim' => $latest['raw_trim'], 'raw_trim' => $latest['raw_trim'],
'data' => [ 'data' => [
'boundary' => (int)$latest['boundary'], 'boundary' => (int)$latest['boundary'],
@@ -110,26 +110,26 @@ if ($requestMethod !== 'POST') {
], 405); ], 405);
} }
$tcpMs = 0; $tcpMs = 0;
$connectMs = 0; $connectMs = 0;
$readMs = 0; $readMs = 0;
$tcpError = ''; $tcpError = '';
$trimError = ''; $trimError = '';
$sentBytes = 0; $sentBytes = 0;
$receivedBytes = 0; $receivedBytes = 0;
$rawFull = tcp_request( $rawFull = tcp_request(
$cmd, $cmd,
$tcpMs, $tcpMs,
$connectMs, $connectMs,
$readMs, $readMs,
$tcpError, $tcpError,
'api_control', 'api_control',
$requestId, $requestId,
$sentBytes, $sentBytes,
$receivedBytes $receivedBytes
); );
$execMs = (int)round((microtime(true) - $tsStart) * 1000); $execMs = (int)round((microtime(true) - $tsStart) * 1000);
if ($rawFull === '') { if ($rawFull === '') {
json_exit([ json_exit([
@@ -141,16 +141,16 @@ if ($rawFull === '') {
'client_ip' => $clientIp, 'client_ip' => $clientIp,
'ua' => $userAgent, 'ua' => $userAgent,
'tcp_ok' => 0, 'tcp_ok' => 0,
'tcp_ms' => $tcpMs, 'tcp_ms' => $tcpMs,
'connect_ms' => $connectMs, 'connect_ms' => $connectMs,
'read_ms' => $readMs, 'read_ms' => $readMs,
'sent_bytes' => $sentBytes, 'sent_bytes' => $sentBytes,
'received_bytes' => $receivedBytes, 'received_bytes' => $receivedBytes,
'total_bytes' => $sentBytes + $receivedBytes, 'total_bytes' => $sentBytes + $receivedBytes,
'tcp_error' => ($tcpError !== '' ? $tcpError : 'timeout_or_empty'), 'tcp_error' => ($tcpError !== '' ? $tcpError : 'timeout_or_empty'),
'error' => 'CONTROL_CMD_SEND_FAILED' 'error' => 'CONTROL_CMD_SEND_FAILED'
], 502); ], 502);
} }
$rawTrim = make_trim($rawFull, $trimError); $rawTrim = make_trim($rawFull, $trimError);
$data = ($rawTrim !== '') ? parse_trim($rawTrim) : null; $data = ($rawTrim !== '') ? parse_trim($rawTrim) : null;
@@ -174,16 +174,16 @@ json_exit([
'client_ip' => $clientIp, 'client_ip' => $clientIp,
'ua' => $userAgent, 'ua' => $userAgent,
'tcp_ok' => 1, 'tcp_ok' => 1,
'tcp_ms' => $tcpMs, 'tcp_ms' => $tcpMs,
'connect_ms' => $connectMs, 'connect_ms' => $connectMs,
'read_ms' => $readMs, 'read_ms' => $readMs,
'sent_bytes' => $sentBytes, 'sent_bytes' => $sentBytes,
'received_bytes' => $receivedBytes, 'received_bytes' => $receivedBytes,
'total_bytes' => $sentBytes + $receivedBytes, 'total_bytes' => $sentBytes + $receivedBytes,
'tcp_error' => $tcpError, 'tcp_error' => $tcpError,
'accepted' => true, 'accepted' => true,
'ack_only' => ($rawTrim === ''), 'ack_only' => ($rawTrim === ''),
'raw_full' => $rawFull, 'raw_full' => $rawFull,
'raw_trim' => $rawTrim, 'raw_trim' => $rawTrim,
'data' => $data 'data' => $data
]); ]);
+2 -3
View File
@@ -59,12 +59,11 @@ $assets = [];
foreach (collect_asset_files($root, $scanRoots) as $fullPath) { foreach (collect_asset_files($root, $scanRoots) as $fullPath) {
$relativePath = ltrim(str_replace($rootPath ?: $root, '', $fullPath), DIRECTORY_SEPARATOR); $relativePath = ltrim(str_replace($rootPath ?: $root, '', $fullPath), DIRECTORY_SEPARATOR);
$fileHash = is_readable($fullPath) ? (hash_file('sha256', $fullPath) ?: 'hash-failed') : 'unreadable'; $fileHash = is_readable($fullPath) ? (hash_file('sha256', $fullPath) ?: 'hash-failed') : 'unreadable';
$fileVersion = (string)filemtime($fullPath) . '-' . substr($fileHash, 0, 10); $fileVersion = substr($fileHash, 0, 16);
$publicPath = '/car/' . str_replace(DIRECTORY_SEPARATOR, '/', $relativePath); $publicPath = '/custom/car/' . str_replace(DIRECTORY_SEPARATOR, '/', $relativePath);
$fingerprints[] = implode('|', [ $fingerprints[] = implode('|', [
ltrim($publicPath, '/'), ltrim($publicPath, '/'),
(string)filesize($fullPath), (string)filesize($fullPath),
(string)filemtime($fullPath),
$fileHash, $fileHash,
]); ]);
$assets[$publicPath] = $fileVersion; $assets[$publicPath] = $fileVersion;
+9 -6
View File
@@ -214,20 +214,23 @@
}).then(function (data) { }).then(function (data) {
if (!data || data.result !== 'ok' || !data.version) return; if (!data || data.result !== 'ok' || !data.version) return;
var token = data.version.slice(0, 12);
var previous = storeGet(storageKey); var previous = storeGet(storageKey);
var mismatch = loadedAssetMismatch(data.assets); var versionChanged = previous && previous !== data.version;
var forceReload = bfcacheReturn; var latestToken = String(data.version).slice(0, 12);
var hasLatestToken = assetTokenFromLocation() === latestToken;
var mismatch = !hasLatestToken && loadedAssetMismatch(data.assets);
var wasBfcacheReturn = bfcacheReturn;
bfcacheReturn = false; bfcacheReturn = false;
storeSet(storageKey, data.version); storeSet(storageKey, data.version);
if (assetTokenFromLocation() !== token || mismatch || forceReload) { if ((mismatch || wasBfcacheReturn) && !hasLatestToken) {
reloadWith(data.version, mismatch || forceReload); reloadWith(data.version, true);
return; return;
} }
if (previous && previous !== data.version) { if (versionChanged) {
reloadWith(data.version, false); reloadWith(data.version, false);
return;
} }
}).then(function () { }).then(function () {
running = false; running = false;
+4 -4
View File
@@ -2,21 +2,21 @@
"name": "Car Monitor", "name": "Car Monitor",
"short_name": "Car Monitor", "short_name": "Car Monitor",
"description": "Vehicle status monitor", "description": "Vehicle status monitor",
"start_url": "/car/monitor.php?pwa=1", "start_url": "/custom/car/monitor.php?pwa=1",
"scope": "/car/", "scope": "/custom/car/",
"display": "standalone", "display": "standalone",
"orientation": "portrait", "orientation": "portrait",
"background_color": "#0f172a", "background_color": "#0f172a",
"theme_color": "#0f172a", "theme_color": "#0f172a",
"icons": [ "icons": [
{ {
"src": "/car/assets/icon-192.png", "src": "/custom/car/assets/icon-192.png",
"sizes": "192x192", "sizes": "192x192",
"type": "image/png", "type": "image/png",
"purpose": "any maskable" "purpose": "any maskable"
}, },
{ {
"src": "/car/assets/icon-512.png", "src": "/custom/car/assets/icon-512.png",
"sizes": "512x512", "sizes": "512x512",
"type": "image/png", "type": "image/png",
"purpose": "any maskable" "purpose": "any maskable"
+14 -14
View File
@@ -62,19 +62,19 @@ function collect_once(): bool
$tcpError = ''; $tcpError = '';
$trimError = ''; $trimError = '';
$sentBytes = 0; $sentBytes = 0;
$receivedBytes = 0; $receivedBytes = 0;
$rawFull = tcp_request( $rawFull = tcp_request(
'se', 'se',
$tcpMs, $tcpMs,
$connectMs, $connectMs,
$readMs, $readMs,
$tcpError, $tcpError,
'collector_se', 'collector_se',
null, null,
$sentBytes, $sentBytes,
$receivedBytes $receivedBytes
); );
if ($rawFull === '') { if ($rawFull === '') {
return false; return false;
} }
@@ -105,4 +105,4 @@ if (!is_fast_poll_state() && should_skip_non_driving()) {
} }
mark_attempt(); mark_attempt();
collect_once(); collect_once();
+750 -680
View File
File diff suppressed because it is too large. Load diff
+3452 -3556
View File
File diff suppressed because it is too large. Load diff
+37 -37
View File
@@ -1,44 +1,44 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
require __DIR__ . '/common.php'; require __DIR__ . '/common.php';
const WORKER_IDLE_SLEEP_USEC = 200000; const WORKER_IDLE_SLEEP_USEC = 200000;
if (PHP_SAPI !== 'cli') { if (PHP_SAPI !== 'cli') {
fwrite(STDERR, "tcp_worker.php must run from CLI\n"); fwrite(STDERR, "tcp_worker.php must run from CLI\n");
exit(1); exit(1);
} }
$lockFp = fopen('/tmp/car_tcp_worker.lock', 'c'); $lockFp = fopen('/tmp/car_tcp_worker.lock', 'c');
if ($lockFp === false) { if ($lockFp === false) {
fwrite(STDERR, "failed to open worker lock\n"); fwrite(STDERR, "failed to open worker lock\n");
exit(1); exit(1);
} }
if (!flock($lockFp, LOCK_EX | LOCK_NB)) { if (!flock($lockFp, LOCK_EX | LOCK_NB)) {
fwrite(STDERR, "worker already running\n"); fwrite(STDERR, "worker already running\n");
exit(0); exit(0);
} }
register_shutdown_function(static function () use ($lockFp): void { register_shutdown_function(static function () use ($lockFp): void {
@flock($lockFp, LOCK_UN); @flock($lockFp, LOCK_UN);
@fclose($lockFp); @fclose($lockFp);
}); });
db_ensure_tcp_queue_schema(db()); db_ensure_tcp_queue_schema(db(true));
while (true) { while (true) {
try { try {
$job = tcp_queue_claim_next(db()); $job = tcp_queue_claim_next(db(true));
if (!$job) { if (!$job) {
usleep(WORKER_IDLE_SLEEP_USEC); usleep(WORKER_IDLE_SLEEP_USEC);
continue; continue;
} }
tcp_worker_process_job($job); tcp_worker_process_job($job);
} catch (Throwable $e) { } catch (Throwable $e) {
fwrite(STDERR, date('c') . ' ' . $e->getMessage() . "\n"); fwrite(STDERR, date('c') . ' ' . $e->getMessage() . "\n");
usleep(1000000); usleep(1000000);
} }
} }