312 lines
11 KiB
PHP
312 lines
11 KiB
PHP
<?php
|
|
|
|
namespace Paymenter\Extensions\Others\UptimeLab\Services;
|
|
|
|
use Paymenter\Extensions\Others\UptimeLab\Models\UptimeServer;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class UptimeMonitoringService
|
|
{
|
|
/**
|
|
* Check the status of a server
|
|
*/
|
|
public function checkServerStatus(UptimeServer $server): array
|
|
{
|
|
$startTime = microtime(true);
|
|
$isOnline = false;
|
|
$responseTime = null;
|
|
|
|
try {
|
|
if ($server->server_type === 'ip') {
|
|
$result = $this->pingServer($server->ip_address);
|
|
$isOnline = $result['online'];
|
|
$responseTime = $result['response_time'];
|
|
} else {
|
|
// For subdomains, try HTTP first, then fallback to ping if HTTP fails
|
|
$result = $this->httpCheck($server->ip_address);
|
|
$isOnline = $result['online'];
|
|
$responseTime = $result['response_time'];
|
|
|
|
// If HTTP fails, try ping as fallback for subdomains
|
|
if (!$isOnline) {
|
|
Log::info('HTTP check failed for subdomain, trying ping as fallback: ' . $server->ip_address);
|
|
$pingResult = $this->pingServer($server->ip_address);
|
|
if ($pingResult['online']) {
|
|
$isOnline = true;
|
|
$responseTime = $pingResult['response_time'];
|
|
Log::info('Ping fallback successful for subdomain: ' . $server->ip_address);
|
|
}
|
|
}
|
|
}
|
|
|
|
$endTime = microtime(true);
|
|
$totalTime = round(($endTime - $startTime) * 1000, 2);
|
|
|
|
return [
|
|
'online' => $isOnline,
|
|
'response_time' => $responseTime,
|
|
'check_time' => $totalTime,
|
|
];
|
|
} catch (\Exception $e) {
|
|
Log::error('Uptime check failed for server: ' . $server->name, [
|
|
'error' => $e->getMessage(),
|
|
'server_id' => $server->id,
|
|
'server_type' => $server->server_type,
|
|
'ip_address' => $server->ip_address,
|
|
]);
|
|
|
|
return [
|
|
'online' => false,
|
|
'response_time' => null,
|
|
'check_time' => null,
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ping an IP address or domain
|
|
*/
|
|
private function pingServer(string $ip): array
|
|
{
|
|
$command = "ping -c 1 -W 5 " . escapeshellarg($ip) . " 2>&1";
|
|
$output = shell_exec($command);
|
|
|
|
if (preg_match('/time=(\d+\.?\d*)\s*ms/', $output, $matches)) {
|
|
return [
|
|
'online' => true,
|
|
'response_time' => (int) $matches[1],
|
|
];
|
|
}
|
|
|
|
return [
|
|
'online' => false,
|
|
'response_time' => null,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Check HTTP response for subdomains
|
|
*/
|
|
private function httpCheck(string $domain): array
|
|
{
|
|
try {
|
|
// Remove any protocol prefix if present
|
|
$cleanDomain = preg_replace('/^https?:\/\//', '', $domain);
|
|
|
|
// Try HTTP first
|
|
$response = Http::timeout(10)
|
|
->withHeaders([
|
|
'User-Agent' => 'Paymenter-UptimeLab/1.0',
|
|
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
])
|
|
->get('http://' . $cleanDomain);
|
|
|
|
if ($response->successful()) {
|
|
$responseTime = $this->calculateResponseTime($response);
|
|
return [
|
|
'online' => true,
|
|
'response_time' => $responseTime,
|
|
];
|
|
}
|
|
|
|
// If HTTP fails, try HTTPS
|
|
$httpsResponse = Http::timeout(10)
|
|
->withHeaders([
|
|
'User-Agent' => 'Paymenter-UptimeLab/1.0',
|
|
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
])
|
|
->get('https://' . $cleanDomain);
|
|
|
|
if ($httpsResponse->successful()) {
|
|
$responseTime = $this->calculateResponseTime($httpsResponse);
|
|
return [
|
|
'online' => true,
|
|
'response_time' => $responseTime,
|
|
];
|
|
}
|
|
|
|
// If both HTTP and HTTPS fail, check if domain resolves
|
|
if (gethostbyname($cleanDomain) !== $cleanDomain) {
|
|
// Domain resolves but HTTP/HTTPS failed
|
|
return [
|
|
'online' => false,
|
|
'response_time' => null,
|
|
];
|
|
}
|
|
|
|
// Domain doesn't resolve
|
|
return [
|
|
'online' => false,
|
|
'response_time' => null,
|
|
];
|
|
|
|
} catch (\Exception $e) {
|
|
Log::warning('HTTP check failed for domain: ' . $domain, [
|
|
'error' => $e->getMessage(),
|
|
'domain' => $domain,
|
|
]);
|
|
|
|
// Try DNS resolution as fallback
|
|
if (gethostbyname($cleanDomain) !== $cleanDomain) {
|
|
return [
|
|
'online' => false, // Domain resolves but HTTP failed
|
|
'response_time' => null,
|
|
];
|
|
}
|
|
|
|
return [
|
|
'online' => false,
|
|
'response_time' => null,
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculate response time from HTTP response
|
|
*/
|
|
private function calculateResponseTime($response): ?int
|
|
{
|
|
try {
|
|
// Try to get response time from handler stats
|
|
if (method_exists($response, 'handlerStats')) {
|
|
$stats = $response->handlerStats();
|
|
if (isset($stats['total_time_us'])) {
|
|
return (int) ($stats['total_time_us'] / 1000); // Convert to milliseconds
|
|
}
|
|
}
|
|
|
|
// Fallback: estimate response time based on current time
|
|
return null;
|
|
} catch (\Exception $e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update server status
|
|
*/
|
|
public function updateServerStatus(UptimeServer $server, array $checkResult): void
|
|
{
|
|
$wasOnline = $server->status === 'online';
|
|
$isOnline = $checkResult['online'];
|
|
|
|
$server->update([
|
|
'status' => $isOnline ? 'online' : 'offline',
|
|
'last_check' => now(),
|
|
'response_time' => $checkResult['response_time'],
|
|
]);
|
|
|
|
// Update last online/offline timestamps
|
|
if ($isOnline && !$wasOnline) {
|
|
$server->update(['last_online' => now()]);
|
|
} elseif (!$isOnline && $wasOnline) {
|
|
$server->update(['last_offline' => now()]);
|
|
}
|
|
|
|
// Calculate uptime percentage (simplified calculation)
|
|
$this->calculateUptimePercentage($server);
|
|
}
|
|
|
|
/**
|
|
* Calculate uptime percentage
|
|
*/
|
|
private function calculateUptimePercentage(UptimeServer $server): void
|
|
{
|
|
// Calculate uptime based on server status and monitoring history
|
|
$now = now();
|
|
$uptimePercentage = 0;
|
|
|
|
if ($server->status === 'online') {
|
|
// Server is currently online
|
|
if ($server->last_offline) {
|
|
// Server has been offline before, calculate based on recent performance
|
|
$lastOfflineTime = $server->last_offline;
|
|
$timeSinceOffline = $now->diffInHours($lastOfflineTime);
|
|
|
|
if ($timeSinceOffline > 24) {
|
|
// If server has been online for more than 24 hours, give high uptime
|
|
$uptimePercentage = 99.5;
|
|
} elseif ($timeSinceOffline > 12) {
|
|
// If server has been online for more than 12 hours
|
|
$uptimePercentage = 98.0;
|
|
} elseif ($timeSinceOffline > 6) {
|
|
// If server has been online for more than 6 hours
|
|
$uptimePercentage = 96.0;
|
|
} elseif ($timeSinceOffline > 1) {
|
|
// If server has been online for more than 1 hour
|
|
$uptimePercentage = 92.0;
|
|
} else {
|
|
// Server just came back online
|
|
$uptimePercentage = 85.0;
|
|
}
|
|
} else {
|
|
// Server has never been offline (new server or always online)
|
|
$uptimePercentage = 99.9;
|
|
}
|
|
} else {
|
|
// Server is currently offline
|
|
if ($server->last_online) {
|
|
// Server was online before, calculate based on downtime
|
|
$lastOnlineTime = $server->last_online;
|
|
$timeSinceOnline = $now->diffInHours($lastOnlineTime);
|
|
|
|
if ($timeSinceOnline < 1) {
|
|
// Server just went offline
|
|
$uptimePercentage = 95.0;
|
|
} elseif ($timeSinceOnline < 6) {
|
|
// Server has been offline for a few hours
|
|
$uptimePercentage = 85.0;
|
|
} elseif ($timeSinceOnline < 24) {
|
|
// Server has been offline for a day
|
|
$uptimePercentage = 70.0;
|
|
} else {
|
|
// Server has been offline for a long time
|
|
$uptimePercentage = 50.0;
|
|
}
|
|
} else {
|
|
// Server has never been online
|
|
$uptimePercentage = 0.0;
|
|
}
|
|
}
|
|
|
|
// Ensure percentage is between 0 and 100
|
|
$uptimePercentage = max(0, min(100, $uptimePercentage));
|
|
|
|
$server->update([
|
|
'uptime_percentage' => round($uptimePercentage, 2),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Check all active servers
|
|
*/
|
|
public function checkAllServers(): void
|
|
{
|
|
$servers = UptimeServer::where('is_active', true)->get();
|
|
|
|
foreach ($servers as $server) {
|
|
try {
|
|
$checkResult = $this->checkServerStatus($server);
|
|
$this->updateServerStatus($server, $checkResult);
|
|
|
|
Log::info('Server status checked', [
|
|
'server' => $server->name,
|
|
'status' => $checkResult['online'] ? 'online' : 'offline',
|
|
'response_time' => $checkResult['response_time'],
|
|
'server_type' => $server->server_type,
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
Log::error('Failed to check server: ' . $server->name, [
|
|
'error' => $e->getMessage(),
|
|
'server_id' => $server->id,
|
|
]);
|
|
}
|
|
|
|
// Add a small delay between checks to avoid overwhelming the system
|
|
usleep(200000); // 0.1 second delay
|
|
}
|
|
}
|
|
}
|