Files
jarvis/api/endpoints/arc.php
T
myron 7013a80428 feat: Phase 1 — Arc Reactor Core Daemon
- Python asyncio daemon (/opt/jarvis-arc/reactor.py) running on 127.0.0.1:7474
- systemd service (jarvis-arc) auto-starts with MySQL dependency
- arc_jobs + arc_status MySQL tables for async job queue
- api/endpoints/arc.php: PHP bridge to daemon (status, job_create, job_get, jobs, purge)
- api.php: added arc route
- index.html: ARC REACTOR status indicator in bottom bar with live polling
- admin/index.php: ARC REACTOR nav section + full job management panel
- Built-in job handlers: ping, echo, shell (whitelist-gated)
- Foundation for Phase 2 (Intel Protocol) and beyond

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 04:07:28 +00:00

109 lines
3.9 KiB
PHP

<?php
/**
* JARVIS Arc Reactor Bridge
* Proxies job requests to the Arc Reactor daemon at 127.0.0.1:7474
*/
define('ARC_REACTOR_URL', 'http://127.0.0.1:7474');
define('ARC_TIMEOUT', 8);
function arc_request(string $method, string $path, array $body = []): array {
$url = ARC_REACTOR_URL . $path;
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => ARC_TIMEOUT,
CURLOPT_CONNECTTIMEOUT => 3,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
]);
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
} elseif ($method === 'DELETE') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
}
$raw = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$err = curl_error($ch);
curl_close($ch);
if ($err || $raw === false) {
return ['error' => 'Arc Reactor unreachable: ' . $err, 'online' => false];
}
$decoded = json_decode($raw, true);
return $decoded ?? ['error' => 'Invalid response from Arc Reactor', 'raw' => substr($raw, 0, 200)];
}
// ── ROUTING ───────────────────────────────────────────────────────────────────
// arc action comes from query string or POST body (not the URL path segment)
global $data;
$action = $_GET['action'] ?? $data['action'] ?? '';
switch ($action) {
// GET /api/arc?action=status
case 'status':
$result = arc_request('GET', '/status');
if (!isset($result['online'])) $result['online'] = false;
echo json_encode($result);
break;
// POST /api/arc — create a job
// body: { action: "job_create", type: "ping", payload: {}, priority: 5 }
case 'job_create':
$type = $data['type'] ?? '';
$payload = $data['payload'] ?? [];
$priority = (int)($data['priority'] ?? 5);
if (!$type) { http_response_code(400); echo json_encode(['error' => 'Missing job type']); break; }
$result = arc_request('POST', '/job', [
'type' => $type,
'payload' => $payload,
'priority' => $priority,
'created_by' => 'jarvis_ui',
]);
echo json_encode($result);
break;
// GET /api/arc?action=job_get&id=123
case 'job_get':
$id = (int)($data['id'] ?? $_GET['id'] ?? 0);
if (!$id) { http_response_code(400); echo json_encode(['error' => 'Missing job id']); break; }
echo json_encode(arc_request('GET', "/job/{$id}"));
break;
// GET /api/arc?action=jobs&status=done&limit=20
case 'jobs':
$status = $_GET['status'] ?? $data['status'] ?? '';
$limit = (int)($_GET['limit'] ?? $data['limit'] ?? 50);
$qs = http_build_query(array_filter(['status' => $status, 'limit' => $limit]));
echo json_encode(arc_request('GET', '/jobs' . ($qs ? "?{$qs}" : '')));
break;
// DELETE /api/arc?action=job_cancel&id=123
case 'job_cancel':
$id = (int)($data['id'] ?? $_GET['id'] ?? 0);
if (!$id) { http_response_code(400); echo json_encode(['error' => 'Missing job id']); break; }
echo json_encode(arc_request('DELETE', "/job/{$id}"));
break;
// DELETE /api/arc?action=purge
case 'purge':
echo json_encode(arc_request('DELETE', '/jobs/purge'));
break;
// Quick ping test
case 'ping':
$result = arc_request('POST', '/job', [
'type' => 'ping',
'payload' => [],
'priority' => 9,
'created_by' => 'jarvis_ping',
]);
echo json_encode($result);
break;
default:
http_response_code(404);
echo json_encode(['error' => "Unknown arc action: {$action}"]);
}