Init
This commit is contained in:
71
.vscode/launch.json
vendored
Normal file
71
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "HTTP/JSON Server",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/Server/bin/Debug/net8.0/Server.dll",
|
||||||
|
"args": [ "http", "json" ],
|
||||||
|
"cwd": "${workspaceFolder}/Server",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"presentation": {
|
||||||
|
"hidden": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HTTP/JSON Client",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/Client/bin/Debug/net8.0/Client.dll",
|
||||||
|
"args": [ "http", "json" ],
|
||||||
|
"cwd": "${workspaceFolder}/Client",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"presentation": {
|
||||||
|
"hidden": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HTTP/BIN Server",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/Server/bin/Debug/net8.0/Server.dll",
|
||||||
|
"args": [ "http", "bin" ],
|
||||||
|
"cwd": "${workspaceFolder}/Server",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"presentation": {
|
||||||
|
"hidden": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HTTP/BIN Client",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/Client/bin/Debug/net8.0/Client.dll",
|
||||||
|
"args": [ "http", "bin" ],
|
||||||
|
"cwd": "${workspaceFolder}/Client",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"presentation": {
|
||||||
|
"hidden": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"compounds": [
|
||||||
|
{
|
||||||
|
"name": "HTTP/JSON: Server and Client",
|
||||||
|
"configurations": ["HTTP/JSON Server", "HTTP/JSON Client"],
|
||||||
|
"preLaunchTask": "dotnet: build",
|
||||||
|
"stopAll": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HTTP/BIN: Server and Client",
|
||||||
|
"configurations": ["HTTP/BIN Server", "HTTP/BIN Client"],
|
||||||
|
"preLaunchTask": "dotnet: build",
|
||||||
|
"stopAll": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
18
Client/Client.csproj
Normal file
18
Client/Client.csproj
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../Domain/Domain.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MessagePack" Version="3.1.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
96
Client/HttpClient.cs
Normal file
96
Client/HttpClient.cs
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Domain;
|
||||||
|
using Domain.Dto;
|
||||||
|
using MessagePack;
|
||||||
|
|
||||||
|
namespace Client;
|
||||||
|
|
||||||
|
public class HttpClientWrapper : IClient
|
||||||
|
{
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
private readonly string _baseUrl;
|
||||||
|
private CancellationTokenSource _cts = new CancellationTokenSource();
|
||||||
|
private Task? _runningTask;
|
||||||
|
private Func<HttpResponseMessage, Task<Data?>>? _responseConverter;
|
||||||
|
|
||||||
|
public HttpClientWrapper(Func<HttpResponseMessage, Task<Data?>> responseConverter, string baseUrl = "http://localhost:5555/")
|
||||||
|
{
|
||||||
|
_httpClient = new HttpClient();
|
||||||
|
_baseUrl = baseUrl;
|
||||||
|
_responseConverter = responseConverter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
_cts = new CancellationTokenSource();
|
||||||
|
_runningTask = Task.Run(() => RunAsync(_cts.Token));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
_cts.Cancel();
|
||||||
|
_runningTask?.Wait();
|
||||||
|
_httpClient.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RunAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
long index = 0;
|
||||||
|
var sw = Stopwatch.StartNew();
|
||||||
|
var lastMs = 0L;
|
||||||
|
var lastIndex = 0L;
|
||||||
|
var ms = 1000;
|
||||||
|
while (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = $"{_baseUrl}fetchpackage?index={index}";
|
||||||
|
var response = await _httpClient.GetAsync(url, token);
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
if (_responseConverter != null)
|
||||||
|
{
|
||||||
|
var data = await _responseConverter(response);
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
var diff = sw.ElapsedMilliseconds - lastMs;
|
||||||
|
if (diff >= ms)
|
||||||
|
{
|
||||||
|
var fetched = index - lastIndex;
|
||||||
|
System.Console.WriteLine($"Fetched {fetched} data packages in {diff} ms.");
|
||||||
|
lastIndex = index;
|
||||||
|
lastMs = sw.ElapsedMilliseconds;
|
||||||
|
}
|
||||||
|
//System.Console.WriteLine(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("Response converter not set.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Failed to fetch data for index {index}: {response.StatusCode}");
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
//await Task.Delay(100, token); // Wait 1 second between requests
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error: {ex.Message}");
|
||||||
|
await Task.Delay(1000, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
Client/IClient.cs
Normal file
7
Client/IClient.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Client;
|
||||||
|
|
||||||
|
interface IClient
|
||||||
|
{
|
||||||
|
public void Start();
|
||||||
|
public void Stop();
|
||||||
|
}
|
||||||
53
Client/Program.cs
Normal file
53
Client/Program.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Client;
|
||||||
|
using Domain;
|
||||||
|
using Domain.Dto;
|
||||||
|
using MessagePack;
|
||||||
|
|
||||||
|
if (args.Length < 2)
|
||||||
|
{
|
||||||
|
System.Console.WriteLine("Pass two args: http/tcp and json/bin");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var protocol = args[0];
|
||||||
|
var serialization = args[1];
|
||||||
|
IClient? client = protocol == "http" ? new HttpClientWrapper(serialization == "json" ? ConvertJsonResponse : ConvertMessagePackResponse) : null;
|
||||||
|
|
||||||
|
client?.Start();
|
||||||
|
System.Console.WriteLine("Client started:");
|
||||||
|
System.Console.WriteLine(client);
|
||||||
|
|
||||||
|
// Обработка выхода по Ctrl+C
|
||||||
|
Console.CancelKeyPress += (sender, e) =>
|
||||||
|
{
|
||||||
|
e.Cancel = true; // Prevent immediate termination
|
||||||
|
Console.WriteLine("Shutdown signal received. Stopping client...");
|
||||||
|
client?.Stop();
|
||||||
|
Console.WriteLine("Goodbye!");
|
||||||
|
Environment.Exit(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Бесконечный цикл ожидания
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async Task<Data?> ConvertJsonResponse(HttpResponseMessage response)
|
||||||
|
{
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
var jsonData = JsonSerializer.Deserialize<JsonData>(json);
|
||||||
|
return jsonData?.ToData();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async Task<Data?> ConvertMessagePackResponse(HttpResponseMessage response)
|
||||||
|
{
|
||||||
|
var bytes = await response.Content.ReadAsByteArrayAsync();
|
||||||
|
var msgPackData = MessagePackSerializer.Deserialize<MessagePackData>(bytes);
|
||||||
|
return msgPackData?.ToData();
|
||||||
|
}
|
||||||
17
Domain/Data.cs
Normal file
17
Domain/Data.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
namespace Domain;
|
||||||
|
|
||||||
|
public record class Data(
|
||||||
|
double ConcentrationIndex,
|
||||||
|
double RelaxationIndex,
|
||||||
|
double CognitiveControl,
|
||||||
|
double CognitiveLoad,
|
||||||
|
double Alpha,
|
||||||
|
double Beta,
|
||||||
|
double Theta,
|
||||||
|
double Smr,
|
||||||
|
double MuWave,
|
||||||
|
bool Artifact,
|
||||||
|
double SignalQuality,
|
||||||
|
long PackageIndex,
|
||||||
|
DateTime TimeOfDataGenerate
|
||||||
|
);
|
||||||
14
Domain/Domain.csproj
Normal file
14
Domain/Domain.csproj
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MessagePack" Version="3.1.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
71
Domain/Dto/JsonData.cs
Normal file
71
Domain/Dto/JsonData.cs
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
namespace Domain.Dto;
|
||||||
|
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
public class JsonData
|
||||||
|
{
|
||||||
|
[JsonPropertyName("concentrationIndex")]
|
||||||
|
public double ConcentrationIndex { get; set; }
|
||||||
|
[JsonPropertyName("relaxationIndex")]
|
||||||
|
public double RelaxationIndex { get; set; }
|
||||||
|
[JsonPropertyName("cognitiveControl")]
|
||||||
|
public double CognitiveControl { get; set; }
|
||||||
|
[JsonPropertyName("cognitiveLoad")]
|
||||||
|
public double CognitiveLoad { get; set; }
|
||||||
|
[JsonPropertyName("alpha")]
|
||||||
|
public double Alpha { get; set; }
|
||||||
|
[JsonPropertyName("beta")]
|
||||||
|
public double Beta { get; set; }
|
||||||
|
[JsonPropertyName("theta")]
|
||||||
|
public double Theta { get; set; }
|
||||||
|
[JsonPropertyName("smr")]
|
||||||
|
public double Smr { get; set; }
|
||||||
|
[JsonPropertyName("muWave")]
|
||||||
|
public double MuWave { get; set; }
|
||||||
|
[JsonPropertyName("artifact")]
|
||||||
|
public bool Artifact { get; set; }
|
||||||
|
[JsonPropertyName("signalQuality")]
|
||||||
|
public double SignalQuality { get; set; }
|
||||||
|
[JsonPropertyName("packageIndex")]
|
||||||
|
public long PackageIndex { get; set; }
|
||||||
|
[JsonPropertyName("timeOfDataGenerate")]
|
||||||
|
public DateTime TimeOfDataGenerate { get; set; }
|
||||||
|
|
||||||
|
public JsonData() { }
|
||||||
|
|
||||||
|
public JsonData(Data data)
|
||||||
|
{
|
||||||
|
ConcentrationIndex = data.ConcentrationIndex;
|
||||||
|
RelaxationIndex = data.RelaxationIndex;
|
||||||
|
CognitiveControl = data.CognitiveControl;
|
||||||
|
CognitiveLoad = data.CognitiveLoad;
|
||||||
|
Alpha = data.Alpha;
|
||||||
|
Beta = data.Beta;
|
||||||
|
Theta = data.Theta;
|
||||||
|
Smr = data.Smr;
|
||||||
|
MuWave = data.MuWave;
|
||||||
|
Artifact = data.Artifact;
|
||||||
|
SignalQuality = data.SignalQuality;
|
||||||
|
PackageIndex = data.PackageIndex;
|
||||||
|
TimeOfDataGenerate = data.TimeOfDataGenerate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Data ToData()
|
||||||
|
{
|
||||||
|
return new Data(
|
||||||
|
ConcentrationIndex,
|
||||||
|
RelaxationIndex,
|
||||||
|
CognitiveControl,
|
||||||
|
CognitiveLoad,
|
||||||
|
Alpha,
|
||||||
|
Beta,
|
||||||
|
Theta,
|
||||||
|
Smr,
|
||||||
|
MuWave,
|
||||||
|
Artifact,
|
||||||
|
SignalQuality,
|
||||||
|
PackageIndex,
|
||||||
|
TimeOfDataGenerate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
72
Domain/Dto/MessagePackData.cs
Normal file
72
Domain/Dto/MessagePackData.cs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
namespace Domain.Dto;
|
||||||
|
|
||||||
|
using MessagePack;
|
||||||
|
|
||||||
|
[MessagePackObject]
|
||||||
|
public class MessagePackData
|
||||||
|
{
|
||||||
|
[Key("concentrationIndex")]
|
||||||
|
public double ConcentrationIndex { get; set; }
|
||||||
|
[Key("relaxationIndex")]
|
||||||
|
public double RelaxationIndex { get; set; }
|
||||||
|
[Key("cognitiveControl")]
|
||||||
|
public double CognitiveControl { get; set; }
|
||||||
|
[Key("cognitiveLoad")]
|
||||||
|
public double CognitiveLoad { get; set; }
|
||||||
|
[Key("alpha")]
|
||||||
|
public double Alpha { get; set; }
|
||||||
|
[Key("beta")]
|
||||||
|
public double Beta { get; set; }
|
||||||
|
[Key("theta")]
|
||||||
|
public double Theta { get; set; }
|
||||||
|
[Key("smr")]
|
||||||
|
public double Smr { get; set; }
|
||||||
|
[Key("muWave")]
|
||||||
|
public double MuWave { get; set; }
|
||||||
|
[Key("artifact")]
|
||||||
|
public bool Artifact { get; set; }
|
||||||
|
[Key("signalQuality")]
|
||||||
|
public double SignalQuality { get; set; }
|
||||||
|
[Key("packageIndex")]
|
||||||
|
public long PackageIndex { get; set; }
|
||||||
|
[Key("timeOfDataGenerate")]
|
||||||
|
public DateTime TimeOfDataGenerate { get; set; }
|
||||||
|
|
||||||
|
public MessagePackData() { }
|
||||||
|
|
||||||
|
public MessagePackData(Data data)
|
||||||
|
{
|
||||||
|
ConcentrationIndex = data.ConcentrationIndex;
|
||||||
|
RelaxationIndex = data.RelaxationIndex;
|
||||||
|
CognitiveControl = data.CognitiveControl;
|
||||||
|
CognitiveLoad = data.CognitiveLoad;
|
||||||
|
Alpha = data.Alpha;
|
||||||
|
Beta = data.Beta;
|
||||||
|
Theta = data.Theta;
|
||||||
|
Smr = data.Smr;
|
||||||
|
MuWave = data.MuWave;
|
||||||
|
Artifact = data.Artifact;
|
||||||
|
SignalQuality = data.SignalQuality;
|
||||||
|
PackageIndex = data.PackageIndex;
|
||||||
|
TimeOfDataGenerate = data.TimeOfDataGenerate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Data ToData()
|
||||||
|
{
|
||||||
|
return new Data(
|
||||||
|
ConcentrationIndex,
|
||||||
|
RelaxationIndex,
|
||||||
|
CognitiveControl,
|
||||||
|
CognitiveLoad,
|
||||||
|
Alpha,
|
||||||
|
Beta,
|
||||||
|
Theta,
|
||||||
|
Smr,
|
||||||
|
MuWave,
|
||||||
|
Artifact,
|
||||||
|
SignalQuality,
|
||||||
|
PackageIndex,
|
||||||
|
TimeOfDataGenerate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
34
NetworkTest.sln
Normal file
34
NetworkTest.sln
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.0.31903.59
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{A33376EF-FB88-4A2F-A1FD-0F9B0F89B976}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Client\Client.csproj", "{B4ABD6BA-1C0A-49A4-8580-E5A5B9A4DD4D}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Domain", "Domain\Domain.csproj", "{7EFE01A5-B489-4460-988D-E34D6C67711D}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{A33376EF-FB88-4A2F-A1FD-0F9B0F89B976}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A33376EF-FB88-4A2F-A1FD-0F9B0F89B976}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A33376EF-FB88-4A2F-A1FD-0F9B0F89B976}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A33376EF-FB88-4A2F-A1FD-0F9B0F89B976}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B4ABD6BA-1C0A-49A4-8580-E5A5B9A4DD4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B4ABD6BA-1C0A-49A4-8580-E5A5B9A4DD4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B4ABD6BA-1C0A-49A4-8580-E5A5B9A4DD4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B4ABD6BA-1C0A-49A4-8580-E5A5B9A4DD4D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7EFE01A5-B489-4460-988D-E34D6C67711D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7EFE01A5-B489-4460-988D-E34D6C67711D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7EFE01A5-B489-4460-988D-E34D6C67711D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7EFE01A5-B489-4460-988D-E34D6C67711D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
88
Server/DataGenerator.cs
Normal file
88
Server/DataGenerator.cs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Domain;
|
||||||
|
|
||||||
|
namespace Server;
|
||||||
|
|
||||||
|
public class DataGenerator
|
||||||
|
{
|
||||||
|
private static readonly Random _random = new Random();
|
||||||
|
|
||||||
|
private readonly int _minNewPackages;
|
||||||
|
private readonly int _maxPreviousPackages;
|
||||||
|
private readonly TimeSpan _generationInterval;
|
||||||
|
private readonly LinkedList<Data> _cache = new LinkedList<Data>();
|
||||||
|
private readonly ConcurrentDictionary<long, Data> _dict = [];
|
||||||
|
private readonly object _lock = new object();
|
||||||
|
private long _maxRequestedIndex = 0;
|
||||||
|
private Task _generationTask;
|
||||||
|
private CancellationTokenSource _cts = new();
|
||||||
|
|
||||||
|
public DataGenerator(int minNewPackages = 50, int maxPreviousPackages = 50, TimeSpan? generationInterval = null)
|
||||||
|
{
|
||||||
|
_minNewPackages = Math.Max(minNewPackages, 5);
|
||||||
|
_maxPreviousPackages = Math.Max(maxPreviousPackages, 5);
|
||||||
|
_generationInterval = generationInterval ?? TimeSpan.FromSeconds(1);
|
||||||
|
_generationTask = Task.Run(() => GenerateInBackground(_cts.Token));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateInBackground(CancellationToken token)
|
||||||
|
{
|
||||||
|
var firstData = GenerateRandomData(0);
|
||||||
|
_cache.AddLast(firstData);
|
||||||
|
_dict[firstData.PackageIndex] = firstData;
|
||||||
|
|
||||||
|
while (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
//await Task.Delay(_generationInterval, token);
|
||||||
|
var first = _cache.First!.Value;
|
||||||
|
var last = _cache.Last!.Value;
|
||||||
|
if (last.PackageIndex - _maxRequestedIndex < _minNewPackages)
|
||||||
|
{
|
||||||
|
var data = GenerateRandomData(last.PackageIndex + 1);
|
||||||
|
_cache.AddLast(data);
|
||||||
|
_dict[data.PackageIndex] = data;
|
||||||
|
}
|
||||||
|
if (_maxRequestedIndex - first.PackageIndex > _maxPreviousPackages)
|
||||||
|
{
|
||||||
|
_cache.RemoveFirst();
|
||||||
|
_dict.TryRemove(first.PackageIndex, out _);
|
||||||
|
}
|
||||||
|
//System.Console.WriteLine($"[{first.PackageIndex}; {last.PackageIndex}]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Data? GetPackage(long packageIndex)
|
||||||
|
{
|
||||||
|
var res = _dict.TryGetValue(packageIndex, out var value);
|
||||||
|
_maxRequestedIndex = Math.Max(_maxRequestedIndex, packageIndex);
|
||||||
|
return res ? value : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Data GenerateRandomData(long packageNumber)
|
||||||
|
{
|
||||||
|
var alpha = _random.NextDouble();
|
||||||
|
var beta = _random.NextDouble() * (1 - alpha);
|
||||||
|
var theta = 1 - alpha - beta;
|
||||||
|
var signalQuality = _random.NextDouble();
|
||||||
|
|
||||||
|
return new Data(
|
||||||
|
ConcentrationIndex: _random.NextDouble(),
|
||||||
|
RelaxationIndex: _random.NextDouble(),
|
||||||
|
CognitiveControl: _random.NextDouble(),
|
||||||
|
CognitiveLoad: _random.NextDouble(),
|
||||||
|
Alpha: alpha,
|
||||||
|
Beta: beta,
|
||||||
|
Theta: theta,
|
||||||
|
Smr: _random.NextDouble(),
|
||||||
|
MuWave: _random.NextDouble(),
|
||||||
|
Artifact: signalQuality < 0.5,
|
||||||
|
SignalQuality: signalQuality,
|
||||||
|
PackageIndex: packageNumber,
|
||||||
|
TimeOfDataGenerate: DateTime.Now
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
105
Server/HttpServer.cs
Normal file
105
Server/HttpServer.cs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Domain;
|
||||||
|
using Domain.Dto;
|
||||||
|
|
||||||
|
namespace NetworkTest;
|
||||||
|
|
||||||
|
public class HttpServer : IServer
|
||||||
|
{
|
||||||
|
private readonly HttpListener _listener;
|
||||||
|
private readonly string _url;
|
||||||
|
private CancellationTokenSource _cts = new CancellationTokenSource();
|
||||||
|
private Func<long, Data?> _getData;
|
||||||
|
private Action<Data, HttpListenerResponse> _writeResponse;
|
||||||
|
|
||||||
|
public HttpServer(Func<long, Data?> getData, Action<Data, HttpListenerResponse> writeResponse, string url = "http://*:5555/")
|
||||||
|
{
|
||||||
|
_getData = getData;
|
||||||
|
_writeResponse = writeResponse;
|
||||||
|
_url = url;
|
||||||
|
_listener = new HttpListener();
|
||||||
|
_listener.Prefixes.Add(_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
_cts = new CancellationTokenSource();
|
||||||
|
_listener.Start();
|
||||||
|
Task.Run(() => ListenAsync(_cts.Token));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
_cts.Cancel();
|
||||||
|
_listener.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ListenAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
while (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var context = await _listener.GetContextAsync();
|
||||||
|
_ = Task.Run(() => HandleRequest(context));
|
||||||
|
}
|
||||||
|
catch (HttpListenerException)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleRequest(HttpListenerContext context)
|
||||||
|
{
|
||||||
|
if (context.Request.Url?.AbsolutePath.Equals("/fetchpackage", StringComparison.OrdinalIgnoreCase) == true)
|
||||||
|
{
|
||||||
|
string? indexStr = context.Request.QueryString["index"];
|
||||||
|
if (indexStr != null && long.TryParse(indexStr, out long index))
|
||||||
|
{
|
||||||
|
var data = _getData(index);
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
_writeResponse(data, context.Response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var responseText = JsonSerializer.Serialize(new { error = "Data not found" });
|
||||||
|
context.Response.StatusCode = 404;
|
||||||
|
byte[] buffer = Encoding.UTF8.GetBytes(responseText);
|
||||||
|
context.Response.ContentType = "application/json";
|
||||||
|
context.Response.ContentLength64 = buffer.Length;
|
||||||
|
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 400;
|
||||||
|
byte[] buffer = Encoding.UTF8.GetBytes("Invalid or missing 'index' parameter.");
|
||||||
|
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 404;
|
||||||
|
byte[] buffer = Encoding.UTF8.GetBytes("Not Found");
|
||||||
|
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
context.Response.OutputStream.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"HTTP: [{string.Join(", ", _listener.Prefixes)}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
8
Server/IServer.cs
Normal file
8
Server/IServer.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace NetworkTest;
|
||||||
|
|
||||||
|
interface IServer
|
||||||
|
{
|
||||||
|
public void Start();
|
||||||
|
public void Stop();
|
||||||
|
|
||||||
|
}
|
||||||
111
Server/Program.cs
Normal file
111
Server/Program.cs
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Domain;
|
||||||
|
using Domain.Dto;
|
||||||
|
using MessagePack;
|
||||||
|
using NetworkTest;
|
||||||
|
using Server;
|
||||||
|
|
||||||
|
if (args.Length < 2)
|
||||||
|
{
|
||||||
|
System.Console.WriteLine("Pass twp arg: test/http/tcp and json/bin");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dataGenerator = new DataGenerator(generationInterval: TimeSpan.FromMilliseconds(1));
|
||||||
|
|
||||||
|
var protocol = args[0];
|
||||||
|
var serialization = args[1];
|
||||||
|
|
||||||
|
if (protocol == "test")
|
||||||
|
{
|
||||||
|
int nullCount = 0;
|
||||||
|
long index = 0;
|
||||||
|
var sw = Stopwatch.StartNew();
|
||||||
|
var lastMs = 0L;
|
||||||
|
var lastIndex = 0L;
|
||||||
|
var ms = 1000;
|
||||||
|
|
||||||
|
var json = serialization == "json";
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var data = dataGenerator.GetPackage(index);
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
nullCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json)
|
||||||
|
{
|
||||||
|
JsonData jsonData = new JsonData(data);
|
||||||
|
var responseText = JsonSerializer.Serialize(jsonData);
|
||||||
|
byte[] buffer = Encoding.UTF8.GetBytes(responseText);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessagePackData msgPackData = new MessagePackData(data);
|
||||||
|
byte[] buffer = MessagePackSerializer.Serialize(msgPackData);
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
|
||||||
|
var diff = sw.ElapsedMilliseconds - lastMs;
|
||||||
|
if (diff >= ms)
|
||||||
|
{
|
||||||
|
var serializrd = index - lastIndex;
|
||||||
|
System.Console.WriteLine($"Serialized {serializrd} data packages in {diff} ms.");
|
||||||
|
lastIndex = index;
|
||||||
|
lastMs = sw.ElapsedMilliseconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IServer? server = protocol == "http" ?
|
||||||
|
new HttpServer(index => dataGenerator.GetPackage(index),
|
||||||
|
serialization == "json" ? PrepareResponseJson : PrepareResponseMessagePack) :
|
||||||
|
null;
|
||||||
|
|
||||||
|
server?.Start();
|
||||||
|
System.Console.WriteLine("Server started:");
|
||||||
|
System.Console.WriteLine(server);
|
||||||
|
|
||||||
|
// Обработка выхода по Ctrl+C
|
||||||
|
Console.CancelKeyPress += (sender, e) =>
|
||||||
|
{
|
||||||
|
e.Cancel = true; // Prevent immediate termination
|
||||||
|
Console.WriteLine("Shutdown signal received. Stopping server...");
|
||||||
|
server?.Stop();
|
||||||
|
Console.WriteLine("Goodbye!");
|
||||||
|
Environment.Exit(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Бесконечный цикл ожидания
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PrepareResponseJson(Data data, HttpListenerResponse response)
|
||||||
|
{
|
||||||
|
JsonData jsonData = new JsonData(data);
|
||||||
|
var responseText = JsonSerializer.Serialize(jsonData);
|
||||||
|
byte[] buffer = Encoding.UTF8.GetBytes(responseText);
|
||||||
|
response.ContentType = "application/json";
|
||||||
|
response.ContentLength64 = buffer.Length;
|
||||||
|
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrepareResponseMessagePack(Data data, HttpListenerResponse response)
|
||||||
|
{
|
||||||
|
MessagePackData msgPackData = new MessagePackData(data);
|
||||||
|
byte[] buffer = MessagePackSerializer.Serialize(msgPackData);
|
||||||
|
response.ContentType = "application/x-msgpack";
|
||||||
|
response.ContentLength64 = buffer.Length;
|
||||||
|
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
|
||||||
18
Server/Server.csproj
Normal file
18
Server/Server.csproj
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../Domain/Domain.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MessagePack" Version="3.1.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Reference in New Issue
Block a user