Initial commit - Pingerino network monitoring application

هذا الالتزام موجود في:
Era
2025-08-19 07:34:27 +03:00
التزام 243f4787dd
41 ملفات معدلة مع 12352 إضافات و0 حذوفات

808
FormPinger.cs Normal file
عرض الملف

@@ -0,0 +1,808 @@
using System;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Pingerino.Infrastructure;
using Pingerino.Services.Interfaces;
using Pingerino.Utilities;
namespace Pingerino
{
public partial class FormPinger : Form
{
#region Services
private readonly IPingService _pingService;
private readonly INetworkService _networkService;
private readonly IConfigurationService _configService;
private readonly ISystemService _systemService;
private readonly ILoggingService _logger;
#endregion
#region Fields
private CancellationTokenSource _cancellationTokenSource;
private System.Threading.Timer _publicIpTimer;
private string _currentPublicIp = "Loading...";
private bool _disposed;
#endregion
#region Constructor
public FormPinger()
{
InitializeComponent();
// Get services from container
_pingService = ServiceContainer.Instance.GetService<IPingService>();
_networkService = ServiceContainer.Instance.GetService<INetworkService>();
_configService = ServiceContainer.Instance.GetService<IConfigurationService>();
_systemService = ServiceContainer.Instance.GetService<ISystemService>();
_logger = ServiceContainer.Instance.GetService<ILoggingService>();
InitializeFormAsync();
}
#endregion
#region Initialization
private async void InitializeFormAsync()
{
try
{
_logger.LogInformation("Initializing Pingerino application");
// Setup UI
SetupUI();
// Load configuration
LoadConfiguration();
// Setup event handlers
SetupEventHandlers();
// Initialize services
await InitializeServicesAsync();
_logger.LogInformation("Application initialized successfully");
}
catch (Exception ex)
{
_logger.LogError("Error during application initialization", ex);
UIHelper.ShowError($"Failed to initialize application: {ex.Message}");
}
}
private void SetupUI()
{
// Apply rounded corners
UIHelper.ApplyRoundedCorners(this);
// Enable form dragging
UIHelper.EnableFormDragging(this, panel1);
// Enable double buffering
this.DoubleBuffered = true;
// Initialize context menu
InitializeContextMenu();
// Set default values
textBoxInterval.Text = "300";
ipAddress.Select();
}
private void LoadConfiguration()
{
try
{
// Load form position
var savedPosition = _configService.FormPosition;
if (savedPosition != Point.Empty)
{
this.Location = savedPosition;
}
// Load IP address and interval
ipAddress.Text = _configService.IpAddressValue;
textBoxInterval.Text = _configService.TextBoxIntervalValue;
_logger.LogInformation("Configuration loaded successfully");
}
catch (Exception ex)
{
_logger.LogError("Error loading configuration", ex);
}
}
private void SetupEventHandlers()
{
// Form events
this.Load += FormPinger_Load;
this.FormClosing += FormPinger_FormClosing;
// Input events
textBoxInterval.KeyDown += TextBoxInterval_KeyDown;
ipAddress.KeyDown += TextBoxIpAddress_KeyDown;
// Button events are handled by Designer file - no manual registration needed
// Service events
_pingService.PingCompleted += PingService_PingCompleted;
_pingService.StatisticsUpdated += PingService_StatisticsUpdated;
}
private async System.Threading.Tasks.Task InitializeServicesAsync()
{
// Start public IP fetching
await StartPublicIpUpdatesAsync();
// Start initial ping if auto-ping is enabled
if (_configService.AutoPingEnabled)
{
await StartPingingAsync();
}
}
#endregion
#region Event Handlers
private async void FormPinger_Load(object sender, EventArgs e)
{
await UpdateNetworkStatisticsAsync();
}
private async void FormPinger_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
// Save configuration
_configService.FormPosition = this.Location;
_configService.IpAddressValue = ipAddress.Text;
_configService.TextBoxIntervalValue = textBoxInterval.Text;
_configService.Save();
// Stop services
await _pingService.StopPingingAsync();
_publicIpTimer?.Dispose();
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
_logger.LogInformation("Application closing - configuration saved");
}
catch (Exception ex)
{
_logger.LogError("Error during application shutdown", ex);
}
}
private async void TextBoxInterval_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
await HandleIntervalChangeAsync();
}
}
private async void TextBoxIpAddress_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
await HandleIpAddressChangeAsync();
}
}
private void ButtonExit_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void ButtonMinimize_Click(object sender, EventArgs e)
{
WindowState = FormWindowState.Minimized;
}
private async void ButtonClearAll_Click(object sender, EventArgs e)
{
await ClearAllDataAsync();
}
private async void ButtonCleanNetwork_Click(object sender, EventArgs e)
{
await ResetNetworkAsync();
}
private async void ButtonCleanTemp_Click(object sender, EventArgs e)
{
await CleanTemporaryFilesAsync();
}
private void ButtonNetworkAdapters_Click(object sender, EventArgs e)
{
_systemService.OpenNetworkAdaptersControl();
}
private void ButtonMenu_Click(object sender, EventArgs e)
{
contextMenuStrip1.Show(ButtonMenu, 0, ButtonMenu.Height);
}
// Additional event handlers referenced by Designer
private void COPYRIGHT_TextChanged(object sender, EventArgs e)
{
// Copyright text changed - no action needed
}
private void TextBoxInterval_TextChanged(object sender, EventArgs e)
{
// Interval text changed - we handle this with KeyDown events instead
}
private void TextBoxJitter_TextChanged(object sender, EventArgs e)
{
// Jitter display text changed - no action needed (read-only display)
}
private void Label1_Click(object sender, EventArgs e)
{
// Label click - no action needed
}
private void LabelJitter_Click(object sender, EventArgs e)
{
// Jitter label click - no action needed
}
private void IpAddress_Click(object sender, EventArgs e)
{
// IP address control click - no action needed
}
private void Label2_Click(object sender, EventArgs e)
{
// Label click - no action needed
}
private void Panel1_MouseDown(object sender, MouseEventArgs e)
{
// Panel mouse down - form dragging is handled by UIHelper.EnableFormDragging
}
private void Label3_MouseDown(object sender, MouseEventArgs e)
{
// Label mouse down - form dragging is handled by UIHelper.EnableFormDragging
}
private void TextBoxMinJitter_TextChanged(object sender, EventArgs e)
{
// Min jitter display text changed - no action needed (read-only display)
}
#endregion
#region Service Event Handlers
private void PingService_PingCompleted(object sender, PingResultEventArgs e)
{
UIHelper.SafeInvoke(this, () =>
{
var timestamp = e.Timestamp.ToString("HH:mm:ss.ff");
var status = e.Result.IsSuccess ?
$"Pinging {e.Result.IpAddress} - Success" :
$"Ping to {e.Result.IpAddress} - Failed: {e.Result.Status}";
var rtt = e.Result.IsSuccess ? $"{e.Result.RoundTripTime} ms" : "";
AddLineToOutput(timestamp, status, rtt);
});
}
private void PingService_StatisticsUpdated(object sender, NetworkStatisticsEventArgs e)
{
UIHelper.SafeInvoke(this, () =>
{
UpdateStatisticsDisplay(e.Statistics);
});
}
#endregion
#region Business Logic Methods
private async System.Threading.Tasks.Task HandleIntervalChangeAsync()
{
try
{
var intervalText = ValidationHelper.SanitizeInput(textBoxInterval.Text);
if (!ValidationHelper.IsValidPingInterval(intervalText, out int interval))
{
UIHelper.ShowError(ValidationHelper.GetValidationErrorMessage("Interval", intervalText));
return;
}
await ClearAllDataAsync();
if (_pingService.IsRunning)
{
await _pingService.StopPingingAsync();
await _pingService.StartPingingAsync(ipAddress.Text, interval);
}
_logger.LogInformation($"Ping interval changed to {interval}ms");
}
catch (Exception ex)
{
_logger.LogError("Error changing ping interval", ex);
UIHelper.ShowError("Failed to change ping interval");
}
}
private async System.Threading.Tasks.Task HandleIpAddressChangeAsync()
{
try
{
var address = ValidationHelper.SanitizeInput(ipAddress.Text);
if (!ValidationHelper.IsValidIpAddressOrHostname(address))
{
UIHelper.ShowError(ValidationHelper.GetValidationErrorMessage("IP Address", address));
return;
}
await ClearAllDataAsync();
// Save to configuration
_configService.LastUsedIpAddress = address;
_configService.Save();
// Restart pinging if it was running
if (_pingService.IsRunning)
{
var interval = int.Parse(textBoxInterval.Text);
await _pingService.StopPingingAsync();
await _pingService.StartPingingAsync(address, interval);
}
_logger.LogInformation($"IP address changed to {address}");
}
catch (Exception ex)
{
_logger.LogError("Error changing IP address", ex);
UIHelper.ShowError("Failed to change IP address");
}
}
private async System.Threading.Tasks.Task StartPingingAsync()
{
try
{
var address = ValidationHelper.SanitizeInput(ipAddress.Text);
var intervalText = ValidationHelper.SanitizeInput(textBoxInterval.Text);
if (!ValidationHelper.IsValidIpAddressOrHostname(address))
{
UIHelper.ShowError("Please enter a valid IP address or hostname");
return;
}
if (!ValidationHelper.IsValidPingInterval(intervalText, out int interval))
{
UIHelper.ShowError("Please enter a valid ping interval (100-60000 ms)");
return;
}
await _pingService.StartPingingAsync(address, interval);
_logger.LogInformation($"Started pinging {address} with {interval}ms interval");
}
catch (Exception ex)
{
_logger.LogError("Error starting ping service", ex);
UIHelper.ShowError("Failed to start pinging");
}
}
private async System.Threading.Tasks.Task ClearAllDataAsync()
{
try
{
_pingService.ClearStatistics();
UIHelper.SafeInvoke(this, () =>
{
dataGridView1.Rows.Clear();
dataGridView2.Rows.Clear();
// Reset statistics display
ResetStatisticsDisplay();
});
// Refresh public IP
await FetchPublicIpAsync();
_logger.LogInformation("All data cleared");
}
catch (Exception ex)
{
_logger.LogError("Error clearing data", ex);
}
}
private async System.Threading.Tasks.Task ResetNetworkAsync()
{
try
{
if (!UIHelper.ShowConfirmation(
"This action will release and renew network settings. Are you sure you want to continue?",
"Confirm Network Reset"))
{
return;
}
var adapter = await _networkService.GetActiveEthernetAdapterAsync();
if (adapter == null)
{
UIHelper.ShowError("No active Ethernet adapter found");
return;
}
ButtonCleanNetwork.Visible = false;
var progress = new Progress<int>(value =>
{
UIHelper.SafeInvoke(this, () =>
{
// Update progress if you have a progress bar
});
});
var success = await _networkService.ResetNetworkAdapterAsync(adapter.Name, progress);
UIHelper.SafeInvoke(this, () =>
{
ButtonCleanNetwork.Visible = true;
if (success)
{
AddLineToOutput(DateTime.Now.ToString("HH:mm:ss.ff"), "Network reset completed", "");
}
else
{
UIHelper.ShowError("Network reset failed");
}
});
}
catch (Exception ex)
{
_logger.LogError("Error during network reset", ex);
UIHelper.SafeInvoke(this, () =>
{
ButtonCleanNetwork.Visible = true;
UIHelper.ShowError("Network reset failed");
});
}
}
private async System.Threading.Tasks.Task CleanTemporaryFilesAsync()
{
try
{
buttonCleanTemp.Visible = false;
var progress = new Progress<int>(value =>
{
UIHelper.SafeInvoke(this, () =>
{
// Update progress if you have a progress bar
});
});
var success = await _systemService.CleanTemporaryFilesAsync(progress);
UIHelper.SafeInvoke(this, () =>
{
buttonCleanTemp.Visible = true;
if (success)
{
UIHelper.ShowInformation("Temporary files cleaned successfully");
}
else
{
UIHelper.ShowError("Failed to clean temporary files");
}
});
}
catch (Exception ex)
{
_logger.LogError("Error cleaning temporary files", ex);
UIHelper.SafeInvoke(this, () =>
{
buttonCleanTemp.Visible = true;
UIHelper.ShowError("Failed to clean temporary files");
});
}
}
private async System.Threading.Tasks.Task StartPublicIpUpdatesAsync()
{
await FetchPublicIpAsync();
// Update public IP every hour
_publicIpTimer = new System.Threading.Timer(async _ => await FetchPublicIpAsync(), null,
TimeSpan.FromHours(1), TimeSpan.FromHours(1));
}
private async System.Threading.Tasks.Task FetchPublicIpAsync()
{
try
{
_cancellationTokenSource?.Cancel();
_cancellationTokenSource = new CancellationTokenSource();
var publicIp = await _networkService.GetPublicIpAddressAsync(_cancellationTokenSource.Token);
_currentPublicIp = publicIp;
UIHelper.SafeInvoke(this, () =>
{
label4.Text = $"Public IP: {publicIp}";
});
}
catch (Exception ex)
{
_logger.LogError("Error fetching public IP", ex);
UIHelper.SafeInvoke(this, () =>
{
label4.Text = "Error fetching IP";
});
// Retry after delay
await System.Threading.Tasks.Task.Delay(30000);
_ = System.Threading.Tasks.Task.Run(async () => await FetchPublicIpAsync());
}
}
private async System.Threading.Tasks.Task UpdateNetworkStatisticsAsync()
{
try
{
var address = ValidationHelper.SanitizeInput(ipAddress.Text);
if (!ValidationHelper.IsValidIpAddressOrHostname(address))
return;
// This will trigger the StatisticsUpdated event
await System.Threading.Tasks.Task.Run(async () =>
{
var result = await _pingService.PingOnceAsync(address);
// Statistics are automatically calculated and updated via events
});
}
catch (Exception ex)
{
_logger.LogError("Error updating network statistics", ex);
}
}
#endregion
#region UI Helper Methods
private void AddLineToOutput(string time, string status, string rtt = "")
{
if (dataGridView1.IsDisposed || !dataGridView1.IsHandleCreated)
return;
UIHelper.SafeInvoke(this, () =>
{
dataGridView1.Rows.Add(new object[] { time, status, rtt });
// Auto-scroll to bottom
if (dataGridView1.Rows.Count > 0)
{
dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.Rows.Count - 1;
}
});
}
private void UpdateStatisticsDisplay(NetworkStatistics stats)
{
try
{
// Update ping statistics
if (dataGridView2.Rows.Count == 0)
{
dataGridView2.Rows.Add();
}
var row = dataGridView2.Rows[0];
row.Cells["MaxPing"].Value = $"{stats.MaxPing} ms";
row.Cells["MinPing"].Value = $"{stats.MinPing} ms";
row.Cells["AvgPing"].Value = $"{stats.AveragePing:F0} ms";
// Update jitter statistics
TextBoxMaxJitter.Text = $"{stats.MaxJitter:F0} ms";
TextBoxMinJitter.Text = $"{stats.MinJitter:F0} ms";
TextBoxAvgJitter.Text = $"{stats.AverageJitter:F0} ms";
// Update packet loss statistics
TextBoxMaxLoss.Text = $"{stats.MaxPacketLoss:F0}%";
TextBoxMinLoss.Text = $"{stats.MinPacketLoss:F0}%";
TextBoxAvgLoss.Text = $"{stats.AveragePacketLoss:F0}%";
// Update current values
textBoxPacketLoss.Text = $"{stats.PacketLoss:F2}%";
textBoxJitter.Text = $"{stats.Jitter:F2}ms";
}
catch (Exception ex)
{
_logger.LogError("Error updating statistics display", ex);
}
}
private void ResetStatisticsDisplay()
{
if (dataGridView2.Rows.Count > 0)
{
dataGridView2.Rows[0].Cells["MaxPing"].Value = "0 ms";
dataGridView2.Rows[0].Cells["MinPing"].Value = "0 ms";
dataGridView2.Rows[0].Cells["AvgPing"].Value = "0 ms";
}
TextBoxMaxJitter.Text = "0 ms";
TextBoxMinJitter.Text = "0 ms";
TextBoxAvgJitter.Text = "0 ms";
TextBoxMaxLoss.Text = "0%";
TextBoxMinLoss.Text = "0%";
TextBoxAvgLoss.Text = "0%";
textBoxPacketLoss.Text = "0%";
textBoxJitter.Text = "0ms";
}
#endregion
#region Context Menu
private void InitializeContextMenu()
{
contextMenuStrip1 = new ContextMenuStrip();
contextMenuStrip1.Items.Add("[1] Show Network Details");
contextMenuStrip1.Items.Add("[2] Auto Ping");
contextMenuStrip1.Items.Add("[3] Run with Windows");
contextMenuStrip1.Items.Add("[4] Proxy");
// Attach event handlers
contextMenuStrip1.Items[0].Click += ShowNetworkDetails_Click;
contextMenuStrip1.Items[1].Click += AutoPing_Click;
contextMenuStrip1.Items[2].Click += RunWithWindows_Click;
contextMenuStrip1.Items[3].Click += Proxy_Click;
UpdateContextMenuItems();
}
private async void ShowNetworkDetails_Click(object sender, EventArgs e)
{
try
{
var adapters = await _networkService.GetNetworkAdaptersAsync();
var activeAdapters = adapters.Where(a => a.IsActive).ToList();
if (!activeAdapters.Any())
{
UIHelper.ShowInformation("No active network adapters found");
return;
}
var details = string.Join("\n\n", activeAdapters.Select(adapter =>
$"Description: {adapter.Description}\n" +
$"Physical Address: {adapter.PhysicalAddress}\n" +
$"DHCP Enabled: {(adapter.IsDhcpEnabled ? "Yes" : "No")}\n" +
$"IPv4 Address: {adapter.IpAddress}\n" +
$"IPv4 Subnet Mask: {adapter.SubnetMask}\n" +
$"IPv4 Default Gateway: {adapter.DefaultGateway}\n" +
$"IPv4 DHCP Server: {adapter.DhcpServer}\n" +
$"IPv4 DNS Servers: {string.Join(", ", adapter.DnsServers)}"
));
UIHelper.ShowInformation(details, "Network Details");
}
catch (Exception ex)
{
_logger.LogError("Error showing network details", ex);
UIHelper.ShowError("Failed to retrieve network details");
}
}
private async void AutoPing_Click(object sender, EventArgs e)
{
try
{
if (_pingService.IsRunning)
{
await _pingService.StopPingingAsync();
_configService.AutoPingEnabled = false;
}
else
{
await StartPingingAsync();
_configService.AutoPingEnabled = true;
}
_configService.Save();
UpdateContextMenuItems();
}
catch (Exception ex)
{
_logger.LogError("Error toggling auto ping", ex);
UIHelper.ShowError("Failed to toggle auto ping");
}
}
private async void RunWithWindows_Click(object sender, EventArgs e)
{
try
{
const string taskName = "Pingerino";
var executablePath = Application.ExecutablePath;
var taskExists = await _systemService.IsStartupTaskExistsAsync(taskName);
bool success;
if (taskExists)
{
success = await _systemService.RemoveStartupTaskAsync(taskName);
}
else
{
success = await _systemService.CreateStartupTaskAsync(taskName, executablePath);
}
if (success)
{
UpdateContextMenuItems();
}
else
{
UIHelper.ShowError("Failed to update startup task");
}
}
catch (Exception ex)
{
_logger.LogError("Error managing startup task", ex);
UIHelper.ShowError("Failed to manage startup task");
}
}
private async void Proxy_Click(object sender, EventArgs e)
{
try
{
var scriptPath = System.IO.Path.Combine(
System.IO.Path.GetDirectoryName(Application.ExecutablePath),
"runPS1.bat");
var success = await _systemService.RunExternalScriptAsync(scriptPath);
if (!success)
{
UIHelper.ShowError("Proxy script not found or failed to execute");
}
}
catch (Exception ex)
{
_logger.LogError("Error running proxy script", ex);
UIHelper.ShowError("Failed to run proxy script");
}
}
private async void UpdateContextMenuItems()
{
try
{
// Update auto ping status
contextMenuStrip1.Items[1].Text = _pingService.IsRunning ?
"[2] Auto Ping ✔" : "[2] Auto Ping";
// Update startup task status
var taskExists = await _systemService.IsStartupTaskExistsAsync("Pingerino");
contextMenuStrip1.Items[2].Text = taskExists ?
"[3] Run with Windows ✔" : "[3] Run with Windows";
}
catch (Exception ex)
{
_logger.LogError("Error updating context menu items", ex);
}
}
#endregion
}
}