Add project files.
This commit is contained in:
182
Network.cs
Normal file
182
Network.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace AiQ_GUI
|
||||
{
|
||||
public class Network
|
||||
{
|
||||
public static HttpClient? SingleHTTPClient;
|
||||
public static HttpClient Client => SingleHTTPClient ?? throw new InvalidOperationException("Client not initialized.");
|
||||
|
||||
public static void Initialize(string username, string password)
|
||||
{
|
||||
HttpClientHandler handler = new HttpClientHandler
|
||||
{
|
||||
MaxConnectionsPerServer = 25,
|
||||
Credentials = new NetworkCredential(username, password)
|
||||
};
|
||||
|
||||
SingleHTTPClient?.Dispose(); // Dispose old client if needed
|
||||
SingleHTTPClient = new HttpClient(handler)
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(20)
|
||||
};
|
||||
}
|
||||
|
||||
// Handles get and post to the camera API
|
||||
public static async Task<string> SendHttpRequest(string url, HttpMethod method, int? Timeout, string? jsonData = null, string[]? Headers = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpRequestMessage request = new HttpRequestMessage(method, url);
|
||||
|
||||
if (jsonData != null) // Fills in the body of the request if jsonData is provided
|
||||
request.Content = new StringContent(jsonData, Encoding.UTF8, "application/json");
|
||||
|
||||
if (Headers != null) // Fills in the headers of the request if Headers are provided
|
||||
{
|
||||
foreach (string Header in Headers)
|
||||
{
|
||||
string[] parts = Header.Split(':');
|
||||
|
||||
if (parts.Length == 2)
|
||||
request.Headers.Add(parts[0].Trim(), parts[1].Trim());
|
||||
else
|
||||
throw new ArgumentException($"Invalid header format: {Header}");
|
||||
}
|
||||
}
|
||||
|
||||
int timeoutMs = (Timeout ?? 10) * 1000; // Convert from seconds to ms
|
||||
using CancellationTokenSource cts = new CancellationTokenSource(timeoutMs);
|
||||
|
||||
using HttpResponseMessage response = await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cts.Token);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return await response.Content.ReadAsStringAsync(cts.Token); // Use token here too if you're chaining timeouts
|
||||
}
|
||||
catch (TaskCanceledException ex)
|
||||
{
|
||||
return $"HTTP error calling {url}: {ex.Message}";
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
return $"HTTP error calling {url}: {ex.Message}";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return $"Unexpected error calling {url}: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
public async static Task<IList<string>> SearchForCams()
|
||||
{
|
||||
const int sendPort = 6666;
|
||||
const int receivePort = 6667;
|
||||
IList<string> FoundCams = [];
|
||||
|
||||
byte[] discoveryPacket = [0x50, 0x4f, 0x4c, 0x4c, 0xaf, 0xb0, 0xb3, 0xb3, 0xb6, 0x01, 0xa8, 0xc0, 0x0b, 0x1a, 0x00, 0x00];
|
||||
|
||||
async Task SendAndListen(IPAddress localIp)
|
||||
{
|
||||
using (UdpClient sender = new(new IPEndPoint(localIp, sendPort)))
|
||||
{
|
||||
sender.EnableBroadcast = true;
|
||||
sender.Connect(new IPEndPoint(IPAddress.Broadcast, sendPort));
|
||||
sender.Send(discoveryPacket, discoveryPacket.Length);
|
||||
}
|
||||
|
||||
using UdpClient receiver = new(receivePort); // Listen for replies on fixed port
|
||||
receiver.Client.ReceiveTimeout = 750;
|
||||
|
||||
DateTime timeout = DateTime.Now.AddMilliseconds(750);
|
||||
try
|
||||
{
|
||||
while (DateTime.Now < timeout)
|
||||
{
|
||||
if (receiver.Available > 0)
|
||||
{
|
||||
UdpReceiveResult result = await receiver.ReceiveAsync();
|
||||
byte[] recvBuffer = result.Buffer;
|
||||
|
||||
if (recvBuffer.Length >= 52) // Safety check
|
||||
{
|
||||
byte[] ipBytes = recvBuffer.Skip(recvBuffer.Length - 52).Take(4).Reverse().ToArray();
|
||||
string ipToAdd = string.Join(".", ipBytes);
|
||||
|
||||
if (!FoundCams.Contains(ipToAdd))
|
||||
FoundCams.Add(ipToAdd);
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Delay(50); // brief wait to allow data in
|
||||
}
|
||||
}
|
||||
catch (SocketException ex) when (ex.SocketErrorCode == SocketError.TimedOut)
|
||||
{
|
||||
// No data received in time — normal case
|
||||
}
|
||||
}
|
||||
|
||||
// Get first IPv4 interface (non-loopback)
|
||||
foreach (IPAddress ip in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
|
||||
{
|
||||
try
|
||||
{
|
||||
await SendAndListen(ip);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
return FoundCams;
|
||||
}
|
||||
|
||||
// Ping to make sure devices are connected to the network, be aware it isn't consistant across subnets.
|
||||
public async static Task<bool> PingIP(string ipAddress)
|
||||
{
|
||||
if (RegexCache.RegexIPPattern().IsMatch(ipAddress))
|
||||
{
|
||||
try
|
||||
{
|
||||
Ping myPing = new();
|
||||
PingReply reply = await myPing.SendPingAsync(ipAddress, 1000); // Timeout is 1s
|
||||
return reply.Status == IPStatus.Success;
|
||||
}
|
||||
catch (PingException ex) { MainForm.Instance.AddToActionsList($"PingException: Unable to ping {ipAddress}. Reason: {ex.Message}"); }
|
||||
catch (SocketException ex) { MainForm.Instance.AddToActionsList($"SocketException: Network error while pinging {ipAddress}. Reason: {ex.Message}"); }
|
||||
catch (Exception ex) { MainForm.Instance.AddToActionsList($"Unexpected error while pinging {ipAddress}: {ex.Message}"); }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start a thread that pings each IP in the hardware accessories menu
|
||||
public static async Task PingAndUpdateUI(string IP, Label label, string ItemName, ToolTip TT, Button[]? buttonsToEnable = null)
|
||||
{
|
||||
bool isAvailable = await PingIP(IP);
|
||||
|
||||
label.Invoke(() =>
|
||||
{
|
||||
if (isAvailable)
|
||||
{
|
||||
label.Text = "✔";
|
||||
label.ForeColor = Color.ForestGreen;
|
||||
TT.SetToolTip(label, ItemName + " Available");
|
||||
}
|
||||
else
|
||||
{
|
||||
label.Text = "❌";
|
||||
label.ForeColor = Color.Red;
|
||||
TT.SetToolTip(label, "No ping from " + ItemName);
|
||||
}
|
||||
|
||||
if (buttonsToEnable != null)
|
||||
{
|
||||
foreach (Button button in buttonsToEnable)
|
||||
button.Enabled = isAvailable;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user