Files
html/api/multi-server-dispatch.php

144 lines
4.9 KiB
PHP

<?php
/**
* /api/multi-server-dispatch.php — Doctrine 314 Multi-Server Dispatcher
*
* Déchargement S204 → S95+S151+GPUs+sovereign:4000
*
* Usage:
* POST {"task": "command_name", "params": {...}, "prefer": "auto|s95|s151|sovereign|local"}
*
* Strategy:
* 1. Check load S204 if > 20 → délègue ailleurs
* 2. Match task type → server le mieux adapté
* 3. Fallback chain : sovereign:4000 → S95 sentinel → S151 OVH → S204 local
*
* Created by Opus 25avr - response Yacine "doctrine 314 seul gap structurel"
*/
header('Content-Type: application/json');
header('Cache-Control: no-store');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['error' => 'POST required', 'usage' => 'POST {"task":"NAME","prefer":"auto|s95|s151|sovereign|local"}']);
exit;
}
$body = json_decode(file_get_contents('php://input'), true);
$task = $body['task'] ?? '';
$params = $body['params'] ?? [];
$prefer = $body['prefer'] ?? 'auto';
if (!$task) {
echo json_encode(['error' => 'missing task']);
exit;
}
// === LOAD CHECK ===
$load_str = trim(@file_get_contents('/proc/loadavg'));
$load_1m = (float) explode(' ', $load_str)[0];
$disk_pct = 0;
$df_out = @shell_exec('df / | tail -1');
if ($df_out && preg_match('/(\d+)%/', $df_out, $m)) $disk_pct = (int) $m[1];
// === ROUTING DECISION ===
$worker = 'local'; // default S204
$reason = 'low load';
if ($prefer !== 'auto') {
$worker = $prefer;
$reason = 'user prefer';
} elseif ($load_1m > 20 || $disk_pct > 92) {
// Decharge S204
$task_lower = strtolower($task);
// LLM tasks → sovereign
if (preg_match('/(llm|chat|complete|generate|cerebras|groq|mistral|gemini)/', $task_lower)) {
$worker = 'sovereign';
$reason = "load $load_1m + LLM task";
}
// Browser/Playwright → S95 (browser farm)
elseif (preg_match('/(playwright|browser|screenshot|chrome|video|selenium)/', $task_lower)) {
$worker = 's95';
$reason = "load $load_1m + browser task";
}
// Tracking/email → S151
elseif (preg_match('/(track|email|open|click|pmta)/', $task_lower)) {
$worker = 's151';
$reason = "load $load_1m + tracking task";
}
// Generic heavy → sovereign first
else {
$worker = 'sovereign';
$reason = "load $load_1m + generic offload";
}
}
// === DISPATCH ===
$result = ['task' => $task, 'worker' => $worker, 'reason' => $reason, 'load_1m' => $load_1m, 'disk_pct' => $disk_pct, 'ts' => date('c')];
$start = microtime(true);
try {
switch ($worker) {
case 'sovereign':
// Sovereign API local port 4000
$ch = curl_init('http://localhost:4000/' . $task);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($params),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
]);
$r = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$result['response'] = $r;
$result['http'] = $http;
$result['source'] = 'sovereign:4000';
break;
case 's95':
// S95 sentinel-brain proxy
$ch = curl_init('https://wevads.weval-consulting.com/api/sentinel-brain.php');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query(['action' => 'exec', 'cmd' => $task]),
CURLOPT_SSL_VERIFYPEER => false,
]);
$r = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$result['response'] = $r;
$result['http'] = $http;
$result['source'] = 'S95 sentinel-brain';
break;
case 's151':
// S151 OVH (limited - just ping check for now)
$ping = @shell_exec('ping -c 1 -W 2 151.80.235.110 2>&1 | tail -1');
$result['response'] = trim($ping);
$result['source'] = 'S151 OVH ping';
$result['note'] = 'S151 dispatch handler not implemented yet (only health ping for now)';
break;
case 'local':
default:
// Fallback : execute on S204 local
$cmd = "timeout 25 bash -c " . escapeshellarg($task) . " 2>&1";
$r = @shell_exec($cmd);
$result['response'] = trim($r ?: '');
$result['source'] = 'S204 local';
break;
}
$result['elapsed_s'] = round(microtime(true) - $start, 3);
$result['ok'] = true;
} catch (Exception $e) {
$result['ok'] = false;
$result['error'] = $e->getMessage();
}
echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);