0 && count($lines) < $maxLines) { $readSize = min($pos, 4096); $pos -= $readSize; fseek($fp, $pos); $chunk = fread($fp, $readSize); $buffer = $chunk . $buffer; $chunkLines = explode("\n", $buffer); $buffer = array_shift($chunkLines); while (!empty($chunkLines)) { $line = array_pop($chunkLines); if (trim($line) !== "") { array_unshift($lines, trim($line)); if (count($lines) >= $maxLines) break; } } } fclose($fp); return $lines; } // Logic for signaling $action = $_REQUEST["action"] ?? ""; $room = room_id($_REQUEST["room"] ?? "secours"); $my_id = $_REQUEST["peer_id"] ?? ""; if ($action === "join") { $name = $_REQUEST["name"] ?? "User"; $p_file = room_participants_file($room); $ps = read_json_file($p_file); // Cleanup old participants (> 10s) $stale_time = now_ms() - 10000; foreach ($ps as $id => $p) { if (($p["last_seen"] ?? 0) < $stale_time) unset($ps[$id]); } $new_id = peer_id(); $ps[$new_id] = [ "id" => $new_id, "user_id" => $current_user_id, "name" => $name, "avatar_url" => $user["avatar_url"] ?? "", "last_seen" => now_ms() ]; write_json_file($p_file, $ps); // DB Integration for sidebar if ($current_user_id > 0) { try { $stmt = db()->prepare("INSERT INTO voice_sessions (user_id, channel_id, last_seen) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE channel_id = ?, last_seen = ?"); $stmt->execute([$current_user_id, $room, now_ms(), $room, now_ms()]); } catch (Exception $e) {} } json_out(["success" => true, "peer_id" => $new_id, "participants" => $ps]); } if ($action === "poll") { if (!$my_id) json_out(["error" => "Missing peer_id"], 400); $p_file = room_participants_file($room); $ps = read_json_file($p_file); if (isset($ps[$my_id])) { $ps[$my_id]["last_seen"] = now_ms(); } $stale_time = now_ms() - 10000; foreach ($ps as $id => $p) { if (($p["last_seen"] ?? 0) < $stale_time) unset($ps[$id]); } write_json_file($p_file, $ps); // Update DB last_seen if ($current_user_id > 0) { try { $stmt = db()->prepare("UPDATE voice_sessions SET last_seen = ? WHERE user_id = ?"); $stmt->execute([now_ms(), $current_user_id]); } catch (Exception $e) {} } // Read signals $log_file = room_log_file($room); $signals = []; if (file_exists($log_file)) { $lines = file($log_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); $remaining = []; $now = now_ms(); foreach ($lines as $line) { $sig = json_decode($line, true); if ($sig && isset($sig["to"]) && $sig["to"] === $my_id) { $signals[] = $sig; } elseif ($sig && ($now - ($sig["time"] ?? 0) < 30000)) { $remaining[] = $line; } } file_put_contents($log_file, implode("\n", $remaining) . (empty($remaining) ? "" : "\n"), LOCK_EX); } json_out(["success" => true, "participants" => $ps, "signals" => $signals]); } if ($action === "signal") { if (!$my_id) json_out(["error" => "Missing peer_id"], 400); $to = $_REQUEST["to"] ?? ""; $data = $_REQUEST["data"] ?? ""; if (!$to || !$data) json_out(["error" => "Missing to/data"], 400); $sig = [ "from" => $my_id, "to" => $to, "data" => json_decode($data, true), "time" => now_ms() ]; file_put_contents(room_log_file($room), json_encode($sig) . "\n", FILE_APPEND | LOCK_EX); json_out(["success" => true]); } if ($action === "list_all") { // Periodic cleanup of the DB table (stale sessions > 15s) if (rand(1, 10) === 1) { try { $stale_db_time = now_ms() - 15000; $stmt = db()->prepare("DELETE FROM voice_sessions WHERE last_seen < ?"); $stmt->execute([$stale_db_time]); } catch (Exception $e) {} } try { $stmt = db()->prepare(" SELECT vs.channel_id, vs.user_id, u.username, u.display_name, u.avatar_url FROM voice_sessions vs JOIN users u ON vs.user_id = u.id WHERE vs.last_seen > ? "); $stale_db_time = now_ms() - 15000; $stmt->execute([$stale_db_time]); $sessions = $stmt->fetchAll(PDO::FETCH_ASSOC); $by_channel = []; foreach ($sessions as $s) { $by_channel[$s['channel_id']][] = $s; } json_out(["success" => true, "channels" => $by_channel]); } catch (Exception $e) { json_out(["error" => $e->getMessage()], 500); } } if ($action === "leave") { if ($my_id) { $p_file = room_participants_file($room); $ps = read_json_file($p_file); unset($ps[$my_id]); write_json_file($p_file, $ps); } if ($current_user_id > 0) { try { $stmt = db()->prepare("DELETE FROM voice_sessions WHERE user_id = ?"); $stmt->execute([$current_user_id]); } catch (Exception $e) {} } json_out(["success" => true]); } json_out(["error" => "Unknown action"], 404);