diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index e7840696..53799570 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -1,31 +1,3 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# This workflow helps you trigger a SonarCloud analysis of your code and populates -# GitHub Code Scanning alerts with the vulnerabilities found. -# Free for open source project. - -# 1. Login to SonarCloud.io using your GitHub account - -# 2. Import your project on SonarCloud -# * Add your GitHub organization first, then add your repository as a new project. -# * Please note that many languages are eligible for automatic analysis, -# which means that the analysis will start automatically without the need to set up GitHub Actions. -# * This behavior can be changed in Administration > Analysis Method. -# -# 3. Follow the SonarCloud in-product tutorial -# * a. Copy/paste the Project Key and the Organization Key into the args parameter below -# (You'll find this information in SonarCloud. Click on "Information" at the bottom left) -# -# * b. Generate a new token and add it to your Github repository's secrets using the name SONAR_TOKEN -# (On SonarCloud, click on your avatar on top-right > My account > Security -# or go directly to https://sonarcloud.io/account/security/) - -# Feel free to take a look at our documentation (https://docs.sonarcloud.io/getting-started/github/) -# or reach out to our community forum if you need some help (https://community.sonarsource.com/c/help/sc/9) - name: SonarCloud analysis on: @@ -36,48 +8,46 @@ on: workflow_dispatch: permissions: - pull-requests: read # allows SonarCloud to decorate PRs with analysis results + contents: read + pull-requests: read jobs: - sonar-check: - name: Sonar Check - runs-on: windows-latest # безпечно для будь-яких .NET проектів + sonar: + name: SonarCloud Analysis + runs-on: windows-latest + steps: - uses: actions/checkout@v4 - with: { fetch-depth: 0 } + with: + fetch-depth: 0 - uses: actions/setup-dotnet@v4 with: dotnet-version: '8.0.x' - # 1) BEGIN: SonarScanner for .NET - - name: SonarScanner Begin + - name: Install SonarScanner run: | dotnet tool install --global dotnet-sonarscanner echo "$env:USERPROFILE\.dotnet\tools" >> $env:GITHUB_PATH + shell: pwsh + + - name: SonarScanner Begin + run: | dotnet sonarscanner begin ` - /k:"ppanchen_NetSdrClient" ` - /o:"ppanchen" ` - /d:sonar.token="${{ secrets.SONAR_TOKEN }}" ` - /d:sonar.cs.opencover.reportsPaths="**/coverage.xml" ` - /d:sonar.cpd.cs.minimumTokens=40 ` - /d:sonar.cpd.cs.minimumLines=5 ` - /d:sonar.exclusions=**/bin/**,**/obj/**,**/sonarcloud.yml ` - /d:sonar.qualitygate.wait=true + /k:"olekca160406_NetSdrClient" ` + /o:"olekca160406" ` + /d:sonar.token="${{ secrets.SONAR_TOKEN }}" ` + /d:sonar.cs.opencover.reportsPaths="**/coverage.xml" ` + /d:sonar.exclusions="**/bin/**,**/obj/**" ` + shell: pwsh - # 2) BUILD & TEST + - name: Restore run: dotnet restore NetSdrClient.sln + - name: Build run: dotnet build NetSdrClient.sln -c Release --no-restore - #- name: Tests with coverage (OpenCover) - # run: | - # dotnet test NetSdrClientAppTests/NetSdrClientAppTests.csproj -c Release --no-build ` - # /p:CollectCoverage=true ` - # /p:CoverletOutput=TestResults/coverage.xml ` - # /p:CoverletOutputFormat=opencover - # shell: pwsh - # 3) END: SonarScanner + - name: SonarScanner End run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" shell: pwsh diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs index 5966c579..9affa28f 100644 --- a/EchoTcpServer/Program.cs +++ b/EchoTcpServer/Program.cs @@ -1,108 +1,107 @@ -using System; +using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; + /// /// This program was designed for test purposes only /// Not for a review /// -public class EchoServer +namespace NetSdrClientApp.EchoServer { - private readonly int _port; - private TcpListener _listener; - private CancellationTokenSource _cancellationTokenSource; - - - public EchoServer(int port) + public class EchoServer { - _port = port; - _cancellationTokenSource = new CancellationTokenSource(); - } + private readonly int _port; + private TcpListener _listener; + private readonly CancellationTokenSource _cancellationTokenSource; - public async Task StartAsync() - { - _listener = new TcpListener(IPAddress.Any, _port); - _listener.Start(); - Console.WriteLine($"Server started on port {_port}."); + public EchoServer(int port) + { + _port = port; + _cancellationTokenSource = new CancellationTokenSource(); + } - while (!_cancellationTokenSource.Token.IsCancellationRequested) + public async Task StartAsync() { - try - { - TcpClient client = await _listener.AcceptTcpClientAsync(); - Console.WriteLine("Client connected."); + _listener = new TcpListener(IPAddress.Any, _port); + _listener.Start(); + Console.WriteLine($"Server started on port {_port}."); - _ = Task.Run(() => HandleClientAsync(client, _cancellationTokenSource.Token)); - } - catch (ObjectDisposedException) + while (!_cancellationTokenSource.Token.IsCancellationRequested) { - // Listener has been closed - break; + try + { + TcpClient client = await _listener.AcceptTcpClientAsync(); + Console.WriteLine("Client connected."); + + _ = Task.Run(() => HandleClientAsync(client, _cancellationTokenSource.Token)); + } + catch (ObjectDisposedException) + { + // Listener has been closed + break; + } } - } - Console.WriteLine("Server shutdown."); - } + Console.WriteLine("Server shutdown."); + } - private async Task HandleClientAsync(TcpClient client, CancellationToken token) - { - using (NetworkStream stream = client.GetStream()) + private async Task HandleClientAsync(TcpClient client, CancellationToken token) { - try + using (NetworkStream stream = client.GetStream()) { - byte[] buffer = new byte[8192]; - int bytesRead; - - while (!token.IsCancellationRequested && (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token)) > 0) + try { - // Echo back the received message - await stream.WriteAsync(buffer, 0, bytesRead, token); - Console.WriteLine($"Echoed {bytesRead} bytes to the client."); + byte[] buffer = new byte[8192]; + int bytesRead; + + while (!token.IsCancellationRequested && + (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token)) > 0) + { + await stream.WriteAsync(buffer, 0, bytesRead, token); + Console.WriteLine($"Echoed {bytesRead} bytes to the client."); + } + } + catch (Exception ex) when (ex is not OperationCanceledException) + { + Console.WriteLine($"Error: {ex.Message}"); + } + finally + { + client.Close(); + Console.WriteLine("Client disconnected."); } - } - catch (Exception ex) when (!(ex is OperationCanceledException)) - { - Console.WriteLine($"Error: {ex.Message}"); - } - finally - { - client.Close(); - Console.WriteLine("Client disconnected."); } } - } - public void Stop() - { - _cancellationTokenSource.Cancel(); - _listener.Stop(); - _cancellationTokenSource.Dispose(); - Console.WriteLine("Server stopped."); - } + public void Stop() + { + _cancellationTokenSource.Cancel(); + _listener.Stop(); + _cancellationTokenSource.Dispose(); + Console.WriteLine("Server stopped."); + } - public static async Task Main(string[] args) - { - EchoServer server = new EchoServer(5000); + public static async Task Main(string[] args) + { + EchoServer server = new EchoServer(5000); - // Start the server in a separate task - _ = Task.Run(() => server.StartAsync()); + _ = Task.Run(() => server.StartAsync()); - string host = "127.0.0.1"; // Target IP - int port = 60000; // Target Port - int intervalMilliseconds = 5000; // Send every 3 seconds + string host = "127.0.0.1"; + int port = 60000; + int intervalMilliseconds = 5000; - using (var sender = new UdpTimedSender(host, port)) - { + using var sender = new UdpTimedSender(host, port); Console.WriteLine("Press any key to stop sending..."); sender.StartSending(intervalMilliseconds); Console.WriteLine("Press 'q' to quit..."); while (Console.ReadKey(intercept: true).Key != ConsoleKey.Q) { - // Just wait until 'q' is pressed } sender.StopSending(); @@ -110,64 +109,66 @@ public static async Task Main(string[] args) Console.WriteLine("Sender stopped."); } } -} - - -public class UdpTimedSender : IDisposable -{ - private readonly string _host; - private readonly int _port; - private readonly UdpClient _udpClient; - private Timer _timer; - public UdpTimedSender(string host, int port) + public class UdpTimedSender : IDisposable { - _host = host; - _port = port; - _udpClient = new UdpClient(); - } + private readonly string _host; + private readonly int _port; + private readonly UdpClient _udpClient; + private Timer? _timer; - public void StartSending(int intervalMilliseconds) - { - if (_timer != null) - throw new InvalidOperationException("Sender is already running."); + private ushort _counter; - _timer = new Timer(SendMessageCallback, null, 0, intervalMilliseconds); - } + public UdpTimedSender(string host, int port) + { + _host = host; + _port = port; + _udpClient = new UdpClient(); + } - ushort i = 0; + public void StartSending(int intervalMilliseconds) + { + if (_timer != null) + throw new InvalidOperationException("Sender is already running."); - private void SendMessageCallback(object state) - { - try + _timer = new Timer(SendMessageCallback, null, 0, intervalMilliseconds); + } + + private void SendMessageCallback(object? state) { - //dummy data - Random rnd = new Random(); - byte[] samples = new byte[1024]; - rnd.NextBytes(samples); - i++; + try + { + var rnd = new Random(); + byte[] samples = new byte[1024]; + rnd.NextBytes(samples); + _counter++; + + byte[] msg = new byte[] { 0x04, 0x84 } + .Concat(BitConverter.GetBytes(_counter)) + .Concat(samples) + .ToArray(); - byte[] msg = (new byte[] { 0x04, 0x84 }).Concat(BitConverter.GetBytes(i)).Concat(samples).ToArray(); - var endpoint = new IPEndPoint(IPAddress.Parse(_host), _port); + var endpoint = new IPEndPoint(IPAddress.Parse(_host), _port); - _udpClient.Send(msg, msg.Length, endpoint); - Console.WriteLine($"Message sent to {_host}:{_port} "); + _udpClient.Send(msg, msg.Length, endpoint); + Console.WriteLine($"Message sent to {_host}:{_port} "); + } + catch (Exception ex) + { + Console.WriteLine($"Error sending message: {ex.Message}"); + } } - catch (Exception ex) + + public void StopSending() { - Console.WriteLine($"Error sending message: {ex.Message}"); + _timer?.Dispose(); + _timer = null; } - } - - public void StopSending() - { - _timer?.Dispose(); - _timer = null; - } - public void Dispose() - { - StopSending(); - _udpClient.Dispose(); + public void Dispose() + { + StopSending(); + _udpClient.Dispose(); + } } -} \ No newline at end of file +} diff --git a/NetSdrClientApp/Networking/IUdpClient.cs b/NetSdrClientApp/Networking/IUdpClient.cs index 1b9f9311..fb296806 100644 --- a/NetSdrClientApp/Networking/IUdpClient.cs +++ b/NetSdrClientApp/Networking/IUdpClient.cs @@ -1,10 +1,10 @@ - -public interface IUdpClient +namespace NetSdrClientApp.Networking { - event EventHandler? MessageReceived; - - Task StartListeningAsync(); - - void StopListening(); - void Exit(); -} \ No newline at end of file + public interface IUdpClient + { + event EventHandler? MessageReceived; + Task StartListeningAsync(); + void StopListening(); + void Exit(); + } +} diff --git a/README.md b/README.md index b3a90294..9032ea73 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,18 @@ # Лабораторні з реінжинірингу (8×) -[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=coverage)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=bugs)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) + + +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=bugs)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=coverage)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) + + Цей репозиторій використовується для курсу **реінжиніринг ПЗ**.