Initial commit

This commit is contained in:
2026-09-24 21:39:36 +03:00 Unverified
commit bea2b4f180
38 changed files with 1225 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Application
x:Class="IPClab._5.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:IPClab._5">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->
</ResourceDictionary>
</Application.Resources>
</Application>
+50
View File
@@ -0,0 +1,50 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.UI.Xaml.Shapes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace IPClab._5
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : Application
{
private Window? _window;
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
InitializeComponent();
}
/// <summary>
/// Invoked when the application is launched.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
_window = new MainWindow();
_window.Activate();
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

+66
View File
@@ -0,0 +1,66 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RootNamespace>IPClab._5</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Platforms>x86;x64;ARM64</Platforms>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
<PublishProfile>win-$(Platform).pubxml</PublishProfile>
<UseWinUI>true</UseWinUI>
<WinUISDKReferences>false</WinUISDKReferences>
<EnableMsixTooling>true</EnableMsixTooling>
<Nullable>enable</Nullable>
<WindowsPackageType>None</WindowsPackageType>
<WindowsAppSdkBootstrapInitialize>true</WindowsAppSdkBootstrapInitialize>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>14.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<Content Include="Assets\SplashScreen.scale-200.png" />
<Content Include="Assets\LockScreenLogo.scale-200.png" />
<Content Include="Assets\Square150x150Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Assets\StoreLogo.png" />
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
</ItemGroup>
<ItemGroup>
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<!--
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
Tools extension to be activated for this project even if the Windows App SDK Nuget
package has not yet been restored.
-->
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.12" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.28000.2705" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="2.5.1" />
</ItemGroup>
<!--
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
Explorer "Package and Publish" context menu entry to be enabled for this project even if
the Windows App SDK Nuget package has not yet been restored.
-->
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>
<!-- Publish Properties -->
<PropertyGroup>
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
</PropertyGroup>
</Project>
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="IPClab._5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:IPClab._5"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="IPClab.5">
<Window.SystemBackdrop>
<MicaBackdrop />
</Window.SystemBackdrop>
<Grid>
</Grid>
</Window>
+31
View File
@@ -0,0 +1,31 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace IPClab._5
{
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
+15
View File
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IPClab._5.Models;
public class NetworkEvent
{
public string Message { get; set; } = string.Empty;
public long BytesTransferred { get; set; }
public string StatusText { get; set; } = string.Empty;
public bool IsError { get; set; }
}
+53
View File
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:systemai="http://schemas.microsoft.com/appx/manifest/systemai/windows10"
IgnorableNamespaces="uap rescap systemai">
<Identity
Name="49ea2d0d-285b-4301-9671-48a328bf201c"
Publisher="CN=retrd"
Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="49ea2d0d-285b-4301-9671-48a328bf201c" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>IPClab.5</DisplayName>
<PublisherDisplayName>retrd</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.26226.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.26226.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="IPClab.5"
Description="IPClab.5"
BackgroundColor="transparent"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
<systemai:Capability Name="systemAIModels"/>
</Capabilities>
</Package>
+10
View File
@@ -0,0 +1,10 @@
{
"profiles": {
"IPClab.5 (Package)": {
"commandName": "MsixPackage"
},
"IPClab.5 (Unpackaged)": {
"commandName": "Project"
}
}
}
+131
View File
@@ -0,0 +1,131 @@
using IPClab._5.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace IPClab._5.Service;
public class TcpClientService
{
private TcpClient? _client;
private NetworkStream? _stream;
private CancellationTokenSource? _cts;
private long _totalBytesReceived;
private long _totalBytesSent;
public bool IsConnected => _client?.Connected ?? false;
public async Task ConnectAsync(string ipAddress, int port, IProgress<NetworkEvent> progress)
{
if (IsConnected) return;
_totalBytesReceived = 0;
_totalBytesSent = 0;
_client = new TcpClient();
_cts = new CancellationTokenSource();
try
{
progress.Report(new NetworkEvent { StatusText = "Connecting", Message = $"Connecting to {ipAddress}:{port}..." });
await _client.ConnectAsync(ipAddress, port).ConfigureAwait(false);
_stream = _client.GetStream();
// Quality Control Step: Apply structural operation timeouts
_stream.ReadTimeout = 5000;
_stream.WriteTimeout = 5000;
progress.Report(new NetworkEvent { StatusText = "Connected", Message = "Successfully connected to server." });
// Fire and forget background incoming processing loop
_ = Task.Run(() => ListenForServerPayloadsAsync(_cts.Token, progress), _cts.Token);
}
catch (Exception ex)
{
CleanUp();
progress.Report(new NetworkEvent { StatusText = "Disconnected", Message = $"Connection failed: {ex.Message}", IsError = true });
throw;
}
}
public async Task SendMessageAsync(string message, IProgress<NetworkEvent> progress)
{
if (!IsConnected || _stream == null)
{
progress.Report(new NetworkEvent { StatusText = "Disconnected", Message = "Cannot send message. Client is offline.", IsError = true });
return;
}
try
{
// Quality Control Requirement: Delimiter-based separation
byte[] data = Encoding.UTF8.GetBytes(message + "\n");
await _stream.WriteAsync(data, 0, data.Length).ConfigureAwait(false);
_totalBytesSent += data.Length;
progress.Report(new NetworkEvent { StatusText = "Connected", Message = $"Sent: {message}", BytesTransferred = _totalBytesSent });
}
catch (Exception ex)
{
progress.Report(new NetworkEvent { StatusText = "Disconnected", Message = $"Send fault occurred: {ex.Message}", IsError = true });
CleanUp();
}
}
private async Task ListenForServerPayloadsAsync(CancellationToken token, IProgress<NetworkEvent> progress)
{
using (StreamReader reader = new StreamReader(_stream!, Encoding.UTF8))
{
while (!token.IsCancellationRequested && IsConnected)
{
try
{
string? incomingPayload = await reader.ReadLineAsync(token).ConfigureAwait(false);
if (incomingPayload == null) break; // Clean TCP drop detected
long rawBytesCount = Encoding.UTF8.GetByteCount(incomingPayload) + Environment.NewLine.Length;
_totalBytesReceived += rawBytesCount;
progress.Report(new NetworkEvent
{
StatusText = "Connected",
Message = $"Received: {incomingPayload}",
BytesTransferred = _totalBytesReceived
});
}
catch (OperationCanceledException) when (token.IsCancellationRequested)
{
break;
}
catch (Exception ex)
{
progress.Report(new NetworkEvent { StatusText = "Disconnected", Message = $"Read thread error: {ex.Message}", IsError = true });
break;
}
}
}
CleanUp();
progress.Report(new NetworkEvent { StatusText = "Disconnected", Message = "Disconnected from server cleanly." });
}
public void Disconnect()
{
CleanUp();
}
private void CleanUp()
{
_cts?.Cancel();
_stream?.Dispose();
_client?.Dispose();
_stream = null;
_client = null;
}
}
@@ -0,0 +1,12 @@
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IPClab._5.ViewModels;
public partial class MainWindowViewModel : ObservableObject
{
}
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="IPClab.5.app"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- The ID below informs the system that this application is compatible with OS features first introduced in Windows 10.
It is necessary to support features in unpackaged applications, for example the custom titlebar implementation.
For more info see https://docs.microsoft.com/windows/apps/windows-app-sdk/use-windows-app-sdk-run-time#declare-os-compatibility-in-your-application-manifest -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
</assembly>