From 0e37a2ec38967c24d31ea48f46177b83f1d4a6c1 Mon Sep 17 00:00:00 2001 From: to-0 Date: Thu, 17 Aug 2023 16:15:10 +0200 Subject: [PATCH 01/55] Addes signalR service and wwwroot folder in presentation service --- cppseminar/docker-compose.yml | 27 +++++++++++++ cppseminar/monitoringservice/Dockerfile | 22 +++++++++++ .../monitoringservice/Hubs/MonitoringHub.cs | 12 ++++++ cppseminar/monitoringservice/Program.cs | 30 ++++++++++++++ .../Properties/launchSettings.json | 37 ++++++++++++++++++ cppseminar/monitoringservice/Services/Test.cs | 0 .../appsettings.Development.json | 9 +++++ cppseminar/monitoringservice/appsettings.json | 9 +++++ .../monitoringservice.csproj | 9 +++++ .../monitoringservice/wwwroot/css/site.css | 22 +++++++++++ .../monitoringservice/wwwroot/favicon.ico | Bin 0 -> 5430 bytes .../monitoringservice/wwwroot/js/site.js | 4 ++ cppseminar/presentation/Startup.cs | 1 + 13 files changed, 182 insertions(+) create mode 100644 cppseminar/monitoringservice/Dockerfile create mode 100644 cppseminar/monitoringservice/Hubs/MonitoringHub.cs create mode 100644 cppseminar/monitoringservice/Program.cs create mode 100644 cppseminar/monitoringservice/Properties/launchSettings.json create mode 100644 cppseminar/monitoringservice/Services/Test.cs create mode 100644 cppseminar/monitoringservice/appsettings.Development.json create mode 100644 cppseminar/monitoringservice/appsettings.json create mode 100644 cppseminar/monitoringservice/monitoringservice.csproj create mode 100644 cppseminar/monitoringservice/wwwroot/css/site.css create mode 100644 cppseminar/monitoringservice/wwwroot/favicon.ico create mode 100644 cppseminar/monitoringservice/wwwroot/js/site.js diff --git a/cppseminar/docker-compose.yml b/cppseminar/docker-compose.yml index f84685fd..8346ae61 100644 --- a/cppseminar/docker-compose.yml +++ b/cppseminar/docker-compose.yml @@ -38,6 +38,7 @@ services: - ./presentation/Model:/src/Model - ./presentation/Pages:/src/Pages - ./presentation/Services:/src/Services + - ./presentation/wwwroot:/src/wwwroot networks: - sharednet ports: @@ -261,6 +262,32 @@ services: - ./envoy/envoy.yaml:/etc/envoy/envoy.yaml networks: - sharednet + + monitoringservice.local: + build: + context: ./monitoringservice + target: dev + volumes: + - ./monitoringservice/Program.cs:/src/Program.cs + - ./monitoringservice/Model:/src/Model + - ./monitoringservice/Services:/src/Services + networks: + - sharednet + ports: + - 8525:8525 + environment: + DOTNET_USE_POLLING_FILE_WATCHER: 1 + DOTNET_WATCH_SUPPRESS_MSBUILD_INCREMENTALISM: 1 + DOTNET_WATCH_SUPPRESS_LAUNCH_BROWSER: 1 + DOTNET_WATCH_SUPPRESS_BROWSER_REFRESH: 1 + ASPNETCORE_ENVIRONMENT: Development + LINKS_CURRENT_DOCS: https://example.com/ + API_GATEWAY: http://gateway.local:5000/ + LOG_PRETTY: 1 + restart: always + depends_on: + - rabbitmq.local + networks: diff --git a/cppseminar/monitoringservice/Dockerfile b/cppseminar/monitoringservice/Dockerfile new file mode 100644 index 00000000..9e09b877 --- /dev/null +++ b/cppseminar/monitoringservice/Dockerfile @@ -0,0 +1,22 @@ +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +WORKDIR /app +EXPOSE 90 + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src +COPY ["monitoringservice.csproj", "./monitoringservice.csproj"] +RUN dotnet restore "monitoringservice.csproj" +COPY . . +RUN dotnet build "monitoringservice.csproj" -c Release -o /app/build + +FROM build as dev +EXPOSE 8525 +CMD dotnet watch run --urls=http://0.0.0.0:8525 + +FROM build AS publish +RUN dotnet publish "monitoringservice.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "monitoringservice.dll"] diff --git a/cppseminar/monitoringservice/Hubs/MonitoringHub.cs b/cppseminar/monitoringservice/Hubs/MonitoringHub.cs new file mode 100644 index 00000000..bf5e6ccf --- /dev/null +++ b/cppseminar/monitoringservice/Hubs/MonitoringHub.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.SignalR; + +namespace MonitoringService.Hubs +{ + public class MonitoringHub : Hub + { + public async Task SendMessage(string user, string message) + { + await Clients.All.SendAsync("ReceiveMessage", user, message); + } + } +} \ No newline at end of file diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs new file mode 100644 index 00000000..b5a56752 --- /dev/null +++ b/cppseminar/monitoringservice/Program.cs @@ -0,0 +1,30 @@ +using MonitoringService.Hubs; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +//builder.Services.AddRazorPages(); +builder.Services.AddSignalR(); + +var app = builder.Build(); + + +// Configure the HTTP request pipeline. +if (!app.Environment.IsDevelopment()) +{ + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); +} + +app.UseHttpsRedirection(); +app.UseStaticFiles(); + +app.UseRouting(); + +app.UseAuthorization(); + +//app.MapRazorPages(); +app.MapHub("/monitor"); + +app.Run(); diff --git a/cppseminar/monitoringservice/Properties/launchSettings.json b/cppseminar/monitoringservice/Properties/launchSettings.json new file mode 100644 index 00000000..06f09cec --- /dev/null +++ b/cppseminar/monitoringservice/Properties/launchSettings.json @@ -0,0 +1,37 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:9271", + "sslPort": 44364 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:5224", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7026;http://localhost:5224", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/cppseminar/monitoringservice/Services/Test.cs b/cppseminar/monitoringservice/Services/Test.cs new file mode 100644 index 00000000..e69de29b diff --git a/cppseminar/monitoringservice/appsettings.Development.json b/cppseminar/monitoringservice/appsettings.Development.json new file mode 100644 index 00000000..770d3e93 --- /dev/null +++ b/cppseminar/monitoringservice/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "DetailedErrors": true, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/cppseminar/monitoringservice/appsettings.json b/cppseminar/monitoringservice/appsettings.json new file mode 100644 index 00000000..10f68b8c --- /dev/null +++ b/cppseminar/monitoringservice/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/cppseminar/monitoringservice/monitoringservice.csproj b/cppseminar/monitoringservice/monitoringservice.csproj new file mode 100644 index 00000000..c78c9c7e --- /dev/null +++ b/cppseminar/monitoringservice/monitoringservice.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/cppseminar/monitoringservice/wwwroot/css/site.css b/cppseminar/monitoringservice/wwwroot/css/site.css new file mode 100644 index 00000000..f8d98fcb --- /dev/null +++ b/cppseminar/monitoringservice/wwwroot/css/site.css @@ -0,0 +1,22 @@ +html { + font-size: 14px; +} + +@media (min-width: 768px) { + html { + font-size: 16px; + } +} + +.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { + box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; +} + +html { + position: relative; + min-height: 100%; +} + +body { + margin-bottom: 60px; +} \ No newline at end of file diff --git a/cppseminar/monitoringservice/wwwroot/favicon.ico b/cppseminar/monitoringservice/wwwroot/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..63e859b476eff5055e0e557aaa151ca8223fbeef GIT binary patch literal 5430 zcmc&&Yj2xp8Fqnv;>&(QB_ve7>^E#o2mu=cO~A%R>DU-_hfbSRv1t;m7zJ_AMrntN zy0+^f&8be>q&YYzH%(88lQ?#KwiCzaCO*ZEo%j&v;<}&Lj_stKTKK>#U3nin@AF>w zb3ONSAFR{u(S1d?cdw53y}Gt1b-Hirbh;;bm(Rcbnoc*%@jiaXM|4jU^1WO~`TYZ~ zC-~jh9~b-f?fX`DmwvcguQzn*uV}c^Vd&~?H|RUs4Epv~gTAfR(B0lT&?RWQOtduM z^1vUD9{HQsW!{a9|0crA34m7Z6lpG^}f6f?={zD+ zXAzk^i^aKN_}s2$eX81wjSMONE#WVdzf|MT)Ap*}Vsn!XbvsI#6o&ij{87^d%$|A{ z=F{KB%)g%@z76yBzbb7seW**Ju8r4e*Z3PWNX3_tTDgzZatz7)Q6ytwB%@&@A|XT; zecM`Snxx5po$C)%yCP!KEtos~eOS)@2=kX-RIm)4glMCoagTEFxrBeSX%Euz734Fk z%7)x(k~T!@Hbg_37NSQL!vlTBXoURSzt~I**Zw`&F24fH*&kx=%nvZv|49SC*daD( zIw<~%#=lk8{2-l(BcIjy^Q$Q&m#KlWL9?UG{b8@qhlD z;umc+6p%|NsAT~0@DgV4-NKgQuWPWrmPIK&&XhV&n%`{l zOl^bbWYjQNuVXTXESO)@|iUKVmErPUDfz2Wh`4dF@OFiaCW|d`3paV^@|r^8T_ZxM)Z+$p5qx# z#K=z@%;aBPO=C4JNNGqVv6@UGolIz;KZsAro``Rz8X%vq_gpi^qEV&evgHb_=Y9-l z`)imdx0UC>GWZYj)3+3aKh?zVb}=@%oNzg7a8%kfVl)SV-Amp1Okw&+hEZ3|v(k8vRjXW9?ih`&FFM zV$~{j3IzhtcXk?Mu_!12;=+I7XK-IR2>Yd%VB^?oI9c^E&Chb&&je$NV0P-R;ujkP z;cbLCCPEF6|22NDj=S`F^2e~XwT1ZnRX8ra0#DaFa9-X|8(xNW_+JhD75WnSd7cxo z2>I_J5{c|WPfrgl7E2R)^c}F7ry()Z>$Jhk9CzZxiPKL#_0%`&{MX>P_%b~Dx0D^S z7xP1(DQ!d_Icpk!RN3I1w@~|O1ru#CO==h#9M~S4Chx*@?=EKUPGBv$tmU+7Zs_al z`!jR?6T&Z7(%uVq>#yLu`abWk!FBlnY{RFNHlj~6zh*;@u}+}viRKsD`IIxN#R-X3 z@vxu#EA_m}I503U(8Qmx^}u;)KfGP`O9E1H1Q|xeeksX8jC%@!{YT1)!lWgO=+Y3*jr=iSxvOW1}^HSy=y){tOMQJ@an>sOl4FYniE z;GOxd7AqxZNbYFNqobpv&HVO$c-w!Y*6r;$2oJ~h(a#(Bp<-)dg*mNigX~9rPqcHv z^;c*|Md?tD)$y?6FO$DWl$jUGV`F1G_^E&E>sY*YnA~ruv3=z9F8&&~Xpm<<75?N3 z>x~`I&M9q)O1=zWZHN9hZWx>RQ}zLP+iL57Q)%&_^$Sme^^G7;e-P~CR?kqU#Io#( z(nH1Wn*Ig)|M>WLGrxoU?FZrS`4GO&w;+39A3f8w{{Q7eg|$+dIlNFPAe+tN=FOYU z{A&Fg|H73+w1IK(W=j*L>JQgz$g0 z7JpKXLHIh}#$wm|N`s}o-@|L_`>*(gTQ~)wr3Eap7g%PVNisKw82im;Gdv#85x#s+ zoqqtnwu4ycd>cOQgRh-=aEJbnvVK`}ja%+FZx}&ehtX)n(9nVfe4{mn0bgijUbNr7Tf5X^$*{qh2%`?--%+sbSrjE^;1e3>% zqa%jdY16{Y)a1hSy*mr0JGU05Z%=qlx5vGvTjSpTt6k%nR06q}1DU`SQh_ZAeJ}A@`hL~xvv05U?0%=spP`R>dk?cOWM9^KNb7B?xjex>OZo%JMQQ1Q zB|q@}8RiP@DWn-(fB;phPaIOP2Yp)XN3-Fsn)S3w($4&+p8f5W_f%gac}QvmkHfCj$2=!t`boCvQ zCW;&Dto=f8v##}dy^wg3VNaBy&kCe3N;1|@n@pUaMPT?(aJ9b*(gJ28$}(2qFt$H~u5z94xcIQkcOI++)*exzbrk?WOOOf*|%k5#KV zL=&ky3)Eirv$wbRJ2F2s_ILQY--D~~7>^f}W|Aw^e7inXr#WLI{@h`0|jHud2Y~cI~Yn{r_kU^Vo{1gja Date: Thu, 17 Aug 2023 16:22:14 +0200 Subject: [PATCH 02/55] presentation modified to serve static files in /wwwroot folder + added dummy Connection page --- .gitignore | 3 ++- .../Pages/Connection/Index.cshtml | 16 +++++++++++++++ .../Pages/Connection/Index.cshtml.cs | 20 +++++++++++++++++++ .../presentation/Pages/Shared/_Layout.cshtml | 2 ++ cppseminar/presentation/Startup.cs | 3 +++ cppseminar/presentation/wwwroot/js/script.js | 1 + cppseminar/presentation/wwwroot/test.txt | 1 + 7 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 cppseminar/presentation/Pages/Connection/Index.cshtml create mode 100644 cppseminar/presentation/Pages/Connection/Index.cshtml.cs create mode 100644 cppseminar/presentation/wwwroot/js/script.js create mode 100644 cppseminar/presentation/wwwroot/test.txt diff --git a/.gitignore b/.gitignore index c7184451..f9825327 100644 --- a/.gitignore +++ b/.gitignore @@ -93,6 +93,7 @@ tags *.sublime* *.code* *pyls* +cppseminar/presentation/presentation.sln # From react # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. @@ -123,4 +124,4 @@ yarn-error.log* *.csproj.user # Go bin files -__debug_bin \ No newline at end of file +__debug_bin diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml b/cppseminar/presentation/Pages/Connection/Index.cshtml new file mode 100644 index 00000000..11686189 --- /dev/null +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml @@ -0,0 +1,16 @@ +@page +@model presentation.Pages.Connection.IndexModel +@{ +} + + +@section JavaScript +{ + +} + +
+

Connection checker

+

This page is used to check whether the student is still connected to our network.

+
+ diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs new file mode 100644 index 00000000..e7978044 --- /dev/null +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs @@ -0,0 +1,20 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; +using presentation.Model; +using presentation.Services; +using Microsoft.AspNetCore.Mvc; +using System.Net.Mime; + +namespace presentation.Pages.Connection +{ + public class IndexModel : PageModel + { + private ILogger _logger; + public bool IsAdmin = false; + } +} diff --git a/cppseminar/presentation/Pages/Shared/_Layout.cshtml b/cppseminar/presentation/Pages/Shared/_Layout.cshtml index 4001bbc3..c484dd4a 100644 --- a/cppseminar/presentation/Pages/Shared/_Layout.cshtml +++ b/cppseminar/presentation/Pages/Shared/_Layout.cshtml @@ -31,6 +31,7 @@ + @if (User.IsAdmin()) { @@ -227,5 +228,6 @@ editor.setReadOnly(true) }) + @RenderSection("JavaScript", required: false) diff --git a/cppseminar/presentation/Startup.cs b/cppseminar/presentation/Startup.cs index 1ab9f2da..889c7798 100644 --- a/cppseminar/presentation/Startup.cs +++ b/cppseminar/presentation/Startup.cs @@ -88,11 +88,14 @@ public void ConfigureServices(IServiceCollection services) // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + System.Console.WriteLine(env.ContentRootPath); app.UseForwardedHeaders(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } + + app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); diff --git a/cppseminar/presentation/wwwroot/js/script.js b/cppseminar/presentation/wwwroot/js/script.js new file mode 100644 index 00000000..07b9bc11 --- /dev/null +++ b/cppseminar/presentation/wwwroot/js/script.js @@ -0,0 +1 @@ +alert("Hello") \ No newline at end of file diff --git a/cppseminar/presentation/wwwroot/test.txt b/cppseminar/presentation/wwwroot/test.txt new file mode 100644 index 00000000..faf7da10 --- /dev/null +++ b/cppseminar/presentation/wwwroot/test.txt @@ -0,0 +1 @@ +asdasdasd \ No newline at end of file From 62d26b8431f69ec439713516604b6fea67ba8ba6 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Fri, 18 Aug 2023 11:51:13 +0200 Subject: [PATCH 03/55] added SignalR JS client to presentation + demo message sending --- .gitignore | 1 - cppseminar/docker-compose.yml | 1 + .../monitoringservice/Hubs/MonitoringHub.cs | 14 ++++++ cppseminar/monitoringservice/Program.cs | 14 ++++++ .../monitoringservice/monitoringservice.sln | 25 +++++++++++ .../Pages/Connection/Index.cshtml | 1 + cppseminar/presentation/presentation.sln | 25 +++++++++++ cppseminar/presentation/wwwroot/js/script.js | 44 ++++++++++++++++++- cppseminar/presentation/wwwroot/test.txt | 1 - 9 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 cppseminar/monitoringservice/monitoringservice.sln create mode 100644 cppseminar/presentation/presentation.sln delete mode 100644 cppseminar/presentation/wwwroot/test.txt diff --git a/.gitignore b/.gitignore index f9825327..e4ac8c90 100644 --- a/.gitignore +++ b/.gitignore @@ -93,7 +93,6 @@ tags *.sublime* *.code* *pyls* -cppseminar/presentation/presentation.sln # From react # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. diff --git a/cppseminar/docker-compose.yml b/cppseminar/docker-compose.yml index 8346ae61..d2523472 100644 --- a/cppseminar/docker-compose.yml +++ b/cppseminar/docker-compose.yml @@ -271,6 +271,7 @@ services: - ./monitoringservice/Program.cs:/src/Program.cs - ./monitoringservice/Model:/src/Model - ./monitoringservice/Services:/src/Services + - ./monitoringservice/Hubs:/src/Hubs networks: - sharednet ports: diff --git a/cppseminar/monitoringservice/Hubs/MonitoringHub.cs b/cppseminar/monitoringservice/Hubs/MonitoringHub.cs index bf5e6ccf..10b97932 100644 --- a/cppseminar/monitoringservice/Hubs/MonitoringHub.cs +++ b/cppseminar/monitoringservice/Hubs/MonitoringHub.cs @@ -1,11 +1,25 @@ +using System; using Microsoft.AspNetCore.SignalR; namespace MonitoringService.Hubs { public class MonitoringHub : Hub { + public override Task OnConnectedAsync() + { + System.Console.WriteLine("Client connected " + Context.ConnectionId); + return base.OnConnectedAsync(); + } + + public override async Task OnDisconnectedAsync(Exception? exception) + { + System.Console.WriteLine("Client disconnected " + Context.ConnectionId); + await base.OnDisconnectedAsync(exception); + } + public async Task SendMessage(string user, string message) { + System.Console.WriteLine("SendMessage: " + user + " " + message); await Clients.All.SendAsync("ReceiveMessage", user, message); } } diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs index b5a56752..3ed8ebc1 100644 --- a/cppseminar/monitoringservice/Program.cs +++ b/cppseminar/monitoringservice/Program.cs @@ -6,6 +6,18 @@ //builder.Services.AddRazorPages(); builder.Services.AddSignalR(); +builder.Services.AddCors(options => +{ + options.AddDefaultPolicy( + builder => + { + builder.WithOrigins("http://localhost:8080") + .AllowAnyHeader() + .AllowAnyMethod() + .AllowCredentials(); + }); +}); + var app = builder.Build(); @@ -24,6 +36,8 @@ app.UseAuthorization(); +app.UseCors(); + //app.MapRazorPages(); app.MapHub("/monitor"); diff --git a/cppseminar/monitoringservice/monitoringservice.sln b/cppseminar/monitoringservice/monitoringservice.sln new file mode 100644 index 00000000..b91aac89 --- /dev/null +++ b/cppseminar/monitoringservice/monitoringservice.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "monitoringservice", "monitoringservice.csproj", "{6171F750-7572-4231-BBCB-E02126110C75}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6171F750-7572-4231-BBCB-E02126110C75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6171F750-7572-4231-BBCB-E02126110C75}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6171F750-7572-4231-BBCB-E02126110C75}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6171F750-7572-4231-BBCB-E02126110C75}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {872C4702-FDF5-4978-9622-6EB9E0F6CC23} + EndGlobalSection +EndGlobal diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml b/cppseminar/presentation/Pages/Connection/Index.cshtml index 11686189..8200c3d5 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml @@ -6,6 +6,7 @@ @section JavaScript { + } diff --git a/cppseminar/presentation/presentation.sln b/cppseminar/presentation/presentation.sln new file mode 100644 index 00000000..c959c73d --- /dev/null +++ b/cppseminar/presentation/presentation.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "presentation", "presentation.csproj", "{C100687D-FF4D-4476-B381-B62D5AD7B541}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C100687D-FF4D-4476-B381-B62D5AD7B541}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C100687D-FF4D-4476-B381-B62D5AD7B541}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C100687D-FF4D-4476-B381-B62D5AD7B541}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C100687D-FF4D-4476-B381-B62D5AD7B541}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {383FF98E-0479-4F28-AEB2-FB2182030969} + EndGlobalSection +EndGlobal diff --git a/cppseminar/presentation/wwwroot/js/script.js b/cppseminar/presentation/wwwroot/js/script.js index 07b9bc11..0ca1522a 100644 --- a/cppseminar/presentation/wwwroot/js/script.js +++ b/cppseminar/presentation/wwwroot/js/script.js @@ -1 +1,43 @@ -alert("Hello") \ No newline at end of file +console.log("This is the start of the script.js..."); + +const connection = new signalR.HubConnectionBuilder() + .withUrl("http://localhost:8525/monitor") + .configureLogging(signalR.LogLevel.Information) + .build(); + +async function start() { + try { + await connection.start(); + console.log("SignalR Connected."); + } + catch (err) { + console.log(err); + setTimeout(start, 5000); + } +}; + +connection.onclose(async () => { + console.log("Connection closed."); + await start(); +}); + +// Define the ReceiveMessage method so that it can be triggered from the Hub +connection.on("ReceiveMessage", (user, message) => { + console.log("ReceiveMessage():", user, message); +}); + +async function main() { + console.log("We are in main."); + + // Start the connection. + await start(); + + // Invoke SendMessage on the Hub + try { + await connection.invoke("SendMessage", "user123-TODO", "This is a message " + (new Date).getMilliseconds()); + } catch (err) { + console.error(err); + } +} + +main(); \ No newline at end of file diff --git a/cppseminar/presentation/wwwroot/test.txt b/cppseminar/presentation/wwwroot/test.txt deleted file mode 100644 index faf7da10..00000000 --- a/cppseminar/presentation/wwwroot/test.txt +++ /dev/null @@ -1 +0,0 @@ -asdasdasd \ No newline at end of file From 667f76788fb306db33ce6d224e1db06a01e5b139 Mon Sep 17 00:00:00 2001 From: to-0 Date: Mon, 21 Aug 2023 12:15:17 +0200 Subject: [PATCH 04/55] Moved monitoring service to presentation service. --- cppseminar/docker-compose.yml | 1 + .../Hubs/MonitoringHub.cs | 5 +++-- cppseminar/presentation/Program.cs | 1 + cppseminar/presentation/Startup.cs | 5 +++++ cppseminar/presentation/wwwroot/js/script.js | 2 +- 5 files changed, 11 insertions(+), 3 deletions(-) rename cppseminar/{monitoringservice => presentation}/Hubs/MonitoringHub.cs (88%) diff --git a/cppseminar/docker-compose.yml b/cppseminar/docker-compose.yml index d2523472..1f91b9c9 100644 --- a/cppseminar/docker-compose.yml +++ b/cppseminar/docker-compose.yml @@ -39,6 +39,7 @@ services: - ./presentation/Pages:/src/Pages - ./presentation/Services:/src/Services - ./presentation/wwwroot:/src/wwwroot + - ./presentation/Hubs:/src/Hubs networks: - sharednet ports: diff --git a/cppseminar/monitoringservice/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs similarity index 88% rename from cppseminar/monitoringservice/Hubs/MonitoringHub.cs rename to cppseminar/presentation/Hubs/MonitoringHub.cs index 10b97932..056ded37 100644 --- a/cppseminar/monitoringservice/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -1,9 +1,10 @@ using System; using Microsoft.AspNetCore.SignalR; +using System.Threading.Tasks; -namespace MonitoringService.Hubs +namespace presentation.Hubs { - public class MonitoringHub : Hub + public class MonitoringHub: Hub { public override Task OnConnectedAsync() { diff --git a/cppseminar/presentation/Program.cs b/cppseminar/presentation/Program.cs index 9097242f..39db39db 100644 --- a/cppseminar/presentation/Program.cs +++ b/cppseminar/presentation/Program.cs @@ -41,6 +41,7 @@ public static IHostBuilder CreateHostBuilder(string[] args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); + }); } return Host.CreateDefaultBuilder(args) diff --git a/cppseminar/presentation/Startup.cs b/cppseminar/presentation/Startup.cs index 889c7798..d42210b1 100644 --- a/cppseminar/presentation/Startup.cs +++ b/cppseminar/presentation/Startup.cs @@ -13,6 +13,7 @@ using System; using presentation.Services; +using presentation.Hubs; namespace presentation { @@ -30,6 +31,8 @@ public void ConfigureServices(IServiceCollection services) services.AddRazorPages(opts => { opts.Conventions.AuthorizeFolder("/Admin", "Administrator"); }); + // modified this + services.AddSignalR(); services.Configure(options => { options.AppendTrailingSlash = true; @@ -103,8 +106,10 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); + endpoints.MapHub("/monitor"); }); app.UseStaticFiles(); + } } } diff --git a/cppseminar/presentation/wwwroot/js/script.js b/cppseminar/presentation/wwwroot/js/script.js index 0ca1522a..6c46cb8f 100644 --- a/cppseminar/presentation/wwwroot/js/script.js +++ b/cppseminar/presentation/wwwroot/js/script.js @@ -1,7 +1,7 @@ console.log("This is the start of the script.js..."); const connection = new signalR.HubConnectionBuilder() - .withUrl("http://localhost:8525/monitor") + .withUrl("/monitor") .configureLogging(signalR.LogLevel.Information) .build(); From 1975d093a940fd0bf891a4d80934dcfc065e5894 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Mon, 21 Aug 2023 12:24:37 +0200 Subject: [PATCH 05/55] Redis service + modified monitoring service --- cppseminar/docker-compose.yml | 17 +++++++++----- cppseminar/monitoringservice/Program.cs | 22 ------------------- .../Pages/Connection/Index.cshtml | 1 + cppseminar/presentation/wwwroot/js/script.js | 15 ++++++------- 4 files changed, 20 insertions(+), 35 deletions(-) diff --git a/cppseminar/docker-compose.yml b/cppseminar/docker-compose.yml index 1f91b9c9..f3649455 100644 --- a/cppseminar/docker-compose.yml +++ b/cppseminar/docker-compose.yml @@ -264,6 +264,16 @@ services: networks: - sharednet + redis.local: + image: redis:7.2.0 + build: + target: dev + networks: + - sharednet + ports: + - 6379:6379 + restart: always + monitoringservice.local: build: context: ./monitoringservice @@ -272,11 +282,10 @@ services: - ./monitoringservice/Program.cs:/src/Program.cs - ./monitoringservice/Model:/src/Model - ./monitoringservice/Services:/src/Services - - ./monitoringservice/Hubs:/src/Hubs networks: - sharednet ports: - - 8525:8525 + - 8085:80 environment: DOTNET_USE_POLLING_FILE_WATCHER: 1 DOTNET_WATCH_SUPPRESS_MSBUILD_INCREMENTALISM: 1 @@ -288,9 +297,7 @@ services: LOG_PRETTY: 1 restart: always depends_on: - - rabbitmq.local - - + - redis.local networks: sharednet: diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs index 3ed8ebc1..5f12b0bd 100644 --- a/cppseminar/monitoringservice/Program.cs +++ b/cppseminar/monitoringservice/Program.cs @@ -3,24 +3,8 @@ var builder = WebApplication.CreateBuilder(args); // Add services to the container. -//builder.Services.AddRazorPages(); -builder.Services.AddSignalR(); - -builder.Services.AddCors(options => -{ - options.AddDefaultPolicy( - builder => - { - builder.WithOrigins("http://localhost:8080") - .AllowAnyHeader() - .AllowAnyMethod() - .AllowCredentials(); - }); -}); - var app = builder.Build(); - // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { @@ -30,15 +14,9 @@ } app.UseHttpsRedirection(); -app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); -app.UseCors(); - -//app.MapRazorPages(); -app.MapHub("/monitor"); - app.Run(); diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml b/cppseminar/presentation/Pages/Connection/Index.cshtml index 8200c3d5..8fadd4b9 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml @@ -13,5 +13,6 @@

Connection checker

This page is used to check whether the student is still connected to our network.

+ Send message
diff --git a/cppseminar/presentation/wwwroot/js/script.js b/cppseminar/presentation/wwwroot/js/script.js index 6c46cb8f..0ab94184 100644 --- a/cppseminar/presentation/wwwroot/js/script.js +++ b/cppseminar/presentation/wwwroot/js/script.js @@ -1,5 +1,3 @@ -console.log("This is the start of the script.js..."); - const connection = new signalR.HubConnectionBuilder() .withUrl("/monitor") .configureLogging(signalR.LogLevel.Information) @@ -26,18 +24,19 @@ connection.on("ReceiveMessage", (user, message) => { console.log("ReceiveMessage():", user, message); }); -async function main() { - console.log("We are in main."); - - // Start the connection. - await start(); - +async function invokeSendMessage() { // Invoke SendMessage on the Hub try { await connection.invoke("SendMessage", "user123-TODO", "This is a message " + (new Date).getMilliseconds()); } catch (err) { console.error(err); } + return false; +} + +async function main() { + // Start the connection. + await start(); } main(); \ No newline at end of file From f729b10e114737af169aa3c62a41e0ef659bf4ad Mon Sep 17 00:00:00 2001 From: to-0 Date: Mon, 21 Aug 2023 17:23:50 +0200 Subject: [PATCH 06/55] Testing admin requests to receive list of connected users --- .../Controllers/MonitoringController.cs | 51 +++++++++++++++++++ cppseminar/presentation/Hubs/MonitoringHub.cs | 13 +++++ .../presentation/Model/ConnectionLog.cs | 19 +++++++ .../Pages/Admin/Monitoring/Index.cshtml | 34 +++++++++++++ .../Pages/Admin/Monitoring/Index.cshtml.cs | 31 +++++++++++ .../Pages/Connection/Index.cshtml | 10 +++- .../Pages/Connection/Index.cshtml.cs | 1 - .../presentation/Pages/Shared/_Layout.cshtml | 1 + .../Services/MonitoringService.cs | 43 ++++++++++++++++ cppseminar/presentation/Startup.cs | 10 ++++ .../wwwroot/js/monitoring_admin.js | 47 +++++++++++++++++ cppseminar/presentation/wwwroot/js/script.js | 4 +- 12 files changed, 261 insertions(+), 3 deletions(-) create mode 100644 cppseminar/presentation/Controllers/MonitoringController.cs create mode 100644 cppseminar/presentation/Model/ConnectionLog.cs create mode 100644 cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml create mode 100644 cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs create mode 100644 cppseminar/presentation/Services/MonitoringService.cs create mode 100644 cppseminar/presentation/wwwroot/js/monitoring_admin.js diff --git a/cppseminar/presentation/Controllers/MonitoringController.cs b/cppseminar/presentation/Controllers/MonitoringController.cs new file mode 100644 index 00000000..0c6ca227 --- /dev/null +++ b/cppseminar/presentation/Controllers/MonitoringController.cs @@ -0,0 +1,51 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading.Tasks; +using presentation.Services; +using presentation.Model; + +namespace presentation.Controllers +{ + [Route("monitoring")] + [ApiController] + public class MonitoringController : ControllerBase + { + private readonly ILogger _logger; + private readonly MonitoringService _monitoringService; + + public MonitoringController(ILogger logger, MonitoringService monitoringService) + { + _logger = logger; + _monitoringService = monitoringService; + } + + [HttpGet] + public async Task>> OnGet() + { + if(!User.IsAdmin()){ + System.Console.WriteLine("Unauthorized request"); + return StatusCode(401); + } + System.Console.WriteLine("caf a fsdfasdfsfsdf"); + + + try + { + var connectionLog = await _monitoringService.Test(); + return connectionLog; + } + catch (Exception e) + { + _logger.LogWarning("Error during retrieval of data, {e}", e); + return StatusCode(500); // Internal error + } + } + + + } +} + + diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index 056ded37..abcd1ac8 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -1,11 +1,19 @@ using System; using Microsoft.AspNetCore.SignalR; using System.Threading.Tasks; +using Microsoft.AspNetCore.Http.Features; +using presentation.Services; +using presentation.Model; + namespace presentation.Hubs { public class MonitoringHub: Hub { + private MonitoringService _monitoringService; + public MonitoringHub(MonitoringService monitoringService){ + _monitoringService = monitoringService; + } public override Task OnConnectedAsync() { System.Console.WriteLine("Client connected " + Context.ConnectionId); @@ -20,8 +28,13 @@ public override async Task OnDisconnectedAsync(Exception? exception) public async Task SendMessage(string user, string message) { + System.Console.WriteLine(); System.Console.WriteLine("SendMessage: " + user + " " + message); await Clients.All.SendAsync("ReceiveMessage", user, message); } + public async Task GetConnectedUsers(string email){ + var response = _monitoringService.Test(); + await Clients.Caller.SendAsync("ReceiveUsers", response, "OK"); + } } } \ No newline at end of file diff --git a/cppseminar/presentation/Model/ConnectionLog.cs b/cppseminar/presentation/Model/ConnectionLog.cs new file mode 100644 index 00000000..6dec3a16 --- /dev/null +++ b/cppseminar/presentation/Model/ConnectionLog.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + + +namespace presentation.Model +{ + public class ConnectionLog + { + public ConnectionLog(string email, DateTime timestamp){ + UserEmail = email; + Timestamp = timestamp; + } + public ConnectionLog(){ + } + public string UserEmail { get; set; } + public DateTime Timestamp { get; set; } + } +} diff --git a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml new file mode 100644 index 00000000..ccb5c435 --- /dev/null +++ b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml @@ -0,0 +1,34 @@ +@page +@using System.Security.Claims +@model presentation.Pages.Monitoring.IndexModel +@{ +} + + + + +
+ All connected users + + + + + + @foreach (var user in Model.LoggedUsers) + { + + + + + } + +
+ User email + + Last message +
+ @user.UserEmail + + @user.Timestamp +
+
\ No newline at end of file diff --git a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs new file mode 100644 index 00000000..66c24328 --- /dev/null +++ b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs @@ -0,0 +1,31 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; +using presentation.Model; +using presentation.Services; +using System.Net.Mime; +using Microsoft.AspNetCore.Mvc; + + +namespace presentation.Pages.Monitoring +{ + public class IndexModel : PageModel + { + private ILogger _logger = null; + [BindProperty] + public List LoggedUsers{get;set;} + private readonly MonitoringService _monitoringService = null; + public IndexModel(ILogger logger, MonitoringService monitoringService) + { + _logger = logger; + _monitoringService = monitoringService; + LoggedUsers = new List(); + } + + + } +} diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml b/cppseminar/presentation/Pages/Connection/Index.cshtml index 8fadd4b9..1e46e9e3 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml @@ -1,4 +1,5 @@ @page +@using System.Security.Claims @model presentation.Pages.Connection.IndexModel @{ } @@ -7,7 +8,14 @@ @section JavaScript { - + @if(User.Identity.IsAuthenticated) + { + + + } + }
diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs index e7978044..5ffbd43b 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.Logging; using presentation.Model; using presentation.Services; -using Microsoft.AspNetCore.Mvc; using System.Net.Mime; namespace presentation.Pages.Connection diff --git a/cppseminar/presentation/Pages/Shared/_Layout.cshtml b/cppseminar/presentation/Pages/Shared/_Layout.cshtml index c484dd4a..d9a847bd 100644 --- a/cppseminar/presentation/Pages/Shared/_Layout.cshtml +++ b/cppseminar/presentation/Pages/Shared/_Layout.cshtml @@ -36,6 +36,7 @@ { + } diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs new file mode 100644 index 00000000..97a3b0ea --- /dev/null +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Http.Json; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using System.Web; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using presentation.Model; + +namespace presentation.Services +{ + public class MonitoringService + { + public MonitoringService(ILogger logger, IConfiguration config) + { + _client.BaseAddress = new Uri(config["API_GATEWAY"]); + _client.DefaultRequestHeaders.Accept.Clear(); + _client.DefaultRequestHeaders.Accept.Add( + new MediaTypeWithQualityHeaderValue("application/json")); + _logger = logger; + } + public async Task> Test(){ + var connectionLog = new ConnectionLog(); + connectionLog.UserEmail = "Test user"; + connectionLog.Timestamp = DateTime.Now; + List list = new List + { + connectionLog + }; + return list; + + } + private readonly HttpClient _client = new(); + private readonly ILogger _logger = null; + } + +} \ No newline at end of file diff --git a/cppseminar/presentation/Startup.cs b/cppseminar/presentation/Startup.cs index d42210b1..59d40800 100644 --- a/cppseminar/presentation/Startup.cs +++ b/cppseminar/presentation/Startup.cs @@ -33,6 +33,8 @@ public void ConfigureServices(IServiceCollection services) }); // modified this services.AddSignalR(); + services.AddControllers(); + services.Configure(options => { options.AppendTrailingSlash = true; @@ -51,6 +53,8 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + // + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -105,8 +109,14 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseAuthorization(); app.UseEndpoints(endpoints => { + endpoints.MapControllers(); endpoints.MapRazorPages(); endpoints.MapHub("/monitor"); + // endpoints.MapGet("/testingeverything", async context => + // { + // System.Console.WriteLine("Hello, World!"); + // }); + }); app.UseStaticFiles(); diff --git a/cppseminar/presentation/wwwroot/js/monitoring_admin.js b/cppseminar/presentation/wwwroot/js/monitoring_admin.js new file mode 100644 index 00000000..0d817b34 --- /dev/null +++ b/cppseminar/presentation/wwwroot/js/monitoring_admin.js @@ -0,0 +1,47 @@ +setInterval(()=>{ + var response = fetch("http://localhost:8080/monitoring/getUsers") +},5000) +// const connection = new signalR.HubConnectionBuilder() +// .withUrl("/monitor") +// .configureLogging(signalR.LogLevel.Information) +// .build(); + +// async function start() { +// try { +// await connection.start(); +// console.log("SignalR Connected."); +// } +// catch (err) { +// console.log(err); +// setTimeout(start, 5000); +// } +// }; + +// connection.onclose(async () => { +// console.log("Connection closed."); +// await start(); +// }); + +// // Define the ReceiveMessage method so that it can be triggered from the Hub +// connection.on("ReceiveUsers", (users, message) => { +// users.forEach(user => { +// console.log(user); +// }) +// }); + +// async function invokeSendMessage() { +// // Invoke SendMessage on the Hub +// try { +// await connection.invoke("GetConnectedUsers", userEmail, "This is a message " + (new Date).getMilliseconds()); +// } catch (err) { +// console.error(err); +// } +// return false; +// } + +// async function main() { +// // Start the connection. +// await start(); +// } + +// main(); \ No newline at end of file diff --git a/cppseminar/presentation/wwwroot/js/script.js b/cppseminar/presentation/wwwroot/js/script.js index 0ab94184..07848332 100644 --- a/cppseminar/presentation/wwwroot/js/script.js +++ b/cppseminar/presentation/wwwroot/js/script.js @@ -1,3 +1,5 @@ +console.log("Test", userEmail); + const connection = new signalR.HubConnectionBuilder() .withUrl("/monitor") .configureLogging(signalR.LogLevel.Information) @@ -27,7 +29,7 @@ connection.on("ReceiveMessage", (user, message) => { async function invokeSendMessage() { // Invoke SendMessage on the Hub try { - await connection.invoke("SendMessage", "user123-TODO", "This is a message " + (new Date).getMilliseconds()); + await connection.invoke("SendMessage", userEmail, "This is a message " + (new Date).getMilliseconds()); } catch (err) { console.error(err); } From 5968883eef63a492b1a059035fcc926baa860da5 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Mon, 21 Aug 2023 18:07:33 +0200 Subject: [PATCH 07/55] added redis image + webapi service for redis --- cppseminar/docker-compose.yml | 6 +- cppseminar/monitoringservice/Dockerfile | 5 +- cppseminar/monitoringservice/Model/Pair.cs | 13 ++++ .../monitoringservice/Model/PingRecord.cs | 6 ++ cppseminar/monitoringservice/Program.cs | 58 +++++++++++++----- .../Services/StorageService.cs | 43 +++++++++++++ cppseminar/monitoringservice/Services/Test.cs | 0 .../appsettings.Development.json | 9 --- .../monitoringservice.csproj | 5 ++ .../monitoringservice/wwwroot/css/site.css | 22 ------- .../monitoringservice/wwwroot/favicon.ico | Bin 5430 -> 0 bytes .../monitoringservice/wwwroot/js/site.js | 4 -- 12 files changed, 116 insertions(+), 55 deletions(-) create mode 100644 cppseminar/monitoringservice/Model/Pair.cs create mode 100644 cppseminar/monitoringservice/Model/PingRecord.cs create mode 100644 cppseminar/monitoringservice/Services/StorageService.cs delete mode 100644 cppseminar/monitoringservice/Services/Test.cs delete mode 100644 cppseminar/monitoringservice/appsettings.Development.json delete mode 100644 cppseminar/monitoringservice/wwwroot/css/site.css delete mode 100644 cppseminar/monitoringservice/wwwroot/favicon.ico delete mode 100644 cppseminar/monitoringservice/wwwroot/js/site.js diff --git a/cppseminar/docker-compose.yml b/cppseminar/docker-compose.yml index f3649455..bbac98c7 100644 --- a/cppseminar/docker-compose.yml +++ b/cppseminar/docker-compose.yml @@ -282,6 +282,7 @@ services: - ./monitoringservice/Program.cs:/src/Program.cs - ./monitoringservice/Model:/src/Model - ./monitoringservice/Services:/src/Services + - ./monitoringservice/monitoringservice.csproj:/src/monitoringservice.csproj networks: - sharednet ports: @@ -292,12 +293,13 @@ services: DOTNET_WATCH_SUPPRESS_LAUNCH_BROWSER: 1 DOTNET_WATCH_SUPPRESS_BROWSER_REFRESH: 1 ASPNETCORE_ENVIRONMENT: Development - LINKS_CURRENT_DOCS: https://example.com/ API_GATEWAY: http://gateway.local:5000/ LOG_PRETTY: 1 restart: always depends_on: - - redis.local + redis.local: + condition: service_started + networks: sharednet: diff --git a/cppseminar/monitoringservice/Dockerfile b/cppseminar/monitoringservice/Dockerfile index 9e09b877..92879da3 100644 --- a/cppseminar/monitoringservice/Dockerfile +++ b/cppseminar/monitoringservice/Dockerfile @@ -1,6 +1,6 @@ FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app -EXPOSE 90 +EXPOSE 80 FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src @@ -10,8 +10,7 @@ COPY . . RUN dotnet build "monitoringservice.csproj" -c Release -o /app/build FROM build as dev -EXPOSE 8525 -CMD dotnet watch run --urls=http://0.0.0.0:8525 +CMD dotnet watch run --urls=http://0.0.0.0:80 FROM build AS publish RUN dotnet publish "monitoringservice.csproj" -c Release -o /app/publish diff --git a/cppseminar/monitoringservice/Model/Pair.cs b/cppseminar/monitoringservice/Model/Pair.cs new file mode 100644 index 00000000..d0f04e30 --- /dev/null +++ b/cppseminar/monitoringservice/Model/Pair.cs @@ -0,0 +1,13 @@ +namespace monitoringservice.Model; + +public class Pair +{ + public string? Key { get; set; } + public string? Value { get; set; } + + public Pair(string? key, string? value) + { + Key = key; + Value = value; + } +} \ No newline at end of file diff --git a/cppseminar/monitoringservice/Model/PingRecord.cs b/cppseminar/monitoringservice/Model/PingRecord.cs new file mode 100644 index 00000000..aea91dda --- /dev/null +++ b/cppseminar/monitoringservice/Model/PingRecord.cs @@ -0,0 +1,6 @@ +namespace monitoringservice.Model; + +public class PingRecord +{ + +} diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs index 5f12b0bd..838c933b 100644 --- a/cppseminar/monitoringservice/Program.cs +++ b/cppseminar/monitoringservice/Program.cs @@ -1,22 +1,50 @@ -using MonitoringService.Hubs; +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using monitoringservice.Services; +using monitoringservice.Model; -var builder = WebApplication.CreateBuilder(args); +namespace monitoringservice; -// Add services to the container. -var app = builder.Build(); - -// Configure the HTTP request pipeline. -if (!app.Environment.IsDevelopment()) +public class Program { - app.UseExceptionHandler("/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); -} + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + builder.Services.AddSingleton(); + var app = builder.Build(); + + if (!app.Environment.IsDevelopment()) + { + app.UseExceptionHandler("/Error"); + } -app.UseHttpsRedirection(); + app.MapGet("/redis/get/all", (StorageService db) => { + System.Console.WriteLine("GET /redis/get/all"); + return db.getEveryKeyValueJson(); + }); -app.UseRouting(); + app.MapGet("/redis/get/key/{key}", (string key, StorageService db) => { + System.Console.WriteLine($"GET /redis/get/key/, key={key}"); + string value = db.getValue(key); + if (value == null) + return "404\n"; // TODO - 404 status + else + return value; + }); -app.UseAuthorization(); + app.MapPost("/redis/post", (Pair pair, StorageService db) => { + System.Console.WriteLine($"POST /redis/post: {pair.Key} {pair.Value}"); + if (pair.Key == null || pair.Value == null) + return "Bad request\n"; // TODO - 400 status + + db.setPair(pair.Key, pair.Value); + return "OK\n"; + }); + + app.Run(); + } +} -app.Run(); diff --git a/cppseminar/monitoringservice/Services/StorageService.cs b/cppseminar/monitoringservice/Services/StorageService.cs new file mode 100644 index 00000000..1712fc5e --- /dev/null +++ b/cppseminar/monitoringservice/Services/StorageService.cs @@ -0,0 +1,43 @@ +using StackExchange.Redis; +using System.Text.Json; +using monitoringservice.Model; + +namespace monitoringservice.Services; +public class StorageService +{ + private IDatabase _db; + private IServer _server; + + public StorageService() + { + ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("redis.local"); + _db = redis.GetDatabase(); + _server = redis.GetServer("redis.local", 6379); + } + + public void setPair(string Key, string Value) + { + _db.StringSet(Key, Value); + } + + public string getValue(string Key) + { + string value = _db.StringGet(Key); + return value == null ? "" : value; + } + + public string getEveryKeyValueJson() + { + List pairs = new List(); + + var keys = _server.Keys(); + foreach (var key in keys) + { + var value = _db.StringGet(key); + pairs.Add(new Pair(key, value)); + } + + return JsonSerializer.Serialize(pairs); + } + +} \ No newline at end of file diff --git a/cppseminar/monitoringservice/Services/Test.cs b/cppseminar/monitoringservice/Services/Test.cs deleted file mode 100644 index e69de29b..00000000 diff --git a/cppseminar/monitoringservice/appsettings.Development.json b/cppseminar/monitoringservice/appsettings.Development.json deleted file mode 100644 index 770d3e93..00000000 --- a/cppseminar/monitoringservice/appsettings.Development.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "DetailedErrors": true, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - } -} diff --git a/cppseminar/monitoringservice/monitoringservice.csproj b/cppseminar/monitoringservice/monitoringservice.csproj index c78c9c7e..c53217d3 100644 --- a/cppseminar/monitoringservice/monitoringservice.csproj +++ b/cppseminar/monitoringservice/monitoringservice.csproj @@ -6,4 +6,9 @@ enable + + + + + diff --git a/cppseminar/monitoringservice/wwwroot/css/site.css b/cppseminar/monitoringservice/wwwroot/css/site.css deleted file mode 100644 index f8d98fcb..00000000 --- a/cppseminar/monitoringservice/wwwroot/css/site.css +++ /dev/null @@ -1,22 +0,0 @@ -html { - font-size: 14px; -} - -@media (min-width: 768px) { - html { - font-size: 16px; - } -} - -.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { - box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; -} - -html { - position: relative; - min-height: 100%; -} - -body { - margin-bottom: 60px; -} \ No newline at end of file diff --git a/cppseminar/monitoringservice/wwwroot/favicon.ico b/cppseminar/monitoringservice/wwwroot/favicon.ico deleted file mode 100644 index 63e859b476eff5055e0e557aaa151ca8223fbeef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5430 zcmc&&Yj2xp8Fqnv;>&(QB_ve7>^E#o2mu=cO~A%R>DU-_hfbSRv1t;m7zJ_AMrntN zy0+^f&8be>q&YYzH%(88lQ?#KwiCzaCO*ZEo%j&v;<}&Lj_stKTKK>#U3nin@AF>w zb3ONSAFR{u(S1d?cdw53y}Gt1b-Hirbh;;bm(Rcbnoc*%@jiaXM|4jU^1WO~`TYZ~ zC-~jh9~b-f?fX`DmwvcguQzn*uV}c^Vd&~?H|RUs4Epv~gTAfR(B0lT&?RWQOtduM z^1vUD9{HQsW!{a9|0crA34m7Z6lpG^}f6f?={zD+ zXAzk^i^aKN_}s2$eX81wjSMONE#WVdzf|MT)Ap*}Vsn!XbvsI#6o&ij{87^d%$|A{ z=F{KB%)g%@z76yBzbb7seW**Ju8r4e*Z3PWNX3_tTDgzZatz7)Q6ytwB%@&@A|XT; zecM`Snxx5po$C)%yCP!KEtos~eOS)@2=kX-RIm)4glMCoagTEFxrBeSX%Euz734Fk z%7)x(k~T!@Hbg_37NSQL!vlTBXoURSzt~I**Zw`&F24fH*&kx=%nvZv|49SC*daD( zIw<~%#=lk8{2-l(BcIjy^Q$Q&m#KlWL9?UG{b8@qhlD z;umc+6p%|NsAT~0@DgV4-NKgQuWPWrmPIK&&XhV&n%`{l zOl^bbWYjQNuVXTXESO)@|iUKVmErPUDfz2Wh`4dF@OFiaCW|d`3paV^@|r^8T_ZxM)Z+$p5qx# z#K=z@%;aBPO=C4JNNGqVv6@UGolIz;KZsAro``Rz8X%vq_gpi^qEV&evgHb_=Y9-l z`)imdx0UC>GWZYj)3+3aKh?zVb}=@%oNzg7a8%kfVl)SV-Amp1Okw&+hEZ3|v(k8vRjXW9?ih`&FFM zV$~{j3IzhtcXk?Mu_!12;=+I7XK-IR2>Yd%VB^?oI9c^E&Chb&&je$NV0P-R;ujkP z;cbLCCPEF6|22NDj=S`F^2e~XwT1ZnRX8ra0#DaFa9-X|8(xNW_+JhD75WnSd7cxo z2>I_J5{c|WPfrgl7E2R)^c}F7ry()Z>$Jhk9CzZxiPKL#_0%`&{MX>P_%b~Dx0D^S z7xP1(DQ!d_Icpk!RN3I1w@~|O1ru#CO==h#9M~S4Chx*@?=EKUPGBv$tmU+7Zs_al z`!jR?6T&Z7(%uVq>#yLu`abWk!FBlnY{RFNHlj~6zh*;@u}+}viRKsD`IIxN#R-X3 z@vxu#EA_m}I503U(8Qmx^}u;)KfGP`O9E1H1Q|xeeksX8jC%@!{YT1)!lWgO=+Y3*jr=iSxvOW1}^HSy=y){tOMQJ@an>sOl4FYniE z;GOxd7AqxZNbYFNqobpv&HVO$c-w!Y*6r;$2oJ~h(a#(Bp<-)dg*mNigX~9rPqcHv z^;c*|Md?tD)$y?6FO$DWl$jUGV`F1G_^E&E>sY*YnA~ruv3=z9F8&&~Xpm<<75?N3 z>x~`I&M9q)O1=zWZHN9hZWx>RQ}zLP+iL57Q)%&_^$Sme^^G7;e-P~CR?kqU#Io#( z(nH1Wn*Ig)|M>WLGrxoU?FZrS`4GO&w;+39A3f8w{{Q7eg|$+dIlNFPAe+tN=FOYU z{A&Fg|H73+w1IK(W=j*L>JQgz$g0 z7JpKXLHIh}#$wm|N`s}o-@|L_`>*(gTQ~)wr3Eap7g%PVNisKw82im;Gdv#85x#s+ zoqqtnwu4ycd>cOQgRh-=aEJbnvVK`}ja%+FZx}&ehtX)n(9nVfe4{mn0bgijUbNr7Tf5X^$*{qh2%`?--%+sbSrjE^;1e3>% zqa%jdY16{Y)a1hSy*mr0JGU05Z%=qlx5vGvTjSpTt6k%nR06q}1DU`SQh_ZAeJ}A@`hL~xvv05U?0%=spP`R>dk?cOWM9^KNb7B?xjex>OZo%JMQQ1Q zB|q@}8RiP@DWn-(fB;phPaIOP2Yp)XN3-Fsn)S3w($4&+p8f5W_f%gac}QvmkHfCj$2=!t`boCvQ zCW;&Dto=f8v##}dy^wg3VNaBy&kCe3N;1|@n@pUaMPT?(aJ9b*(gJ28$}(2qFt$H~u5z94xcIQkcOI++)*exzbrk?WOOOf*|%k5#KV zL=&ky3)Eirv$wbRJ2F2s_ILQY--D~~7>^f}W|Aw^e7inXr#WLI{@h`0|jHud2Y~cI~Yn{r_kU^Vo{1gja Date: Tue, 22 Aug 2023 10:03:03 +0200 Subject: [PATCH 08/55] redis API functions are now async --- cppseminar/monitoringservice/Program.cs | 12 +++++----- .../Services/StorageService.cs | 22 +++++++++++++------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs index 838c933b..e9bbcea9 100644 --- a/cppseminar/monitoringservice/Program.cs +++ b/cppseminar/monitoringservice/Program.cs @@ -21,26 +21,26 @@ public static void Main(string[] args) app.UseExceptionHandler("/Error"); } - app.MapGet("/redis/get/all", (StorageService db) => { + app.MapGet("/redis/get/all", async (StorageService db) => { System.Console.WriteLine("GET /redis/get/all"); - return db.getEveryKeyValueJson(); + return await db.getEveryKeyValueJsonAsync(); }); - app.MapGet("/redis/get/key/{key}", (string key, StorageService db) => { + app.MapGet("/redis/get/key/{key}", async (string key, StorageService db) => { System.Console.WriteLine($"GET /redis/get/key/, key={key}"); - string value = db.getValue(key); + string value = await db.getValueAsync(key); if (value == null) return "404\n"; // TODO - 404 status else return value; }); - app.MapPost("/redis/post", (Pair pair, StorageService db) => { + app.MapPost("/redis/post", async (Pair pair, StorageService db) => { System.Console.WriteLine($"POST /redis/post: {pair.Key} {pair.Value}"); if (pair.Key == null || pair.Value == null) return "Bad request\n"; // TODO - 400 status - db.setPair(pair.Key, pair.Value); + await db.setPairAsync(pair.Key, pair.Value); return "OK\n"; }); diff --git a/cppseminar/monitoringservice/Services/StorageService.cs b/cppseminar/monitoringservice/Services/StorageService.cs index 1712fc5e..4635649d 100644 --- a/cppseminar/monitoringservice/Services/StorageService.cs +++ b/cppseminar/monitoringservice/Services/StorageService.cs @@ -1,5 +1,6 @@ using StackExchange.Redis; using System.Text.Json; +using System.Threading.Tasks; using monitoringservice.Model; namespace monitoringservice.Services; @@ -15,29 +16,36 @@ public StorageService() _server = redis.GetServer("redis.local", 6379); } - public void setPair(string Key, string Value) + public async Task setPairAsync(string Key, string Value) { - _db.StringSet(Key, Value); + await _db.StringSetAsync(Key, Value); } - public string getValue(string Key) + public async Task getValueAsync(string Key) { - string value = _db.StringGet(Key); + string value = await _db.StringGetAsync(Key); return value == null ? "" : value; } - public string getEveryKeyValueJson() + public async Task getEveryKeyValueJsonAsync() { List pairs = new List(); - + var keys = _server.Keys(); foreach (var key in keys) { - var value = _db.StringGet(key); + var value = await _db.StringGetAsync(key); pairs.Add(new Pair(key, value)); } return JsonSerializer.Serialize(pairs); } + public async Task delayTestAsync(int delay) + { + await _db.StringSetAsync("delay", delay); + System.Threading.Thread.Sleep(delay); + return true; + } + } \ No newline at end of file From de0f383681bbc790bddf744e5a1a88703c29f0a7 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Tue, 22 Aug 2023 10:22:40 +0200 Subject: [PATCH 09/55] redis api endpoints now return status codes --- cppseminar/monitoringservice/Program.cs | 25 +++++++++++++------ .../Services/StorageService.cs | 11 ++------ 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs index e9bbcea9..f425c6e6 100644 --- a/cppseminar/monitoringservice/Program.cs +++ b/cppseminar/monitoringservice/Program.cs @@ -26,22 +26,33 @@ public static void Main(string[] args) return await db.getEveryKeyValueJsonAsync(); }); - app.MapGet("/redis/get/key/{key}", async (string key, StorageService db) => { + app.MapGet("/redis/get/key/{key}", async (string key, StorageService db, HttpContext context) => { System.Console.WriteLine($"GET /redis/get/key/, key={key}"); + string value = await db.getValueAsync(key); if (value == null) - return "404\n"; // TODO - 404 status + { + context.Response.StatusCode = 404; + return ""; + } else + { return value; + } }); - app.MapPost("/redis/post", async (Pair pair, StorageService db) => { + app.MapPost("/redis/post", async (Pair pair, StorageService db, HttpContext context) => { System.Console.WriteLine($"POST /redis/post: {pair.Key} {pair.Value}"); if (pair.Key == null || pair.Value == null) - return "Bad request\n"; // TODO - 400 status - - await db.setPairAsync(pair.Key, pair.Value); - return "OK\n"; + { + context.Response.StatusCode = 400; + return ""; + } + else + { + await db.setPairAsync(pair.Key, pair.Value); + return "OK\n"; + } }); app.Run(); diff --git a/cppseminar/monitoringservice/Services/StorageService.cs b/cppseminar/monitoringservice/Services/StorageService.cs index 4635649d..91dcf42c 100644 --- a/cppseminar/monitoringservice/Services/StorageService.cs +++ b/cppseminar/monitoringservice/Services/StorageService.cs @@ -21,10 +21,10 @@ public async Task setPairAsync(string Key, string Value) await _db.StringSetAsync(Key, Value); } - public async Task getValueAsync(string Key) + public async Task getValueAsync(string Key) { string value = await _db.StringGetAsync(Key); - return value == null ? "" : value; + return value; } public async Task getEveryKeyValueJsonAsync() @@ -41,11 +41,4 @@ public async Task getEveryKeyValueJsonAsync() return JsonSerializer.Serialize(pairs); } - public async Task delayTestAsync(int delay) - { - await _db.StringSetAsync("delay", delay); - System.Threading.Thread.Sleep(delay); - return true; - } - } \ No newline at end of file From 7a790a3fd1f9873d73eb6a2c67d405e9891f88c3 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Tue, 22 Aug 2023 11:42:28 +0200 Subject: [PATCH 10/55] redis api - added endpoints to create and append lists in redis --- cppseminar/monitoringservice/Program.cs | 32 ++++++++++++++-- .../Services/StorageService.cs | 37 +++++++++++++++++-- 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs index f425c6e6..715723fe 100644 --- a/cppseminar/monitoringservice/Program.cs +++ b/cppseminar/monitoringservice/Program.cs @@ -41,21 +41,45 @@ public static void Main(string[] args) } }); - app.MapPost("/redis/post", async (Pair pair, StorageService db, HttpContext context) => { - System.Console.WriteLine($"POST /redis/post: {pair.Key} {pair.Value}"); - if (pair.Key == null || pair.Value == null) + app.MapPost("/redis/post/pair", async (Pair pair, StorageService db, HttpContext context) => { + System.Console.WriteLine($"POST /redis/post/pair: {pair.Key} {pair.Value}"); + if (!isValidPair(pair)) { context.Response.StatusCode = 400; return ""; } else { - await db.setPairAsync(pair.Key, pair.Value); + await db.setPairAsync(pair); return "OK\n"; } }); + app.MapPost("/redis/post/list/append", async (Pair pair, StorageService db, HttpContext context) => { + System.Console.WriteLine($"POST /redis/post/list/append: {pair.Key} {pair.Value}"); + if (!isValidPair(pair)) + { + context.Response.StatusCode = 400; + return ""; + } + else + { + await db.appendListPairAsync(pair); + return "OK\n"; + } + }); + + app.MapGet("/redis/get/list/all", async (StorageService db) => { + System.Console.WriteLine("GET /redis/get/list/all"); + return await db.getEveryListJsonAsync(); + }); + app.Run(); } + + private static bool isValidPair(Pair pair) + { + return !(pair.Key == null || pair.Value == null); + } } diff --git a/cppseminar/monitoringservice/Services/StorageService.cs b/cppseminar/monitoringservice/Services/StorageService.cs index 91dcf42c..965bee1a 100644 --- a/cppseminar/monitoringservice/Services/StorageService.cs +++ b/cppseminar/monitoringservice/Services/StorageService.cs @@ -16,9 +16,9 @@ public StorageService() _server = redis.GetServer("redis.local", 6379); } - public async Task setPairAsync(string Key, string Value) + public async Task setPairAsync(Pair pair) { - await _db.StringSetAsync(Key, Value); + await _db.StringSetAsync(pair.Key, pair.Value); } public async Task getValueAsync(string Key) @@ -27,6 +27,7 @@ public async Task setPairAsync(string Key, string Value) return value; } +/* This works only when key-value pairs are in redis */ public async Task getEveryKeyValueJsonAsync() { List pairs = new List(); @@ -38,7 +39,37 @@ public async Task getEveryKeyValueJsonAsync() pairs.Add(new Pair(key, value)); } - return JsonSerializer.Serialize(pairs); + return JsonSerializer.Serialize(pairs); } + public async Task appendListPairAsync(Pair pair) + { + // Appending items to the list + await _db.ListRightPushAsync(pair.Key, pair.Value); + + // var last = await _db.ListGetByIndexAsync(pair.Key, -1); + // Console.WriteLine($"Last item: {last}"); + } + + public async Task getEveryListJsonAsync() + { + var output = new List>(); + var keys = _server.Keys(); + foreach (var key in keys) + { + var list = new List(); + list.Add(key); // 1st item is always the key + + // Retrieving all items from the list + var items = await _db.ListRangeAsync(key); + foreach (var item in items) + { + list.Add(item); + } + + output.Add(list); + } + + return JsonSerializer.Serialize(output); + } } \ No newline at end of file From 5c7a9c93aa96c7cb3b6848d775ea412dfa11db36 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Wed, 23 Aug 2023 10:07:00 +0200 Subject: [PATCH 11/55] presentation: /monitoring page shows a dummy list of users with their last timestamp --- .../Controllers/MonitoringController.cs | 51 ------------------- .../Pages/Admin/Monitoring/Index.cshtml.cs | 17 ++++++- .../Services/MonitoringService.cs | 14 ++--- 3 files changed, 23 insertions(+), 59 deletions(-) delete mode 100644 cppseminar/presentation/Controllers/MonitoringController.cs diff --git a/cppseminar/presentation/Controllers/MonitoringController.cs b/cppseminar/presentation/Controllers/MonitoringController.cs deleted file mode 100644 index 0c6ca227..00000000 --- a/cppseminar/presentation/Controllers/MonitoringController.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Text.Json; -using System.Threading.Tasks; -using presentation.Services; -using presentation.Model; - -namespace presentation.Controllers -{ - [Route("monitoring")] - [ApiController] - public class MonitoringController : ControllerBase - { - private readonly ILogger _logger; - private readonly MonitoringService _monitoringService; - - public MonitoringController(ILogger logger, MonitoringService monitoringService) - { - _logger = logger; - _monitoringService = monitoringService; - } - - [HttpGet] - public async Task>> OnGet() - { - if(!User.IsAdmin()){ - System.Console.WriteLine("Unauthorized request"); - return StatusCode(401); - } - System.Console.WriteLine("caf a fsdfasdfsfsdf"); - - - try - { - var connectionLog = await _monitoringService.Test(); - return connectionLog; - } - catch (Exception e) - { - _logger.LogWarning("Error during retrieval of data, {e}", e); - return StatusCode(500); // Internal error - } - } - - - } -} - - diff --git a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs index 66c24328..c560860f 100644 --- a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs @@ -19,11 +19,26 @@ public class IndexModel : PageModel [BindProperty] public List LoggedUsers{get;set;} private readonly MonitoringService _monitoringService = null; + public IndexModel(ILogger logger, MonitoringService monitoringService) { _logger = logger; _monitoringService = monitoringService; - LoggedUsers = new List(); + } + + public async Task OnGetAsync() + { + try + { + _logger.LogTrace("Obtaining list of monitored users for admin"); + LoggedUsers = await _monitoringService.Test(); + _logger.LogTrace("List successfuly retrieved"); + } + catch(Exception e) + { + _logger.LogWarning("Error during logged users {e}", e); + ModelState.AddModelError(string.Empty, "Operation failed. Check log"); + } } diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs index 97a3b0ea..96a01b57 100644 --- a/cppseminar/presentation/Services/MonitoringService.cs +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -17,6 +17,9 @@ namespace presentation.Services { public class MonitoringService { + private readonly HttpClient _client = new HttpClient(); + private readonly ILogger _logger = null; + public MonitoringService(ILogger logger, IConfiguration config) { _client.BaseAddress = new Uri(config["API_GATEWAY"]); @@ -24,20 +27,17 @@ public MonitoringService(ILogger logger, IConfiguration confi _client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); _logger = logger; + System.Console.WriteLine("MonitoringService constructor"); } public async Task> Test(){ - var connectionLog = new ConnectionLog(); - connectionLog.UserEmail = "Test user"; - connectionLog.Timestamp = DateTime.Now; List list = new List { - connectionLog + new ConnectionLog("user1", DateTime.Now), + new ConnectionLog("user2", DateTime.Now), + new ConnectionLog("user3", DateTime.Now), }; return list; - } - private readonly HttpClient _client = new(); - private readonly ILogger _logger = null; } } \ No newline at end of file From 13a62f66ebbdef59798b2b8478493c4684342337 Mon Sep 17 00:00:00 2001 From: to-0 Date: Wed, 23 Aug 2023 13:01:00 +0200 Subject: [PATCH 12/55] Authorization required to invoke functions of MonitoringHub --- cppseminar/presentation/Hubs/MonitoringHub.cs | 11 ++- .../Pages/Connection/Index.cshtml | 2 + cppseminar/presentation/Startup.cs | 1 + .../wwwroot/js/monitoring_admin.js | 82 +++++++++---------- cppseminar/presentation/wwwroot/js/script.js | 8 +- 5 files changed, 58 insertions(+), 46 deletions(-) diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index abcd1ac8..60ea8128 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -4,6 +4,8 @@ using Microsoft.AspNetCore.Http.Features; using presentation.Services; using presentation.Model; +using System.Security.Claims; +using Microsoft.AspNetCore.Authorization; namespace presentation.Hubs @@ -25,13 +27,20 @@ public override async Task OnDisconnectedAsync(Exception? exception) System.Console.WriteLine("Client disconnected " + Context.ConnectionId); await base.OnDisconnectedAsync(exception); } - + [Authorize(Policy="Administrator")] public async Task SendMessage(string user, string message) { System.Console.WriteLine(); System.Console.WriteLine("SendMessage: " + user + " " + message); + System.Console.WriteLine(Context.User.Claims); + foreach (Claim claim in Context.User.Claims){ + System.Console.WriteLine(claim.Type); + System.Console.WriteLine(claim.Value); + } await Clients.All.SendAsync("ReceiveMessage", user, message); } + + [Authorize(Policy="Administrator")] public async Task GetConnectedUsers(string email){ var response = _monitoringService.Test(); await Clients.Caller.SendAsync("ReceiveUsers", response, "OK"); diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml b/cppseminar/presentation/Pages/Connection/Index.cshtml index 1e46e9e3..21d5f7d3 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml @@ -23,4 +23,6 @@

This page is used to check whether the student is still connected to our network.

Send message
+
+
diff --git a/cppseminar/presentation/Startup.cs b/cppseminar/presentation/Startup.cs index 59d40800..56f302e2 100644 --- a/cppseminar/presentation/Startup.cs +++ b/cppseminar/presentation/Startup.cs @@ -89,6 +89,7 @@ public void ConfigureServices(IServiceCollection services) options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser() .Build(); options.AddPolicy("Administrator", policy => policy.RequireClaim("isAdmin", "true")); + options.AddPolicy("Student", policy => policy.RequireClaim("isStudent", "true")); }); } diff --git a/cppseminar/presentation/wwwroot/js/monitoring_admin.js b/cppseminar/presentation/wwwroot/js/monitoring_admin.js index 0d817b34..46c2f77b 100644 --- a/cppseminar/presentation/wwwroot/js/monitoring_admin.js +++ b/cppseminar/presentation/wwwroot/js/monitoring_admin.js @@ -1,47 +1,47 @@ -setInterval(()=>{ - var response = fetch("http://localhost:8080/monitoring/getUsers") -},5000) -// const connection = new signalR.HubConnectionBuilder() -// .withUrl("/monitor") -// .configureLogging(signalR.LogLevel.Information) -// .build(); +// setInterval(()=>{ +// var response = fetch("http://localhost:8080/monitoring/getUsers") +// },5000) +const connection = new signalR.HubConnectionBuilder() + .withUrl("/monitor") + .configureLogging(signalR.LogLevel.Information) + .build(); -// async function start() { -// try { -// await connection.start(); -// console.log("SignalR Connected."); -// } -// catch (err) { -// console.log(err); -// setTimeout(start, 5000); -// } -// }; +async function start() { + try { + await connection.start(); + console.log("SignalR Connected."); + } + catch (err) { + console.log(err); + setTimeout(start, 5000); + } +}; -// connection.onclose(async () => { -// console.log("Connection closed."); -// await start(); -// }); +connection.onclose(async () => { + console.log("Connection closed."); + await start(); +}); -// // Define the ReceiveMessage method so that it can be triggered from the Hub -// connection.on("ReceiveUsers", (users, message) => { -// users.forEach(user => { -// console.log(user); -// }) -// }); +// Define the ReceiveMessage method so that it can be triggered from the Hub +connection.on("ReceiveUsers", (users, message) => { + users.forEach(user => { + console.log(user); + }) +}); -// async function invokeSendMessage() { -// // Invoke SendMessage on the Hub -// try { -// await connection.invoke("GetConnectedUsers", userEmail, "This is a message " + (new Date).getMilliseconds()); -// } catch (err) { -// console.error(err); -// } -// return false; -// } +async function invokeSendMessage() { + // Invoke SendMessage on the Hub + try { + await connection.invoke("GetConnectedUsers", userEmail, "This is a message " + (new Date).getMilliseconds()); + } catch (err) { + console.error(err); + } + return false; +} -// async function main() { -// // Start the connection. -// await start(); -// } +async function main() { + // Start the connection. + await start(); +} -// main(); \ No newline at end of file +main(); \ No newline at end of file diff --git a/cppseminar/presentation/wwwroot/js/script.js b/cppseminar/presentation/wwwroot/js/script.js index 07848332..d1dff3ce 100644 --- a/cppseminar/presentation/wwwroot/js/script.js +++ b/cppseminar/presentation/wwwroot/js/script.js @@ -20,8 +20,6 @@ connection.onclose(async () => { console.log("Connection closed."); await start(); }); - -// Define the ReceiveMessage method so that it can be triggered from the Hub connection.on("ReceiveMessage", (user, message) => { console.log("ReceiveMessage():", user, message); }); @@ -32,13 +30,15 @@ async function invokeSendMessage() { await connection.invoke("SendMessage", userEmail, "This is a message " + (new Date).getMilliseconds()); } catch (err) { console.error(err); + document.getElementById("errorMessages").textContent = "Unauthorized action"; } return false; } +// Define the ReceiveMessage method so that it can be triggered from the Hub + async function main() { // Start the connection. await start(); } - -main(); \ No newline at end of file +main(); From 9f9bf1d5f38ff2f7a595778fb921664574fb5e40 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Wed, 23 Aug 2023 13:03:00 +0200 Subject: [PATCH 13/55] monitoringservice added to envoy --- cppseminar/envoy/envoy.yaml | 17 ++++++++++- cppseminar/monitoringservice/Program.cs | 14 +++++---- cppseminar/presentation/Hubs/MonitoringHub.cs | 29 +++++++++---------- .../presentation/Model/ConnectionLog.cs | 4 +-- .../Pages/Admin/Monitoring/Index.cshtml.cs | 2 +- .../Services/MonitoringService.cs | 28 +++++++++++------- 6 files changed, 60 insertions(+), 34 deletions(-) diff --git a/cppseminar/envoy/envoy.yaml b/cppseminar/envoy/envoy.yaml index 9f078355..19ec69cf 100644 --- a/cppseminar/envoy/envoy.yaml +++ b/cppseminar/envoy/envoy.yaml @@ -45,6 +45,10 @@ static_resources: path_separated_prefix: /test route: cluster: test-service + - match: + path_separated_prefix: /monitoring + route: + cluster: monitoring-service http_filters: - name: envoy.filters.http.router typed_config: @@ -88,4 +92,15 @@ static_resources: address: socket_address: address: submissions.local - port_value: 80 \ No newline at end of file + port_value: 80 + - name: monitoring-service + type: strict_dns + load_assignment: + cluster_name: monitoring-service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: monitoringservice.local + port_value: 80 diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs index 715723fe..3f71bf58 100644 --- a/cppseminar/monitoringservice/Program.cs +++ b/cppseminar/monitoringservice/Program.cs @@ -21,12 +21,12 @@ public static void Main(string[] args) app.UseExceptionHandler("/Error"); } - app.MapGet("/redis/get/all", async (StorageService db) => { + app.MapGet("/monitoring/redis/get/all", async (StorageService db) => { System.Console.WriteLine("GET /redis/get/all"); return await db.getEveryKeyValueJsonAsync(); }); - app.MapGet("/redis/get/key/{key}", async (string key, StorageService db, HttpContext context) => { + app.MapGet("/monitoring/redis/get/key/{key}", async (string key, StorageService db, HttpContext context) => { System.Console.WriteLine($"GET /redis/get/key/, key={key}"); string value = await db.getValueAsync(key); @@ -41,7 +41,7 @@ public static void Main(string[] args) } }); - app.MapPost("/redis/post/pair", async (Pair pair, StorageService db, HttpContext context) => { + app.MapPost("/monitoring/redis/post/pair", async (Pair pair, StorageService db, HttpContext context) => { System.Console.WriteLine($"POST /redis/post/pair: {pair.Key} {pair.Value}"); if (!isValidPair(pair)) { @@ -55,7 +55,7 @@ public static void Main(string[] args) } }); - app.MapPost("/redis/post/list/append", async (Pair pair, StorageService db, HttpContext context) => { + app.MapPost("/monitoring/redis/post/list/append", async (Pair pair, StorageService db, HttpContext context) => { System.Console.WriteLine($"POST /redis/post/list/append: {pair.Key} {pair.Value}"); if (!isValidPair(pair)) { @@ -69,11 +69,15 @@ public static void Main(string[] args) } }); - app.MapGet("/redis/get/list/all", async (StorageService db) => { + app.MapGet("/monitoring/redis/get/list/all", async (StorageService db) => { System.Console.WriteLine("GET /redis/get/list/all"); return await db.getEveryListJsonAsync(); }); + app.MapGet("/monitoring/get/recents", async (StorageService db) => { + return "This is a test."; + }); + app.Run(); } diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index 60ea8128..9ab4eed5 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -16,18 +16,18 @@ public class MonitoringHub: Hub public MonitoringHub(MonitoringService monitoringService){ _monitoringService = monitoringService; } - public override Task OnConnectedAsync() - { - System.Console.WriteLine("Client connected " + Context.ConnectionId); - return base.OnConnectedAsync(); - } + // public override Task OnConnectedAsync() + // { + // System.Console.WriteLine("Client connected " + Context.ConnectionId); + // return base.OnConnectedAsync(); + // } - public override async Task OnDisconnectedAsync(Exception? exception) - { - System.Console.WriteLine("Client disconnected " + Context.ConnectionId); - await base.OnDisconnectedAsync(exception); - } - [Authorize(Policy="Administrator")] + // public override async Task OnDisconnectedAsync(Exception? exception) + // { + // System.Console.WriteLine("Client disconnected " + Context.ConnectionId); + // await base.OnDisconnectedAsync(exception); + // } + public async Task SendMessage(string user, string message) { System.Console.WriteLine(); @@ -39,10 +39,9 @@ public async Task SendMessage(string user, string message) } await Clients.All.SendAsync("ReceiveMessage", user, message); } - - [Authorize(Policy="Administrator")] - public async Task GetConnectedUsers(string email){ - var response = _monitoringService.Test(); + public async Task GetConnectedUsersRecentAsync(){ + var response = _monitoringService.GetConnectedUsersRecentAsync(); + System.Console.WriteLine(response); await Clients.Caller.SendAsync("ReceiveUsers", response, "OK"); } } diff --git a/cppseminar/presentation/Model/ConnectionLog.cs b/cppseminar/presentation/Model/ConnectionLog.cs index 6dec3a16..a22e88fe 100644 --- a/cppseminar/presentation/Model/ConnectionLog.cs +++ b/cppseminar/presentation/Model/ConnectionLog.cs @@ -7,13 +7,13 @@ namespace presentation.Model { public class ConnectionLog { - public ConnectionLog(string email, DateTime timestamp){ + public ConnectionLog(string email, string timestamp){ UserEmail = email; Timestamp = timestamp; } public ConnectionLog(){ } public string UserEmail { get; set; } - public DateTime Timestamp { get; set; } + public string Timestamp { get; set; } } } diff --git a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs index c560860f..373d0f10 100644 --- a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs @@ -31,8 +31,8 @@ public async Task OnGetAsync() try { _logger.LogTrace("Obtaining list of monitored users for admin"); - LoggedUsers = await _monitoringService.Test(); _logger.LogTrace("List successfuly retrieved"); + } catch(Exception e) { diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs index 96a01b57..04df89c0 100644 --- a/cppseminar/presentation/Services/MonitoringService.cs +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -26,17 +26,25 @@ public MonitoringService(ILogger logger, IConfiguration confi _client.DefaultRequestHeaders.Accept.Clear(); _client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); - _logger = logger; - System.Console.WriteLine("MonitoringService constructor"); + _logger = logger; } - public async Task> Test(){ - List list = new List - { - new ConnectionLog("user1", DateTime.Now), - new ConnectionLog("user2", DateTime.Now), - new ConnectionLog("user3", DateTime.Now), - }; - return list; + // public async Task> Test() + // { + // List list = new List + // { + // new ConnectionLog("user1", DateTime.Now), + // new ConnectionLog("user2", DateTime.Now), + // new ConnectionLog("user3", DateTime.Now), + // }; + // return list; + // } + + public async Task GetConnectedUsersRecentAsync() + { + var response = await _client.GetAsync("monitoring/get/recents"); // monitoring/get/all + var responseJson = await response.Content.ReadAsStringAsync(); + System.Console.WriteLine(responseJson); + return responseJson; } } From bb6ecad6c7267640c148484183d5ccfbfa48eec8 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Wed, 23 Aug 2023 13:36:26 +0200 Subject: [PATCH 14/55] monitoringservice API endpoints for logging connections + retrieving users' most recent timestamp --- cppseminar/monitoringservice/Model/Pair.cs | 13 ---- .../monitoringservice/Model/PingRecord.cs | 6 -- cppseminar/monitoringservice/Program.cs | 59 +++---------------- .../Services/StorageService.cs | 51 ++++------------ .../Pages/Admin/Monitoring/Index.cshtml.cs | 18 +----- .../Services/MonitoringService.cs | 10 ---- 6 files changed, 19 insertions(+), 138 deletions(-) delete mode 100644 cppseminar/monitoringservice/Model/Pair.cs delete mode 100644 cppseminar/monitoringservice/Model/PingRecord.cs diff --git a/cppseminar/monitoringservice/Model/Pair.cs b/cppseminar/monitoringservice/Model/Pair.cs deleted file mode 100644 index d0f04e30..00000000 --- a/cppseminar/monitoringservice/Model/Pair.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace monitoringservice.Model; - -public class Pair -{ - public string? Key { get; set; } - public string? Value { get; set; } - - public Pair(string? key, string? value) - { - Key = key; - Value = value; - } -} \ No newline at end of file diff --git a/cppseminar/monitoringservice/Model/PingRecord.cs b/cppseminar/monitoringservice/Model/PingRecord.cs deleted file mode 100644 index aea91dda..00000000 --- a/cppseminar/monitoringservice/Model/PingRecord.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace monitoringservice.Model; - -public class PingRecord -{ - -} diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs index 3f71bf58..7d217398 100644 --- a/cppseminar/monitoringservice/Program.cs +++ b/cppseminar/monitoringservice/Program.cs @@ -21,69 +21,26 @@ public static void Main(string[] args) app.UseExceptionHandler("/Error"); } - app.MapGet("/monitoring/redis/get/all", async (StorageService db) => { - System.Console.WriteLine("GET /redis/get/all"); - return await db.getEveryKeyValueJsonAsync(); - }); - - app.MapGet("/monitoring/redis/get/key/{key}", async (string key, StorageService db, HttpContext context) => { - System.Console.WriteLine($"GET /redis/get/key/, key={key}"); - - string value = await db.getValueAsync(key); - if (value == null) - { - context.Response.StatusCode = 404; - return ""; - } - else - { - return value; - } + app.MapGet("/monitoring/get/recents", async (StorageService db) => { + System.Console.WriteLine("GET /monitoring/get/recents"); + return await db.getConnectionLogsJsonAsync(); }); - app.MapPost("/monitoring/redis/post/pair", async (Pair pair, StorageService db, HttpContext context) => { - System.Console.WriteLine($"POST /redis/post/pair: {pair.Key} {pair.Value}"); - if (!isValidPair(pair)) - { + app.MapPost("/monitoring/post/log", async (ConnectionLog connectionLog, StorageService db, HttpContext context) => { + System.Console.WriteLine($"POST monitoring/post/log: {connectionLog.Email} {connectionLog.Timestamp}"); + if (connectionLog.Email == null || connectionLog.Timestamp == null) + { context.Response.StatusCode = 400; return ""; } else { - await db.setPairAsync(pair); - return "OK\n"; - } - }); - - app.MapPost("/monitoring/redis/post/list/append", async (Pair pair, StorageService db, HttpContext context) => { - System.Console.WriteLine($"POST /redis/post/list/append: {pair.Key} {pair.Value}"); - if (!isValidPair(pair)) - { - context.Response.StatusCode = 400; + await db.setConnectionlogAsync(connectionLog); return ""; } - else - { - await db.appendListPairAsync(pair); - return "OK\n"; - } - }); - - app.MapGet("/monitoring/redis/get/list/all", async (StorageService db) => { - System.Console.WriteLine("GET /redis/get/list/all"); - return await db.getEveryListJsonAsync(); - }); - - app.MapGet("/monitoring/get/recents", async (StorageService db) => { - return "This is a test."; }); app.Run(); } - - private static bool isValidPair(Pair pair) - { - return !(pair.Key == null || pair.Value == null); - } } diff --git a/cppseminar/monitoringservice/Services/StorageService.cs b/cppseminar/monitoringservice/Services/StorageService.cs index 965bee1a..cb5c5dd3 100644 --- a/cppseminar/monitoringservice/Services/StorageService.cs +++ b/cppseminar/monitoringservice/Services/StorageService.cs @@ -16,9 +16,9 @@ public StorageService() _server = redis.GetServer("redis.local", 6379); } - public async Task setPairAsync(Pair pair) + public async Task setConnectionlogAsync(ConnectionLog connectionLog) { - await _db.StringSetAsync(pair.Key, pair.Value); + await _db.StringSetAsync(connectionLog.Email, connectionLog.Timestamp); } public async Task getValueAsync(string Key) @@ -27,49 +27,18 @@ public async Task setPairAsync(Pair pair) return value; } -/* This works only when key-value pairs are in redis */ - public async Task getEveryKeyValueJsonAsync() +/* This works only when key-value pairs of string-string are in redis */ + public async Task getConnectionLogsJsonAsync() { - List pairs = new List(); + List connectionLogsList = new List(); - var keys = _server.Keys(); - foreach (var key in keys) + var emails = _server.Keys(); + foreach (var email in emails) { - var value = await _db.StringGetAsync(key); - pairs.Add(new Pair(key, value)); + var timestamp = await _db.StringGetAsync(email); + connectionLogsList.Add(new ConnectionLog(email, timestamp)); } - return JsonSerializer.Serialize(pairs); - } - - public async Task appendListPairAsync(Pair pair) - { - // Appending items to the list - await _db.ListRightPushAsync(pair.Key, pair.Value); - - // var last = await _db.ListGetByIndexAsync(pair.Key, -1); - // Console.WriteLine($"Last item: {last}"); - } - - public async Task getEveryListJsonAsync() - { - var output = new List>(); - var keys = _server.Keys(); - foreach (var key in keys) - { - var list = new List(); - list.Add(key); // 1st item is always the key - - // Retrieving all items from the list - var items = await _db.ListRangeAsync(key); - foreach (var item in items) - { - list.Add(item); - } - - output.Add(list); - } - - return JsonSerializer.Serialize(output); + return JsonSerializer.Serialize(connectionLogsList); } } \ No newline at end of file diff --git a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs index 373d0f10..ea8a5922 100644 --- a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs @@ -24,23 +24,7 @@ public IndexModel(ILogger logger, MonitoringService monitoringServic { _logger = logger; _monitoringService = monitoringService; + LoggedUsers = new List(); } - - public async Task OnGetAsync() - { - try - { - _logger.LogTrace("Obtaining list of monitored users for admin"); - _logger.LogTrace("List successfuly retrieved"); - - } - catch(Exception e) - { - _logger.LogWarning("Error during logged users {e}", e); - ModelState.AddModelError(string.Empty, "Operation failed. Check log"); - } - } - - } } diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs index 04df89c0..29fbf7e3 100644 --- a/cppseminar/presentation/Services/MonitoringService.cs +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -28,16 +28,6 @@ public MonitoringService(ILogger logger, IConfiguration confi new MediaTypeWithQualityHeaderValue("application/json")); _logger = logger; } - // public async Task> Test() - // { - // List list = new List - // { - // new ConnectionLog("user1", DateTime.Now), - // new ConnectionLog("user2", DateTime.Now), - // new ConnectionLog("user3", DateTime.Now), - // }; - // return list; - // } public async Task GetConnectedUsersRecentAsync() { From f9d80cf6a0b033e19bd010bb0f48ad81cac6942f Mon Sep 17 00:00:00 2001 From: to-0 Date: Wed, 23 Aug 2023 13:44:21 +0200 Subject: [PATCH 15/55] Added dynamic table refreshing in monitoring page. --- cppseminar/presentation/Hubs/MonitoringHub.cs | 7 +++++ .../Pages/Admin/Monitoring/Index.cshtml | 7 +++-- .../Services/MonitoringService.cs | 9 +++--- .../wwwroot/js/monitoring_admin.js | 28 +++++++++++++++++-- 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index 9ab4eed5..374e023a 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -6,6 +6,7 @@ using presentation.Model; using System.Security.Claims; using Microsoft.AspNetCore.Authorization; +using System.Text.Json; namespace presentation.Hubs @@ -28,6 +29,10 @@ public MonitoringHub(MonitoringService monitoringService){ // await base.OnDisconnectedAsync(exception); // } +<<<<<<< HEAD +======= + [Authorize(Policy="Student")] +>>>>>>> 23b70a5 (Added dynamic table refreshing in monitoring page) public async Task SendMessage(string user, string message) { System.Console.WriteLine(); @@ -42,6 +47,8 @@ public async Task SendMessage(string user, string message) public async Task GetConnectedUsersRecentAsync(){ var response = _monitoringService.GetConnectedUsersRecentAsync(); System.Console.WriteLine(response); + var test = JsonSerializer.Serialize(response); + System.Console.WriteLine(test); await Clients.Caller.SendAsync("ReceiveUsers", response, "OK"); } } diff --git a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml index ccb5c435..47331803 100644 --- a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml +++ b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml @@ -18,9 +18,10 @@ Last message - @foreach (var user in Model.LoggedUsers) +
+ @foreach (var user in Model.LoggedUsers) { - + @user.UserEmail @@ -29,6 +30,8 @@ } +
+ \ No newline at end of file diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs index 29fbf7e3..84e121cd 100644 --- a/cppseminar/presentation/Services/MonitoringService.cs +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -29,12 +29,13 @@ public MonitoringService(ILogger logger, IConfiguration confi _logger = logger; } - public async Task GetConnectedUsersRecentAsync() + public async Task> GetConnectedUsersRecentAsync() { var response = await _client.GetAsync("monitoring/get/recents"); // monitoring/get/all - var responseJson = await response.Content.ReadAsStringAsync(); - System.Console.WriteLine(responseJson); - return responseJson; + //var responseJson = await response.Content.ReadAsStringAsync(); + return await response.Content.ReadAsAsync>(); + // System.Console.WriteLine(responseJson); + // return responseJson; } } diff --git a/cppseminar/presentation/wwwroot/js/monitoring_admin.js b/cppseminar/presentation/wwwroot/js/monitoring_admin.js index 46c2f77b..379dcd75 100644 --- a/cppseminar/presentation/wwwroot/js/monitoring_admin.js +++ b/cppseminar/presentation/wwwroot/js/monitoring_admin.js @@ -24,15 +24,39 @@ connection.onclose(async () => { // Define the ReceiveMessage method so that it can be triggered from the Hub connection.on("ReceiveUsers", (users, message) => { + console.log(users) users.forEach(user => { - console.log(user); + const row = document.getElementById(user.email) + const tbl = document.getElementById("userLogs"); + if (row === null){ + const dateNow = Date.now() + const timestamp = new Date(user.timestamp) + tbl.innerHTML += ` + + ${user.email} + + + ${Math.floor((dateNow - timestamp) / 1000)} + + ` + } + else{ + row.innerHTML = ` + ${user.email} + + + ${Math.floor((dateNow - timestamp) / 1000)} + ` + } + console.log(user.email); + console.log(user.timestamp); }) }); async function invokeSendMessage() { // Invoke SendMessage on the Hub try { - await connection.invoke("GetConnectedUsers", userEmail, "This is a message " + (new Date).getMilliseconds()); + await connection.invoke("GetConnectedUsersRecentAsync"); } catch (err) { console.error(err); } From 27f8fb6ca7dcf724d38d4f981d4cc5edf7ffbc2e Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Wed, 23 Aug 2023 15:16:50 +0200 Subject: [PATCH 16/55] SignalR hub pulls user email from claims + 1st version of connection logging in redis --- .../monitoringservice/Model/ConnectionLog.cs | 13 ++++++++++ cppseminar/monitoringservice/Program.cs | 4 +-- .../Services/StorageService.cs | 2 +- cppseminar/presentation/Hubs/MonitoringHub.cs | 22 ++++++++++------ .../presentation/Model/ConnectionLog.cs | 24 +++++++----------- .../Pages/Connection/Index.cshtml | 2 +- .../Services/MonitoringService.cs | 9 +++++++ .../js/{script.js => connection_logging.js} | 14 ++++++++--- cppseminar/userservice/userservice.sln | 25 +++++++++++++++++++ 9 files changed, 86 insertions(+), 29 deletions(-) create mode 100644 cppseminar/monitoringservice/Model/ConnectionLog.cs rename cppseminar/presentation/wwwroot/js/{script.js => connection_logging.js} (78%) create mode 100644 cppseminar/userservice/userservice.sln diff --git a/cppseminar/monitoringservice/Model/ConnectionLog.cs b/cppseminar/monitoringservice/Model/ConnectionLog.cs new file mode 100644 index 00000000..a5973701 --- /dev/null +++ b/cppseminar/monitoringservice/Model/ConnectionLog.cs @@ -0,0 +1,13 @@ +namespace monitoringservice.Model; + +public class ConnectionLog +{ + public string? UserEmail { get; set; } + public string? Timestamp { get; set; } + + public ConnectionLog(string? email, string? timestamp) + { + UserEmail = email; + Timestamp = timestamp; + } +} \ No newline at end of file diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs index 7d217398..954c9030 100644 --- a/cppseminar/monitoringservice/Program.cs +++ b/cppseminar/monitoringservice/Program.cs @@ -27,8 +27,8 @@ public static void Main(string[] args) }); app.MapPost("/monitoring/post/log", async (ConnectionLog connectionLog, StorageService db, HttpContext context) => { - System.Console.WriteLine($"POST monitoring/post/log: {connectionLog.Email} {connectionLog.Timestamp}"); - if (connectionLog.Email == null || connectionLog.Timestamp == null) + System.Console.WriteLine($"POST monitoring/post/log: {connectionLog.UserEmail} {connectionLog.Timestamp}"); + if (connectionLog.UserEmail == null || connectionLog.Timestamp == null) { context.Response.StatusCode = 400; return ""; diff --git a/cppseminar/monitoringservice/Services/StorageService.cs b/cppseminar/monitoringservice/Services/StorageService.cs index cb5c5dd3..f263cecb 100644 --- a/cppseminar/monitoringservice/Services/StorageService.cs +++ b/cppseminar/monitoringservice/Services/StorageService.cs @@ -18,7 +18,7 @@ public StorageService() public async Task setConnectionlogAsync(ConnectionLog connectionLog) { - await _db.StringSetAsync(connectionLog.Email, connectionLog.Timestamp); + await _db.StringSetAsync(connectionLog.UserEmail, connectionLog.Timestamp); } public async Task getValueAsync(string Key) diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index 374e023a..07fd746a 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -17,6 +17,7 @@ public class MonitoringHub: Hub public MonitoringHub(MonitoringService monitoringService){ _monitoringService = monitoringService; } +<<<<<<< HEAD // public override Task OnConnectedAsync() // { // System.Console.WriteLine("Client connected " + Context.ConnectionId); @@ -34,15 +35,22 @@ public MonitoringHub(MonitoringService monitoringService){ [Authorize(Policy="Student")] >>>>>>> 23b70a5 (Added dynamic table refreshing in monitoring page) public async Task SendMessage(string user, string message) +======= + + //[Authorize(Policy="Student")] + public async Task LogConnection() +>>>>>>> 0fcbfd2 (SignalR hub pulls user email from claims + 1st version of connection logging in redis) { - System.Console.WriteLine(); - System.Console.WriteLine("SendMessage: " + user + " " + message); - System.Console.WriteLine(Context.User.Claims); - foreach (Claim claim in Context.User.Claims){ - System.Console.WriteLine(claim.Type); - System.Console.WriteLine(claim.Value); + string userEmail = ""; + foreach (Claim claim in Context.User.Claims) { + if (claim.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress") + { + userEmail = claim.Value; + break; + } } - await Clients.All.SendAsync("ReceiveMessage", user, message); + var connectionLog = new ConnectionLog(userEmail, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + _monitoringService.LogConnectionAsync(connectionLog); } public async Task GetConnectedUsersRecentAsync(){ var response = _monitoringService.GetConnectedUsersRecentAsync(); diff --git a/cppseminar/presentation/Model/ConnectionLog.cs b/cppseminar/presentation/Model/ConnectionLog.cs index a22e88fe..0d1d4a73 100644 --- a/cppseminar/presentation/Model/ConnectionLog.cs +++ b/cppseminar/presentation/Model/ConnectionLog.cs @@ -1,19 +1,13 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; +namespace presentation.Model; - -namespace presentation.Model +public class ConnectionLog { - public class ConnectionLog + public string? UserEmail { get; set; } + public string? Timestamp { get; set; } + + public ConnectionLog(string? email, string? timestamp) { - public ConnectionLog(string email, string timestamp){ - UserEmail = email; - Timestamp = timestamp; - } - public ConnectionLog(){ - } - public string UserEmail { get; set; } - public string Timestamp { get; set; } + UserEmail = email; + Timestamp = timestamp; } -} +} \ No newline at end of file diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml b/cppseminar/presentation/Pages/Connection/Index.cshtml index 21d5f7d3..2b109c82 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml @@ -13,7 +13,7 @@ - + } } diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs index 84e121cd..4aa9016d 100644 --- a/cppseminar/presentation/Services/MonitoringService.cs +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -3,6 +3,7 @@ using System.IO; using System.IO.Compression; using System.Net.Http; +using System.Net; using System.Net.Http.Headers; using System.Net.Http.Json; using System.Text; @@ -29,6 +30,14 @@ public MonitoringService(ILogger logger, IConfiguration confi _logger = logger; } + public async Task LogConnectionAsync(ConnectionLog connectionLog) { + var response = await _client.PostAsJsonAsync("monitoring/post/log", connectionLog); + if (response.StatusCode != HttpStatusCode.OK) + { + _logger.LogError("LogConnectionAsync returned " + response.StatusCode); + } + } + public async Task> GetConnectedUsersRecentAsync() { var response = await _client.GetAsync("monitoring/get/recents"); // monitoring/get/all diff --git a/cppseminar/presentation/wwwroot/js/script.js b/cppseminar/presentation/wwwroot/js/connection_logging.js similarity index 78% rename from cppseminar/presentation/wwwroot/js/script.js rename to cppseminar/presentation/wwwroot/js/connection_logging.js index d1dff3ce..1db03de0 100644 --- a/cppseminar/presentation/wwwroot/js/script.js +++ b/cppseminar/presentation/wwwroot/js/connection_logging.js @@ -20,9 +20,6 @@ connection.onclose(async () => { console.log("Connection closed."); await start(); }); -connection.on("ReceiveMessage", (user, message) => { - console.log("ReceiveMessage():", user, message); -}); async function invokeSendMessage() { // Invoke SendMessage on the Hub @@ -40,5 +37,16 @@ async function invokeSendMessage() { async function main() { // Start the connection. await start(); + + while (true) { + try { + await connection.invoke("LogConnection"); + } catch (err) { + console.error(err); + document.getElementById("errorMessages").textContent = "Unauthorized action"; + } + break; + } } + main(); diff --git a/cppseminar/userservice/userservice.sln b/cppseminar/userservice/userservice.sln new file mode 100644 index 00000000..427b6848 --- /dev/null +++ b/cppseminar/userservice/userservice.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "userservice", "userservice.csproj", "{925E68F9-822C-42B7-8DCD-DE600F008A81}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {925E68F9-822C-42B7-8DCD-DE600F008A81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {925E68F9-822C-42B7-8DCD-DE600F008A81}.Debug|Any CPU.Build.0 = Debug|Any CPU + {925E68F9-822C-42B7-8DCD-DE600F008A81}.Release|Any CPU.ActiveCfg = Release|Any CPU + {925E68F9-822C-42B7-8DCD-DE600F008A81}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {067AAD9B-351B-47D6-B0FB-FB5266CE698F} + EndGlobalSection +EndGlobal From 8742504d3c2b648696200703dd359f60bc611670 Mon Sep 17 00:00:00 2001 From: to-0 Date: Wed, 23 Aug 2023 15:17:10 +0200 Subject: [PATCH 17/55] Fixed errors with ConnectionLog in monitoringService --- .../monitoringservice/Model/ConnectionLog.cs | 24 ++++++++- cppseminar/monitoringservice/Program.cs | 2 +- cppseminar/presentation/Hubs/MonitoringHub.cs | 7 +-- .../Services/MonitoringService.cs | 15 ++---- .../wwwroot/js/monitoring_admin.js | 54 ++++++++++--------- 5 files changed, 61 insertions(+), 41 deletions(-) diff --git a/cppseminar/monitoringservice/Model/ConnectionLog.cs b/cppseminar/monitoringservice/Model/ConnectionLog.cs index a5973701..fee06667 100644 --- a/cppseminar/monitoringservice/Model/ConnectionLog.cs +++ b/cppseminar/monitoringservice/Model/ConnectionLog.cs @@ -1,3 +1,4 @@ +<<<<<<< HEAD namespace monitoringservice.Model; public class ConnectionLog @@ -10,4 +11,25 @@ public ConnectionLog(string? email, string? timestamp) UserEmail = email; Timestamp = timestamp; } -} \ No newline at end of file +} +======= +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + + +namespace monitoringservice.Model +{ + public class ConnectionLog + { + public ConnectionLog(string email, string timestamp){ + UserEmail = email; + Timestamp = timestamp; + } + public ConnectionLog(){ + } + public string UserEmail { get; set; } + public string Timestamp { get; set; } + } +} +>>>>>>> a09bc53 (Fixed errors with ConnectionLog in monitoringService) diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs index 954c9030..256812f9 100644 --- a/cppseminar/monitoringservice/Program.cs +++ b/cppseminar/monitoringservice/Program.cs @@ -3,8 +3,8 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using monitoringservice.Services; using monitoringservice.Model; +using monitoringservice.Services; namespace monitoringservice; diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index 07fd746a..9af1aa01 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -53,10 +53,11 @@ public async Task LogConnection() _monitoringService.LogConnectionAsync(connectionLog); } public async Task GetConnectedUsersRecentAsync(){ - var response = _monitoringService.GetConnectedUsersRecentAsync(); + var response = await _monitoringService.GetConnectedUsersRecentAsync(); + System.Console.WriteLine("Tu je response z monitoring service"); System.Console.WriteLine(response); - var test = JsonSerializer.Serialize(response); - System.Console.WriteLine(test); + // var test = JsonSerializer.Serialize(response); + // System.Console.WriteLine(test); await Clients.Caller.SendAsync("ReceiveUsers", response, "OK"); } } diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs index 4aa9016d..2e10b6d8 100644 --- a/cppseminar/presentation/Services/MonitoringService.cs +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -30,19 +30,14 @@ public MonitoringService(ILogger logger, IConfiguration confi _logger = logger; } - public async Task LogConnectionAsync(ConnectionLog connectionLog) { - var response = await _client.PostAsJsonAsync("monitoring/post/log", connectionLog); - if (response.StatusCode != HttpStatusCode.OK) - { - _logger.LogError("LogConnectionAsync returned " + response.StatusCode); - } - } - - public async Task> GetConnectedUsersRecentAsync() + public async Task GetConnectedUsersRecentAsync() { var response = await _client.GetAsync("monitoring/get/recents"); // monitoring/get/all //var responseJson = await response.Content.ReadAsStringAsync(); - return await response.Content.ReadAsAsync>(); + System.Console.WriteLine("Odpoved z monitoring service"); + System.Console.WriteLine(response); + return response; + // return await response.Content.ReadAsAsync>(); // System.Console.WriteLine(responseJson); // return responseJson; } diff --git a/cppseminar/presentation/wwwroot/js/monitoring_admin.js b/cppseminar/presentation/wwwroot/js/monitoring_admin.js index 379dcd75..8a56e3e9 100644 --- a/cppseminar/presentation/wwwroot/js/monitoring_admin.js +++ b/cppseminar/presentation/wwwroot/js/monitoring_admin.js @@ -10,6 +10,8 @@ async function start() { try { await connection.start(); console.log("SignalR Connected."); + //setInterval(invokeSendMessage, 10000); + invokeSendMessage(); } catch (err) { console.log(err); @@ -25,32 +27,32 @@ connection.onclose(async () => { // Define the ReceiveMessage method so that it can be triggered from the Hub connection.on("ReceiveUsers", (users, message) => { console.log(users) - users.forEach(user => { - const row = document.getElementById(user.email) - const tbl = document.getElementById("userLogs"); - if (row === null){ - const dateNow = Date.now() - const timestamp = new Date(user.timestamp) - tbl.innerHTML += ` - - ${user.email} - - - ${Math.floor((dateNow - timestamp) / 1000)} - - ` - } - else{ - row.innerHTML = ` - ${user.email} - - - ${Math.floor((dateNow - timestamp) / 1000)} - ` - } - console.log(user.email); - console.log(user.timestamp); - }) + // users.forEach(user => { + // const row = document.getElementById(user.email) + // const tbl = document.getElementById("userLogs"); + // if (row === null){ + // const dateNow = Date.now() + // const timestamp = new Date(user.timestamp) + // tbl.innerHTML += ` + // + // ${user.email} + // + // + // ${Math.floor((dateNow - timestamp) / 1000)} + // + // ` + // } + // else{ + // row.innerHTML = ` + // ${user.email} + // + // + // ${Math.floor((dateNow - timestamp) / 1000)} + // ` + // } + // console.log(user.email); + // console.log(user.timestamp); + // }) }); async function invokeSendMessage() { From 936e6ef73f8b0d0a00ef058d28c995ea69d77ede Mon Sep 17 00:00:00 2001 From: to-0 Date: Wed, 23 Aug 2023 15:21:32 +0200 Subject: [PATCH 18/55] Deleted comments --- cppseminar/presentation/Hubs/MonitoringHub.cs | 32 +++++-------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index 9af1aa01..9ab4eed5 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -6,7 +6,6 @@ using presentation.Model; using System.Security.Claims; using Microsoft.AspNetCore.Authorization; -using System.Text.Json; namespace presentation.Hubs @@ -17,7 +16,6 @@ public class MonitoringHub: Hub public MonitoringHub(MonitoringService monitoringService){ _monitoringService = monitoringService; } -<<<<<<< HEAD // public override Task OnConnectedAsync() // { // System.Console.WriteLine("Client connected " + Context.ConnectionId); @@ -30,34 +28,20 @@ public MonitoringHub(MonitoringService monitoringService){ // await base.OnDisconnectedAsync(exception); // } -<<<<<<< HEAD -======= - [Authorize(Policy="Student")] ->>>>>>> 23b70a5 (Added dynamic table refreshing in monitoring page) public async Task SendMessage(string user, string message) -======= - - //[Authorize(Policy="Student")] - public async Task LogConnection() ->>>>>>> 0fcbfd2 (SignalR hub pulls user email from claims + 1st version of connection logging in redis) { - string userEmail = ""; - foreach (Claim claim in Context.User.Claims) { - if (claim.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress") - { - userEmail = claim.Value; - break; - } + System.Console.WriteLine(); + System.Console.WriteLine("SendMessage: " + user + " " + message); + System.Console.WriteLine(Context.User.Claims); + foreach (Claim claim in Context.User.Claims){ + System.Console.WriteLine(claim.Type); + System.Console.WriteLine(claim.Value); } - var connectionLog = new ConnectionLog(userEmail, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); - _monitoringService.LogConnectionAsync(connectionLog); + await Clients.All.SendAsync("ReceiveMessage", user, message); } public async Task GetConnectedUsersRecentAsync(){ - var response = await _monitoringService.GetConnectedUsersRecentAsync(); - System.Console.WriteLine("Tu je response z monitoring service"); + var response = _monitoringService.GetConnectedUsersRecentAsync(); System.Console.WriteLine(response); - // var test = JsonSerializer.Serialize(response); - // System.Console.WriteLine(test); await Clients.Caller.SendAsync("ReceiveUsers", response, "OK"); } } From 6b4a97beaabe7ef0f94e801ee1fd13acaa628817 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Wed, 23 Aug 2023 15:48:00 +0200 Subject: [PATCH 19/55] javascript pinging monitor hub in loop with 2s intervals --- .../Pages/Connection/Index.cshtml | 3 +- .../wwwroot/js/connection_logging.js | 31 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml b/cppseminar/presentation/Pages/Connection/Index.cshtml index 2b109c82..92c286ef 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml @@ -21,7 +21,8 @@
diff --git a/cppseminar/presentation/wwwroot/js/connection_logging.js b/cppseminar/presentation/wwwroot/js/connection_logging.js index 1db03de0..4c9b7e07 100644 --- a/cppseminar/presentation/wwwroot/js/connection_logging.js +++ b/cppseminar/presentation/wwwroot/js/connection_logging.js @@ -9,6 +9,7 @@ async function start() { try { await connection.start(); console.log("SignalR Connected."); + setButtonColor("green"); } catch (err) { console.log(err); @@ -21,32 +22,30 @@ connection.onclose(async () => { await start(); }); -async function invokeSendMessage() { - // Invoke SendMessage on the Hub - try { - await connection.invoke("SendMessage", userEmail, "This is a message " + (new Date).getMilliseconds()); - } catch (err) { - console.error(err); - document.getElementById("errorMessages").textContent = "Unauthorized action"; - } - return false; +function setButtonColor(color) { + document.getElementById("start-logging-button").style.color = color; } -// Define the ReceiveMessage method so that it can be triggered from the Hub +function showLastLog() { + document.getElementById("last-timestamp").innerText = "Last timestamp sent at: " + new Date().toISOString(); +} -async function main() { +async function mainloop() { // Start the connection. await start(); + let counter = 0; while (true) { try { + console.log(counter, "invoking LogConnection..."); await connection.invoke("LogConnection"); + counter += 1; + showLastLog(); } catch (err) { console.error(err); - document.getElementById("errorMessages").textContent = "Unauthorized action"; + setButtonColor("red"); + break; } - break; + await new Promise(resolve => setTimeout(resolve, 2000)); } -} - -main(); +} \ No newline at end of file From d802e376fc9e916ed2e3ff5d5eb287e7407b0241 Mon Sep 17 00:00:00 2001 From: to-0 Date: Wed, 23 Aug 2023 16:09:16 +0200 Subject: [PATCH 20/55] First version of admin monitoring board implemented --- .../Services/StorageService.cs | 2 + cppseminar/presentation/Hubs/MonitoringHub.cs | 38 ++++++------ .../Pages/Admin/Monitoring/Index.cshtml | 18 +++--- .../Services/MonitoringService.cs | 14 +++-- .../wwwroot/js/monitoring_admin.js | 61 ++++++++++--------- 5 files changed, 69 insertions(+), 64 deletions(-) diff --git a/cppseminar/monitoringservice/Services/StorageService.cs b/cppseminar/monitoringservice/Services/StorageService.cs index f263cecb..e7531617 100644 --- a/cppseminar/monitoringservice/Services/StorageService.cs +++ b/cppseminar/monitoringservice/Services/StorageService.cs @@ -18,6 +18,7 @@ public StorageService() public async Task setConnectionlogAsync(ConnectionLog connectionLog) { + System.Console.WriteLine("Setting connection log "+connectionLog.UserEmail); await _db.StringSetAsync(connectionLog.UserEmail, connectionLog.Timestamp); } @@ -38,6 +39,7 @@ public async Task getConnectionLogsJsonAsync() var timestamp = await _db.StringGetAsync(email); connectionLogsList.Add(new ConnectionLog(email, timestamp)); } + System.Console.WriteLine("Get connections returns " + JsonSerializer.Serialize(connectionLogsList)); return JsonSerializer.Serialize(connectionLogsList); } diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index 9ab4eed5..301f08a8 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -6,6 +6,7 @@ using presentation.Model; using System.Security.Claims; using Microsoft.AspNetCore.Authorization; +using System.Text.Json; namespace presentation.Hubs @@ -16,32 +17,29 @@ public class MonitoringHub: Hub public MonitoringHub(MonitoringService monitoringService){ _monitoringService = monitoringService; } - // public override Task OnConnectedAsync() - // { - // System.Console.WriteLine("Client connected " + Context.ConnectionId); - // return base.OnConnectedAsync(); - // } - - // public override async Task OnDisconnectedAsync(Exception? exception) - // { - // System.Console.WriteLine("Client disconnected " + Context.ConnectionId); - // await base.OnDisconnectedAsync(exception); - // } - public async Task SendMessage(string user, string message) + //[Authorize(Policy="Student")] + public async Task LogConnection() { - System.Console.WriteLine(); - System.Console.WriteLine("SendMessage: " + user + " " + message); - System.Console.WriteLine(Context.User.Claims); - foreach (Claim claim in Context.User.Claims){ - System.Console.WriteLine(claim.Type); - System.Console.WriteLine(claim.Value); + string userEmail = ""; + foreach (Claim claim in Context.User.Claims) { + if (claim.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress") + { + userEmail = claim.Value; + break; + } } - await Clients.All.SendAsync("ReceiveMessage", user, message); + var connectionLog = new ConnectionLog(userEmail, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + _monitoringService.LogConnectionAsync(connectionLog); } + + [Authorize(Policy="Administrator")] public async Task GetConnectedUsersRecentAsync(){ - var response = _monitoringService.GetConnectedUsersRecentAsync(); + var response = await _monitoringService.GetConnectedUsersRecentAsync(); + System.Console.WriteLine("Tu je response z monitoring service"); System.Console.WriteLine(response); + // var test = JsonSerializer.Serialize(response); + // System.Console.WriteLine(test); await Clients.Caller.SendAsync("ReceiveUsers", response, "OK"); } } diff --git a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml index 47331803..4da4668f 100644 --- a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml +++ b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml @@ -3,13 +3,12 @@ @model presentation.Pages.Monitoring.IndexModel @{ } - - +
All connected users - +
-
- @foreach (var user in Model.LoggedUsers) + + @* @foreach (var user in Model.LoggedUsers) {
- } - - - + } *@
User email @@ -18,8 +17,8 @@ Last message
@@ -29,9 +28,8 @@ @user.Timestamp
-
\ No newline at end of file + + + \ No newline at end of file diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs index 2e10b6d8..921f4d04 100644 --- a/cppseminar/presentation/Services/MonitoringService.cs +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -30,16 +30,20 @@ public MonitoringService(ILogger logger, IConfiguration confi _logger = logger; } + public async Task LogConnectionAsync(ConnectionLog connectionLog) { + var response = await _client.PostAsJsonAsync("monitoring/post/log", connectionLog); + if (response.StatusCode != HttpStatusCode.OK) + { + _logger.LogError("LogConnectionAsync returned " + response.StatusCode); + } + } + public async Task GetConnectedUsersRecentAsync() { var response = await _client.GetAsync("monitoring/get/recents"); // monitoring/get/all - //var responseJson = await response.Content.ReadAsStringAsync(); System.Console.WriteLine("Odpoved z monitoring service"); System.Console.WriteLine(response); - return response; - // return await response.Content.ReadAsAsync>(); - // System.Console.WriteLine(responseJson); - // return responseJson; + return response; } } diff --git a/cppseminar/presentation/wwwroot/js/monitoring_admin.js b/cppseminar/presentation/wwwroot/js/monitoring_admin.js index 8a56e3e9..e2af059c 100644 --- a/cppseminar/presentation/wwwroot/js/monitoring_admin.js +++ b/cppseminar/presentation/wwwroot/js/monitoring_admin.js @@ -10,8 +10,8 @@ async function start() { try { await connection.start(); console.log("SignalR Connected."); - //setInterval(invokeSendMessage, 10000); - invokeSendMessage(); + setInterval(invokeSendMessage, 10000); + //invokeSendMessage(); } catch (err) { console.log(err); @@ -26,33 +26,36 @@ connection.onclose(async () => { // Define the ReceiveMessage method so that it can be triggered from the Hub connection.on("ReceiveUsers", (users, message) => { - console.log(users) - // users.forEach(user => { - // const row = document.getElementById(user.email) - // const tbl = document.getElementById("userLogs"); - // if (row === null){ - // const dateNow = Date.now() - // const timestamp = new Date(user.timestamp) - // tbl.innerHTML += ` - // - // ${user.email} - // - // - // ${Math.floor((dateNow - timestamp) / 1000)} - // - // ` - // } - // else{ - // row.innerHTML = ` - // ${user.email} - // - // - // ${Math.floor((dateNow - timestamp) / 1000)} - // ` - // } - // console.log(user.email); - // console.log(user.timestamp); - // }) + try{ + users = JSON.parse(users); + console.log(users); + console.log(message); + users.forEach(user => { + const row = document.getElementById(user.UserEmail) + const tbl = document.getElementById("userLogs"); + const dateNow = Date.now() + const timestamp = new Date(user.Timestamp) + if (row === null){ + console.log("HEre"); + const temp = `${user.UserEmail}${Math.floor((dateNow - timestamp) / 1000)}`; + tbl.innerHTML += temp; + } + else{ + row.innerHTML = ` + ${user.UserEmail} + + + ${Math.floor((dateNow - timestamp) / 1000)} + ` + } + console.log(user.UserEmail); + console.log(user.Timestamp); + }) + } + catch (exception){ + console.log(exception); + } + }); async function invokeSendMessage() { From 7ab98d66f016d6907e9779c562c487f784855ce2 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Thu, 24 Aug 2023 09:20:09 +0200 Subject: [PATCH 21/55] Removed debug outputs; changed admin monitoring interval to 1s; prevent student's button from starting multiple mainloops --- cppseminar/monitoringservice/Program.cs | 2 -- cppseminar/monitoringservice/Services/StorageService.cs | 2 -- cppseminar/presentation/Hubs/MonitoringHub.cs | 7 ++----- cppseminar/presentation/Services/MonitoringService.cs | 2 -- cppseminar/presentation/wwwroot/js/connection_logging.js | 6 +++--- cppseminar/presentation/wwwroot/js/monitoring_admin.js | 7 ++----- 6 files changed, 7 insertions(+), 19 deletions(-) diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs index 256812f9..32e7e026 100644 --- a/cppseminar/monitoringservice/Program.cs +++ b/cppseminar/monitoringservice/Program.cs @@ -22,12 +22,10 @@ public static void Main(string[] args) } app.MapGet("/monitoring/get/recents", async (StorageService db) => { - System.Console.WriteLine("GET /monitoring/get/recents"); return await db.getConnectionLogsJsonAsync(); }); app.MapPost("/monitoring/post/log", async (ConnectionLog connectionLog, StorageService db, HttpContext context) => { - System.Console.WriteLine($"POST monitoring/post/log: {connectionLog.UserEmail} {connectionLog.Timestamp}"); if (connectionLog.UserEmail == null || connectionLog.Timestamp == null) { context.Response.StatusCode = 400; diff --git a/cppseminar/monitoringservice/Services/StorageService.cs b/cppseminar/monitoringservice/Services/StorageService.cs index e7531617..f263cecb 100644 --- a/cppseminar/monitoringservice/Services/StorageService.cs +++ b/cppseminar/monitoringservice/Services/StorageService.cs @@ -18,7 +18,6 @@ public StorageService() public async Task setConnectionlogAsync(ConnectionLog connectionLog) { - System.Console.WriteLine("Setting connection log "+connectionLog.UserEmail); await _db.StringSetAsync(connectionLog.UserEmail, connectionLog.Timestamp); } @@ -39,7 +38,6 @@ public async Task getConnectionLogsJsonAsync() var timestamp = await _db.StringGetAsync(email); connectionLogsList.Add(new ConnectionLog(email, timestamp)); } - System.Console.WriteLine("Get connections returns " + JsonSerializer.Serialize(connectionLogsList)); return JsonSerializer.Serialize(connectionLogsList); } diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index 301f08a8..e6b8c34c 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -36,11 +36,8 @@ public async Task LogConnection() [Authorize(Policy="Administrator")] public async Task GetConnectedUsersRecentAsync(){ var response = await _monitoringService.GetConnectedUsersRecentAsync(); - System.Console.WriteLine("Tu je response z monitoring service"); - System.Console.WriteLine(response); - // var test = JsonSerializer.Serialize(response); - // System.Console.WriteLine(test); - await Clients.Caller.SendAsync("ReceiveUsers", response, "OK"); + var str = await response.Content.ReadAsStringAsync(); + await Clients.Caller.SendAsync("ReceiveUsers", str); } } } \ No newline at end of file diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs index 921f4d04..5f68d3ad 100644 --- a/cppseminar/presentation/Services/MonitoringService.cs +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -41,8 +41,6 @@ public async Task LogConnectionAsync(ConnectionLog connectionLog) { public async Task GetConnectedUsersRecentAsync() { var response = await _client.GetAsync("monitoring/get/recents"); // monitoring/get/all - System.Console.WriteLine("Odpoved z monitoring service"); - System.Console.WriteLine(response); return response; } } diff --git a/cppseminar/presentation/wwwroot/js/connection_logging.js b/cppseminar/presentation/wwwroot/js/connection_logging.js index 4c9b7e07..35370cac 100644 --- a/cppseminar/presentation/wwwroot/js/connection_logging.js +++ b/cppseminar/presentation/wwwroot/js/connection_logging.js @@ -31,15 +31,15 @@ function showLastLog() { } async function mainloop() { + if (connection.state === signalR.HubConnectionState.Connected) + return; + // Start the connection. await start(); - let counter = 0; while (true) { try { - console.log(counter, "invoking LogConnection..."); await connection.invoke("LogConnection"); - counter += 1; showLastLog(); } catch (err) { console.error(err); diff --git a/cppseminar/presentation/wwwroot/js/monitoring_admin.js b/cppseminar/presentation/wwwroot/js/monitoring_admin.js index e2af059c..99d0b803 100644 --- a/cppseminar/presentation/wwwroot/js/monitoring_admin.js +++ b/cppseminar/presentation/wwwroot/js/monitoring_admin.js @@ -10,8 +10,7 @@ async function start() { try { await connection.start(); console.log("SignalR Connected."); - setInterval(invokeSendMessage, 10000); - //invokeSendMessage(); + setInterval(invokeSendMessage, 1000); } catch (err) { console.log(err); @@ -25,18 +24,16 @@ connection.onclose(async () => { }); // Define the ReceiveMessage method so that it can be triggered from the Hub -connection.on("ReceiveUsers", (users, message) => { +connection.on("ReceiveUsers", (users) => { try{ users = JSON.parse(users); console.log(users); - console.log(message); users.forEach(user => { const row = document.getElementById(user.UserEmail) const tbl = document.getElementById("userLogs"); const dateNow = Date.now() const timestamp = new Date(user.Timestamp) if (row === null){ - console.log("HEre"); const temp = `${user.UserEmail}${Math.floor((dateNow - timestamp) / 1000)}`; tbl.innerHTML += temp; } From 74154860807fd20b829e21a55f544c87fe71d03f Mon Sep 17 00:00:00 2001 From: to-0 Date: Thu, 24 Aug 2023 09:20:32 +0200 Subject: [PATCH 22/55] Deleting comments --- cppseminar/presentation/wwwroot/js/monitoring_admin.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cppseminar/presentation/wwwroot/js/monitoring_admin.js b/cppseminar/presentation/wwwroot/js/monitoring_admin.js index 99d0b803..2de24d21 100644 --- a/cppseminar/presentation/wwwroot/js/monitoring_admin.js +++ b/cppseminar/presentation/wwwroot/js/monitoring_admin.js @@ -1,6 +1,3 @@ -// setInterval(()=>{ -// var response = fetch("http://localhost:8080/monitoring/getUsers") -// },5000) const connection = new signalR.HubConnectionBuilder() .withUrl("/monitor") .configureLogging(signalR.LogLevel.Information) @@ -31,7 +28,8 @@ connection.on("ReceiveUsers", (users) => { users.forEach(user => { const row = document.getElementById(user.UserEmail) const tbl = document.getElementById("userLogs"); - const dateNow = Date.now() + const dateNow = new Date(); + console.log("Date now", dateNow); const timestamp = new Date(user.Timestamp) if (row === null){ const temp = `${user.UserEmail}${Math.floor((dateNow - timestamp) / 1000)}`; From c0a2f8bd1ec9aeb4c77cc4d1cc5e9ab2478b5ec4 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Thu, 24 Aug 2023 09:27:47 +0200 Subject: [PATCH 23/55] refactoring in monitoring_admin.js --- .../wwwroot/js/monitoring_admin.js | 50 +++++++++---------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/cppseminar/presentation/wwwroot/js/monitoring_admin.js b/cppseminar/presentation/wwwroot/js/monitoring_admin.js index 2de24d21..25f14d6d 100644 --- a/cppseminar/presentation/wwwroot/js/monitoring_admin.js +++ b/cppseminar/presentation/wwwroot/js/monitoring_admin.js @@ -7,7 +7,6 @@ async function start() { try { await connection.start(); console.log("SignalR Connected."); - setInterval(invokeSendMessage, 1000); } catch (err) { console.log(err); @@ -22,50 +21,47 @@ connection.onclose(async () => { // Define the ReceiveMessage method so that it can be triggered from the Hub connection.on("ReceiveUsers", (users) => { - try{ + try { users = JSON.parse(users); - console.log(users); - users.forEach(user => { - const row = document.getElementById(user.UserEmail) - const tbl = document.getElementById("userLogs"); - const dateNow = new Date(); - console.log("Date now", dateNow); - const timestamp = new Date(user.Timestamp) - if (row === null){ - const temp = `${user.UserEmail}${Math.floor((dateNow - timestamp) / 1000)}`; - tbl.innerHTML += temp; - } - else{ - row.innerHTML = ` - ${user.UserEmail} - - - ${Math.floor((dateNow - timestamp) / 1000)} - ` - } - console.log(user.UserEmail); - console.log(user.Timestamp); - }) + // console.log(users); + users.forEach(user => { + const row = document.getElementById(user.UserEmail) + const tbl = document.getElementById("userLogs"); + const dateNow = Date.now() + const timestamp = new Date(user.Timestamp) + if (row === null) { + const temp = `${user.UserEmail}${Math.floor((dateNow - timestamp) / 1000)}`; + tbl.innerHTML += temp; + } + else { + row.innerHTML = ` + ${user.UserEmail} + + + ${Math.floor((dateNow - timestamp) / 1000)} + ` + } + }) } catch (exception){ console.log(exception); } - }); -async function invokeSendMessage() { +async function invokeGetConnectedUsersRecentAsync() { // Invoke SendMessage on the Hub try { await connection.invoke("GetConnectedUsersRecentAsync"); } catch (err) { console.error(err); } - return false; } async function main() { // Start the connection. await start(); + + setInterval(invokeGetConnectedUsersRecentAsync, 1000); } main(); \ No newline at end of file From 578735f1d7bdfd87c5ec4cf2238bd4bc27ff5696 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Thu, 24 Aug 2023 11:38:19 +0200 Subject: [PATCH 24/55] added error logging to monitoringservice --- cppseminar/monitoringservice/Program.cs | 39 ++++++++++++++++--- .../Services/StorageService.cs | 5 ++- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs index 32e7e026..cf912e71 100644 --- a/cppseminar/monitoringservice/Program.cs +++ b/cppseminar/monitoringservice/Program.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using monitoringservice.Model; using monitoringservice.Services; @@ -20,21 +21,49 @@ public static void Main(string[] args) { app.UseExceptionHandler("/Error"); } + app.Use((context, next) => + { + context.Request.EnableBuffering(); + return next(); + }); + + var logger = app.Services.GetRequiredService>(); - app.MapGet("/monitoring/get/recents", async (StorageService db) => { - return await db.getConnectionLogsJsonAsync(); + app.MapGet("/monitoring/get/recents", async (StorageService db, HttpContext context) => { + try + { + return await db.getConnectionLogsJsonAsync(); + } + catch (Exception e) + { + logger.LogError("Exception occured while retrieving all ConnectionLog records. " + e); + context.Response.StatusCode = 500; + return ""; + } }); app.MapPost("/monitoring/post/log", async (ConnectionLog connectionLog, StorageService db, HttpContext context) => { if (connectionLog.UserEmail == null || connectionLog.Timestamp == null) - { + { + context.Request.Body.Position = 0; + string body = await new StreamReader(context.Request.Body).ReadToEndAsync(); + logger.LogWarning($"ConnectionLog not found in the request: {body}"); context.Response.StatusCode = 400; return ""; } else { - await db.setConnectionlogAsync(connectionLog); - return ""; + try + { + await db.setConnectionlogAsync(connectionLog); + return ""; + } + catch (Exception e) + { + logger.LogError("Exception occured while logging user connection. " + e); + context.Response.StatusCode = 500; + return ""; + } } }); diff --git a/cppseminar/monitoringservice/Services/StorageService.cs b/cppseminar/monitoringservice/Services/StorageService.cs index f263cecb..69da0198 100644 --- a/cppseminar/monitoringservice/Services/StorageService.cs +++ b/cppseminar/monitoringservice/Services/StorageService.cs @@ -1,13 +1,14 @@ using StackExchange.Redis; using System.Text.Json; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using monitoringservice.Model; namespace monitoringservice.Services; public class StorageService { - private IDatabase _db; - private IServer _server; + private readonly IDatabase _db; + private readonly IServer _server; public StorageService() { From a930552789d597c51fe2dbcc8ae492133689eb7b Mon Sep 17 00:00:00 2001 From: to-0 Date: Thu, 24 Aug 2023 11:42:33 +0200 Subject: [PATCH 25/55] Moved last seen calculation to presentation service --- cppseminar/docker-compose.yml | 2 ++ .../monitoringservice/Model/ConnectionLog.cs | 4 +-- .../Services/StorageService.cs | 20 ++++++++---- .../Converters/DateTimeDifferenceConverter.cs | 32 +++++++++++++++++++ cppseminar/presentation/Hubs/MonitoringHub.cs | 11 +++++-- .../presentation/Model/ConnectionLog.cs | 11 +++++-- .../presentation/Model/ConnectionLogRest.cs | 14 ++++++++ .../Services/MonitoringService.cs | 2 ++ .../wwwroot/js/monitoring_admin.js | 30 +++++++---------- 9 files changed, 93 insertions(+), 33 deletions(-) create mode 100644 cppseminar/presentation/Converters/DateTimeDifferenceConverter.cs create mode 100644 cppseminar/presentation/Model/ConnectionLogRest.cs diff --git a/cppseminar/docker-compose.yml b/cppseminar/docker-compose.yml index bbac98c7..eae27065 100644 --- a/cppseminar/docker-compose.yml +++ b/cppseminar/docker-compose.yml @@ -40,6 +40,7 @@ services: - ./presentation/Services:/src/Services - ./presentation/wwwroot:/src/wwwroot - ./presentation/Hubs:/src/Hubs + - ./presentation/Converters:/src/Converters networks: - sharednet ports: @@ -59,6 +60,7 @@ services: restart: always depends_on: - rabbitmq.local + - monitoringservice.local userservice.local: build: diff --git a/cppseminar/monitoringservice/Model/ConnectionLog.cs b/cppseminar/monitoringservice/Model/ConnectionLog.cs index fee06667..9053c276 100644 --- a/cppseminar/monitoringservice/Model/ConnectionLog.cs +++ b/cppseminar/monitoringservice/Model/ConnectionLog.cs @@ -22,14 +22,14 @@ namespace monitoringservice.Model { public class ConnectionLog { - public ConnectionLog(string email, string timestamp){ + public ConnectionLog(string email, DateTime timestamp){ UserEmail = email; Timestamp = timestamp; } public ConnectionLog(){ } public string UserEmail { get; set; } - public string Timestamp { get; set; } + public DateTime Timestamp { get; set; } } } >>>>>>> a09bc53 (Fixed errors with ConnectionLog in monitoringService) diff --git a/cppseminar/monitoringservice/Services/StorageService.cs b/cppseminar/monitoringservice/Services/StorageService.cs index 69da0198..e522a366 100644 --- a/cppseminar/monitoringservice/Services/StorageService.cs +++ b/cppseminar/monitoringservice/Services/StorageService.cs @@ -19,7 +19,7 @@ public StorageService() public async Task setConnectionlogAsync(ConnectionLog connectionLog) { - await _db.StringSetAsync(connectionLog.UserEmail, connectionLog.Timestamp); + await _db.StringSetAsync(connectionLog.UserEmail, connectionLog.Timestamp.ToString()); } public async Task getValueAsync(string Key) @@ -34,12 +34,18 @@ public async Task getConnectionLogsJsonAsync() List connectionLogsList = new List(); var emails = _server.Keys(); - foreach (var email in emails) - { - var timestamp = await _db.StringGetAsync(email); - connectionLogsList.Add(new ConnectionLog(email, timestamp)); + try{ + foreach (var email in emails) + { + var timestamp = await _db.StringGetAsync(email); + connectionLogsList.Add(new ConnectionLog(email, DateTime.Parse(timestamp))); + } + System.Console.WriteLine(JsonSerializer.Serialize(connectionLogsList)); + return JsonSerializer.Serialize(connectionLogsList); } - - return JsonSerializer.Serialize(connectionLogsList); + catch (Exception e){ + return ""; + } + } } \ No newline at end of file diff --git a/cppseminar/presentation/Converters/DateTimeDifferenceConverter.cs b/cppseminar/presentation/Converters/DateTimeDifferenceConverter.cs new file mode 100644 index 00000000..799eeb41 --- /dev/null +++ b/cppseminar/presentation/Converters/DateTimeDifferenceConverter.cs @@ -0,0 +1,32 @@ +using System; +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace presentation.Converters; +public class DateTimeDifferenceConverter : JsonConverter +{ + // when deserializing takes the timestamp string value and calculates the time difference between timestamp and current time, returns the result in string format + public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + string dateTimeStr = reader.GetString(); + DateTime timestamp = DateTime.Parse(dateTimeStr, CultureInfo.InvariantCulture); + + TimeSpan difference = DateTime.UtcNow - timestamp; + double secondsDifference = difference.TotalSeconds; + + return secondsDifference.ToString(); + } + + throw new JsonException($"Unexpected token type: {reader.TokenType}"); + } + + public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) + { + writer.WriteStringValue(value); + } +} + + diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index e6b8c34c..4a6de4af 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -7,6 +7,7 @@ using System.Security.Claims; using Microsoft.AspNetCore.Authorization; using System.Text.Json; +using System.Collections.Generic; namespace presentation.Hubs @@ -29,15 +30,19 @@ public async Task LogConnection() break; } } - var connectionLog = new ConnectionLog(userEmail, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); - _monitoringService.LogConnectionAsync(connectionLog); + var connectionLog = new ConnectionLog(userEmail, DateTime.UtcNow); + await _monitoringService.LogConnectionAsync(connectionLog); } [Authorize(Policy="Administrator")] public async Task GetConnectedUsersRecentAsync(){ var response = await _monitoringService.GetConnectedUsersRecentAsync(); var str = await response.Content.ReadAsStringAsync(); - await Clients.Caller.SendAsync("ReceiveUsers", str); + System.Console.WriteLine("Tu je str"); + System.Console.WriteLine(str); + List test = JsonSerializer.Deserialize>(str); + var new_response = JsonSerializer.Serialize(test); + await Clients.Caller.SendAsync("ReceiveUsers", new_response); } } } \ No newline at end of file diff --git a/cppseminar/presentation/Model/ConnectionLog.cs b/cppseminar/presentation/Model/ConnectionLog.cs index 0d1d4a73..e24d8bc5 100644 --- a/cppseminar/presentation/Model/ConnectionLog.cs +++ b/cppseminar/presentation/Model/ConnectionLog.cs @@ -1,13 +1,18 @@ +using System; +using System.Text.Json.Serialization; + + namespace presentation.Model; public class ConnectionLog { - public string? UserEmail { get; set; } - public string? Timestamp { get; set; } + public string UserEmail { get; set; } + public DateTime Timestamp { get; set; } - public ConnectionLog(string? email, string? timestamp) + public ConnectionLog(string email, DateTime timestamp) { UserEmail = email; Timestamp = timestamp; } + } \ No newline at end of file diff --git a/cppseminar/presentation/Model/ConnectionLogRest.cs b/cppseminar/presentation/Model/ConnectionLogRest.cs new file mode 100644 index 00000000..c269c1e6 --- /dev/null +++ b/cppseminar/presentation/Model/ConnectionLogRest.cs @@ -0,0 +1,14 @@ +using System; +using System.Text.Json.Serialization; +using presentation.Converters; + +namespace presentation.Model; + +public class ConnectionLogRest +{ + public string UserEmail { get; set; } + [JsonPropertyName("Timestamp")] + [JsonConverter(typeof(DateTimeDifferenceConverter))] + public string Seconds { get; set; } + +} \ No newline at end of file diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs index 5f68d3ad..dcda13aa 100644 --- a/cppseminar/presentation/Services/MonitoringService.cs +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -41,6 +41,8 @@ public async Task LogConnectionAsync(ConnectionLog connectionLog) { public async Task GetConnectedUsersRecentAsync() { var response = await _client.GetAsync("monitoring/get/recents"); // monitoring/get/all + System.Console.WriteLine("Tu je v monitorign service presentation"); + System.Console.WriteLine(response.Content); return response; } } diff --git a/cppseminar/presentation/wwwroot/js/monitoring_admin.js b/cppseminar/presentation/wwwroot/js/monitoring_admin.js index 25f14d6d..ad571e05 100644 --- a/cppseminar/presentation/wwwroot/js/monitoring_admin.js +++ b/cppseminar/presentation/wwwroot/js/monitoring_admin.js @@ -23,24 +23,18 @@ connection.onclose(async () => { connection.on("ReceiveUsers", (users) => { try { users = JSON.parse(users); - // console.log(users); + const tbl = document.getElementById("userLogs"); + tbl.innerHTML = ` + + User email + + + Last message + + `; users.forEach(user => { - const row = document.getElementById(user.UserEmail) - const tbl = document.getElementById("userLogs"); - const dateNow = Date.now() - const timestamp = new Date(user.Timestamp) - if (row === null) { - const temp = `${user.UserEmail}${Math.floor((dateNow - timestamp) / 1000)}`; - tbl.innerHTML += temp; - } - else { - row.innerHTML = ` - ${user.UserEmail} - - - ${Math.floor((dateNow - timestamp) / 1000)} - ` - } + tbl.innerHTML += `${user.UserEmail}${Math.round(user.Timestamp * 100) / 100 + } seconds ago`; }) } catch (exception){ @@ -61,7 +55,7 @@ async function main() { // Start the connection. await start(); - setInterval(invokeGetConnectedUsersRecentAsync, 1000); + setInterval(invokeGetConnectedUsersRecentAsync, 2000); } main(); \ No newline at end of file From 04ae1c23c453185cf9da99c0ade345fb384a140d Mon Sep 17 00:00:00 2001 From: to-0 Date: Thu, 24 Aug 2023 11:55:11 +0200 Subject: [PATCH 26/55] Removed console logs --- .../monitoringservice/Services/StorageService.cs | 1 - .../Converters/DateTimeDifferenceConverter.cs | 14 ++++++++++---- cppseminar/presentation/Hubs/MonitoringHub.cs | 6 ++---- .../presentation/Services/MonitoringService.cs | 2 -- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/cppseminar/monitoringservice/Services/StorageService.cs b/cppseminar/monitoringservice/Services/StorageService.cs index e522a366..b37a7df8 100644 --- a/cppseminar/monitoringservice/Services/StorageService.cs +++ b/cppseminar/monitoringservice/Services/StorageService.cs @@ -40,7 +40,6 @@ public async Task getConnectionLogsJsonAsync() var timestamp = await _db.StringGetAsync(email); connectionLogsList.Add(new ConnectionLog(email, DateTime.Parse(timestamp))); } - System.Console.WriteLine(JsonSerializer.Serialize(connectionLogsList)); return JsonSerializer.Serialize(connectionLogsList); } catch (Exception e){ diff --git a/cppseminar/presentation/Converters/DateTimeDifferenceConverter.cs b/cppseminar/presentation/Converters/DateTimeDifferenceConverter.cs index 799eeb41..84d1ebae 100644 --- a/cppseminar/presentation/Converters/DateTimeDifferenceConverter.cs +++ b/cppseminar/presentation/Converters/DateTimeDifferenceConverter.cs @@ -12,12 +12,18 @@ public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonS if (reader.TokenType == JsonTokenType.String) { string dateTimeStr = reader.GetString(); - DateTime timestamp = DateTime.Parse(dateTimeStr, CultureInfo.InvariantCulture); + try{ + DateTime timestamp = DateTime.Parse(dateTimeStr, CultureInfo.InvariantCulture); - TimeSpan difference = DateTime.UtcNow - timestamp; - double secondsDifference = difference.TotalSeconds; + TimeSpan difference = DateTime.UtcNow - timestamp; + double secondsDifference = difference.TotalSeconds; - return secondsDifference.ToString(); + return secondsDifference.ToString(); + } + catch (Exception e){ + throw new Exception($"Deserialization failed {e}"); + } + } throw new JsonException($"Unexpected token type: {reader.TokenType}"); diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index 4a6de4af..fa33ab79 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -38,10 +38,8 @@ public async Task LogConnection() public async Task GetConnectedUsersRecentAsync(){ var response = await _monitoringService.GetConnectedUsersRecentAsync(); var str = await response.Content.ReadAsStringAsync(); - System.Console.WriteLine("Tu je str"); - System.Console.WriteLine(str); - List test = JsonSerializer.Deserialize>(str); - var new_response = JsonSerializer.Serialize(test); + List transformedLogs = JsonSerializer.Deserialize>(str); + var new_response = JsonSerializer.Serialize(transformedLogs); await Clients.Caller.SendAsync("ReceiveUsers", new_response); } } diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs index dcda13aa..5f68d3ad 100644 --- a/cppseminar/presentation/Services/MonitoringService.cs +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -41,8 +41,6 @@ public async Task LogConnectionAsync(ConnectionLog connectionLog) { public async Task GetConnectedUsersRecentAsync() { var response = await _client.GetAsync("monitoring/get/recents"); // monitoring/get/all - System.Console.WriteLine("Tu je v monitorign service presentation"); - System.Console.WriteLine(response.Content); return response; } } From 31f2056900f176c8ae5a0b6debf2f07ef5f0ebe2 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Thu, 24 Aug 2023 12:17:52 +0200 Subject: [PATCH 27/55] Monitoring logging in presentation service --- cppseminar/presentation/Hubs/MonitoringHub.cs | 18 ++++++---- .../Pages/Admin/Monitoring/Index.cshtml | 12 ------- .../Pages/Admin/Monitoring/Index.cshtml.cs | 12 +------ .../Services/MonitoringService.cs | 35 +++++++++++++++---- 4 files changed, 42 insertions(+), 35 deletions(-) diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index fa33ab79..63bd7fec 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -19,7 +19,7 @@ public MonitoringHub(MonitoringService monitoringService){ _monitoringService = monitoringService; } - //[Authorize(Policy="Student")] + [Authorize] public async Task LogConnection() { string userEmail = ""; @@ -36,11 +36,17 @@ public async Task LogConnection() [Authorize(Policy="Administrator")] public async Task GetConnectedUsersRecentAsync(){ - var response = await _monitoringService.GetConnectedUsersRecentAsync(); - var str = await response.Content.ReadAsStringAsync(); - List transformedLogs = JsonSerializer.Deserialize>(str); - var new_response = JsonSerializer.Serialize(transformedLogs); - await Clients.Caller.SendAsync("ReceiveUsers", new_response); + var responseJson = await _monitoringService.GetConnectedUsersRecentAsync(); + if (responseJson == null) + { + // TODO: invoke some function for admin + } + else + { + List transformedLogs = JsonSerializer.Deserialize>(responseJson); + var newResponse = JsonSerializer.Serialize(transformedLogs); + await Clients.Caller.SendAsync("ReceiveUsers", newResponse); + } } } } \ No newline at end of file diff --git a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml index 4da4668f..8b55ab4b 100644 --- a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml +++ b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml @@ -17,18 +17,6 @@ Last message - - @* @foreach (var user in Model.LoggedUsers) - { - - - @user.UserEmail - - - @user.Timestamp - - - } *@ diff --git a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs index ea8a5922..907256b0 100644 --- a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs @@ -15,16 +15,6 @@ namespace presentation.Pages.Monitoring { public class IndexModel : PageModel { - private ILogger _logger = null; - [BindProperty] - public List LoggedUsers{get;set;} - private readonly MonitoringService _monitoringService = null; - - public IndexModel(ILogger logger, MonitoringService monitoringService) - { - _logger = logger; - _monitoringService = monitoringService; - LoggedUsers = new List(); - } + } } diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs index 5f68d3ad..c381cb7a 100644 --- a/cppseminar/presentation/Services/MonitoringService.cs +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -31,17 +31,40 @@ public MonitoringService(ILogger logger, IConfiguration confi } public async Task LogConnectionAsync(ConnectionLog connectionLog) { - var response = await _client.PostAsJsonAsync("monitoring/post/log", connectionLog); - if (response.StatusCode != HttpStatusCode.OK) + try { - _logger.LogError("LogConnectionAsync returned " + response.StatusCode); + var response = await _client.PostAsJsonAsync("monitoring/post/log", connectionLog); + if (response.StatusCode != HttpStatusCode.OK) + { + _logger.LogError("LogConnectionAsync returned " + response.StatusCode); + } + } + catch (Exception e) + { + _logger.LogError("LogConnectionAsync failed. " + e); } } - public async Task GetConnectedUsersRecentAsync() + public async Task GetConnectedUsersRecentAsync() { - var response = await _client.GetAsync("monitoring/get/recents"); // monitoring/get/all - return response; + try + { + var response = await _client.GetAsync("monitoring/get/recents"); // monitoring/get/all + if (response.StatusCode != HttpStatusCode.OK) + { + _logger.LogError("GetConnectedUsersRecentAsync returned " + response.StatusCode); + return null; + } + else + { + return await response.Content.ReadAsStringAsync(); + } + } + catch (Exception e) + { + _logger.LogError("GetConnectedUsersRecentAsync failed. " + e); + return null; + } } } From 5f105a5db217e8c9a44985fc3c7852ed4851fb70 Mon Sep 17 00:00:00 2001 From: to-0 Date: Wed, 30 Aug 2023 11:06:02 +0200 Subject: [PATCH 28/55] Nothing From dd9dcca8514ca33264bb17e2a84685f798cc4847 Mon Sep 17 00:00:00 2001 From: to-0 Date: Thu, 24 Aug 2023 12:36:12 +0200 Subject: [PATCH 29/55] Fixed getting user email from Claims in monitoring hub --- cppseminar/presentation/Hubs/MonitoringHub.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index 63bd7fec..d5c2b3d4 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -22,14 +22,7 @@ public MonitoringHub(MonitoringService monitoringService){ [Authorize] public async Task LogConnection() { - string userEmail = ""; - foreach (Claim claim in Context.User.Claims) { - if (claim.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress") - { - userEmail = claim.Value; - break; - } - } + string userEmail = Context.User.FindFirst(claim => claim.Type == ClaimTypes.Email).Value; var connectionLog = new ConnectionLog(userEmail, DateTime.UtcNow); await _monitoringService.LogConnectionAsync(connectionLog); } From c29666572d6d5dca4e25a144383ec006292b604a Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Fri, 25 Aug 2023 10:49:22 +0200 Subject: [PATCH 30/55] User now connects and starts pinging automatically on visiting /connection --- .../Pages/Connection/Index.cshtml | 17 ++----- .../wwwroot/js/connection_logging.js | 50 +++++++++---------- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml b/cppseminar/presentation/Pages/Connection/Index.cshtml index 92c286ef..7ad3db34 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml @@ -7,23 +7,16 @@ @section JavaScript { - - @if(User.Identity.IsAuthenticated) + + @if(User.Identity.IsAuthenticated) { - } - }

Connection checker

-

This page is used to check whether the student is still connected to our network.

- Start logging connection. -

Last timestamp sent at: ---

+

Connection status: Not started

+

-
-
- +
\ No newline at end of file diff --git a/cppseminar/presentation/wwwroot/js/connection_logging.js b/cppseminar/presentation/wwwroot/js/connection_logging.js index 35370cac..5018ba4c 100644 --- a/cppseminar/presentation/wwwroot/js/connection_logging.js +++ b/cppseminar/presentation/wwwroot/js/connection_logging.js @@ -1,51 +1,49 @@ -console.log("Test", userEmail); - const connection = new signalR.HubConnectionBuilder() .withUrl("/monitor") .configureLogging(signalR.LogLevel.Information) .build(); -async function start() { - try { - await connection.start(); - console.log("SignalR Connected."); - setButtonColor("green"); - } - catch (err) { - console.log(err); - setTimeout(start, 5000); - } -}; - connection.onclose(async () => { console.log("Connection closed."); await start(); }); -function setButtonColor(color) { - document.getElementById("start-logging-button").style.color = color; +function setConnectionStatusDisplay(status, color) { + let elem = document.getElementById("connection-status"); + elem.style.color = color; + elem.innerText = "Connection status: " + status; } function showLastLog() { - document.getElementById("last-timestamp").innerText = "Last timestamp sent at: " + new Date().toISOString(); + document.getElementById("last-timestamp").innerText = "Last timestamp sent at: " + new Date().toLocaleTimeString(); } async function mainloop() { - if (connection.state === signalR.HubConnectionState.Connected) - return; - - // Start the connection. - await start(); - - while (true) { + while (true) { try { await connection.invoke("LogConnection"); showLastLog(); } catch (err) { console.error(err); - setButtonColor("red"); + setConnectionStatusDisplay("Error when invoking LogConnection", "red"); break; } await new Promise(resolve => setTimeout(resolve, 2000)); } -} \ No newline at end of file +} + +async function start() { + try { + await connection.start(); + console.log("SignalR Connected."); + setConnectionStatusDisplay("Connected", "green"); + mainloop(); + } + catch (err) { + console.log(err); + setConnectionStatusDisplay("Unable to connect", "red"); + setTimeout(start, 5000); + } +} + +start(); \ No newline at end of file From ac2e5f4534ee14f868b9ec6bc005b165b3362369 Mon Sep 17 00:00:00 2001 From: to-0 Date: Fri, 25 Aug 2023 11:13:02 +0200 Subject: [PATCH 31/55] Coloring of monitoring page, admin gets notified when getting user fails or the connection closes --- cppseminar/presentation/Hubs/MonitoringHub.cs | 1 + .../Pages/Admin/Monitoring/Index.cshtml | 2 ++ .../wwwroot/js/monitoring_admin.js | 18 ++++++++++++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index d5c2b3d4..ac11cf77 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -33,6 +33,7 @@ public async Task GetConnectedUsersRecentAsync(){ if (responseJson == null) { // TODO: invoke some function for admin + await Clients.Caller.SendAsync("ErrorGettingUsers", "Monitoring service responded with null"); } else { diff --git a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml index 8b55ab4b..eb13b1c7 100644 --- a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml +++ b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml @@ -3,7 +3,9 @@ @model presentation.Pages.Monitoring.IndexModel @{ } +
+
diff --git a/cppseminar/presentation/wwwroot/js/monitoring_admin.js b/cppseminar/presentation/wwwroot/js/monitoring_admin.js index ad571e05..660cfddd 100644 --- a/cppseminar/presentation/wwwroot/js/monitoring_admin.js +++ b/cppseminar/presentation/wwwroot/js/monitoring_admin.js @@ -6,6 +6,7 @@ const connection = new signalR.HubConnectionBuilder() async function start() { try { await connection.start(); + document.getElementById("alertBox").textContent = ""; console.log("SignalR Connected."); } catch (err) { @@ -16,6 +17,7 @@ async function start() { connection.onclose(async () => { console.log("Connection closed."); + document.getElementById("alertBox").textContent = "Connection closed, trying to start a new connection..."; await start(); }); @@ -32,15 +34,27 @@ connection.on("ReceiveUsers", (users) => { Last message `; + let time = 0; + let color = "black"; users.forEach(user => { - tbl.innerHTML += `${user.UserEmail}${Math.round(user.Timestamp * 100) / 100 - } seconds ago`; + time = Math.round(user.Timestamp * 100) / 100; + if (time > 5 && time < 15){ + color = "orange"; + } + else if (time > 15) { + color = "red"; + } + tbl.innerHTML += `${user.UserEmail}${time} seconds ago`; }) } catch (exception){ console.log(exception); } }); +connection.on("ErrorGettingUsers", (message)=>{ + const box = document.getElementById("alertBox"); + box.textContent = message; +}) async function invokeGetConnectedUsersRecentAsync() { // Invoke SendMessage on the Hub From 1dca20c98de903a95489fe8361891129917d04de Mon Sep 17 00:00:00 2001 From: to-0 Date: Fri, 25 Aug 2023 11:17:46 +0200 Subject: [PATCH 32/55] Refactoring --- cppseminar/presentation/Hubs/MonitoringHub.cs | 2 +- cppseminar/presentation/Model/ConnectionLogRest.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index ac11cf77..1251daae 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -37,7 +37,7 @@ public async Task GetConnectedUsersRecentAsync(){ } else { - List transformedLogs = JsonSerializer.Deserialize>(responseJson); + List transformedLogs = JsonSerializer.Deserialize>(responseJson); var newResponse = JsonSerializer.Serialize(transformedLogs); await Clients.Caller.SendAsync("ReceiveUsers", newResponse); } diff --git a/cppseminar/presentation/Model/ConnectionLogRest.cs b/cppseminar/presentation/Model/ConnectionLogRest.cs index c269c1e6..a191f69a 100644 --- a/cppseminar/presentation/Model/ConnectionLogRest.cs +++ b/cppseminar/presentation/Model/ConnectionLogRest.cs @@ -4,7 +4,7 @@ namespace presentation.Model; -public class ConnectionLogRest +public class ConnectionLogTimeDiff { public string UserEmail { get; set; } [JsonPropertyName("Timestamp")] From a1e7e26e16e9acc39ee4bf652e82b855bec29c59 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Fri, 25 Aug 2023 11:34:55 +0200 Subject: [PATCH 33/55] Admin monitoring of connected users - sort by email --- cppseminar/presentation/Hubs/MonitoringHub.cs | 1 + .../Model/{ConnectionLogRest.cs => ConnectionLogTimeDiff.cs} | 0 2 files changed, 1 insertion(+) rename cppseminar/presentation/Model/{ConnectionLogRest.cs => ConnectionLogTimeDiff.cs} (100%) diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index 1251daae..50363ed6 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -38,6 +38,7 @@ public async Task GetConnectedUsersRecentAsync(){ else { List transformedLogs = JsonSerializer.Deserialize>(responseJson); + transformedLogs.Sort((log1, log2) => string.Compare(log1.UserEmail, log2.UserEmail)); var newResponse = JsonSerializer.Serialize(transformedLogs); await Clients.Caller.SendAsync("ReceiveUsers", newResponse); } diff --git a/cppseminar/presentation/Model/ConnectionLogRest.cs b/cppseminar/presentation/Model/ConnectionLogTimeDiff.cs similarity index 100% rename from cppseminar/presentation/Model/ConnectionLogRest.cs rename to cppseminar/presentation/Model/ConnectionLogTimeDiff.cs From 6c9230c8f7b83f07acc13ed33453dad7570a3f11 Mon Sep 17 00:00:00 2001 From: to-0 Date: Fri, 25 Aug 2023 11:48:50 +0200 Subject: [PATCH 34/55] Refactoring of monitoring_admin.js --- .../wwwroot/js/monitoring_admin.js | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/cppseminar/presentation/wwwroot/js/monitoring_admin.js b/cppseminar/presentation/wwwroot/js/monitoring_admin.js index 660cfddd..40d03326 100644 --- a/cppseminar/presentation/wwwroot/js/monitoring_admin.js +++ b/cppseminar/presentation/wwwroot/js/monitoring_admin.js @@ -3,26 +3,19 @@ const connection = new signalR.HubConnectionBuilder() .configureLogging(signalR.LogLevel.Information) .build(); -async function start() { - try { - await connection.start(); - document.getElementById("alertBox").textContent = ""; - console.log("SignalR Connected."); - } - catch (err) { - console.log(err); - setTimeout(start, 5000); - } -}; connection.onclose(async () => { console.log("Connection closed."); - document.getElementById("alertBox").textContent = "Connection closed, trying to start a new connection..."; + setAlert("Connection closed, trying to start a new connection..."); await start(); }); +function setAlert(message){ + document.getElementById("alertBox").textcontent = message; +} // Define the ReceiveMessage method so that it can be triggered from the Hub connection.on("ReceiveUsers", (users) => { + console.log("Receive users"); try { users = JSON.parse(users); const tbl = document.getElementById("userLogs"); @@ -64,12 +57,34 @@ async function invokeGetConnectedUsersRecentAsync() { console.error(err); } } +async function start() { + try { + await connection.start(); + document.getElementById("alertBox").textContent = ""; + mainloop(); + } + catch (err) { + console.log(err); + setAlert("Unable to connect."); + setTimeout(start, 5000); + } +} -async function main() { - // Start the connection. - await start(); +async function mainloop() { + console.log("Sme po starte"); + + while (true){ + try{ + await connection.invoke("GetConnectedUsersRecentAsync"); + await new Promise(resolve => setTimeout(resolve, 2000)); + console.log("Cau"); + } + catch (err){ + setAlert("Error when invoking GetconnectedUsers"); + break; + } + } - setInterval(invokeGetConnectedUsersRecentAsync, 2000); } -main(); \ No newline at end of file +start(); \ No newline at end of file From 29a070c15b5a1b9749303de9dd3bebdede95a047 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Mon, 28 Aug 2023 09:34:55 +0200 Subject: [PATCH 35/55] Code cleanup - removed some whitespaces --- .../Services/StorageService.cs | 3 +- cppseminar/presentation/Hubs/MonitoringHub.cs | 2 +- .../Pages/Admin/Monitoring/Index.cshtml.cs | 2 +- .../Pages/Admin/Submissions/List.cshtml.cs | 2 +- .../Pages/Admin/TestCase/Edit.cshtml.cs | 51 +++++++++++++++++++ .../Pages/Admin/Users/Index.cshtml | 2 +- .../Pages/Shared/_UserPanel.cshtml | 2 +- .../Pages/Submissions/Detail.cshtml | 4 ++ cppseminar/presentation/Program.cs | 1 - .../Services/MonitoringService.cs | 2 +- cppseminar/presentation/Startup.cs | 2 - .../wwwroot/js/connection_logging.js | 2 +- .../wwwroot/js/monitoring_admin.js | 6 +-- 13 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 cppseminar/presentation/Pages/Admin/TestCase/Edit.cshtml.cs diff --git a/cppseminar/monitoringservice/Services/StorageService.cs b/cppseminar/monitoringservice/Services/StorageService.cs index b37a7df8..6e24f597 100644 --- a/cppseminar/monitoringservice/Services/StorageService.cs +++ b/cppseminar/monitoringservice/Services/StorageService.cs @@ -32,7 +32,7 @@ public async Task setConnectionlogAsync(ConnectionLog connectionLog) public async Task getConnectionLogsJsonAsync() { List connectionLogsList = new List(); - + var emails = _server.Keys(); try{ foreach (var email in emails) @@ -45,6 +45,5 @@ public async Task getConnectionLogsJsonAsync() catch (Exception e){ return ""; } - } } \ No newline at end of file diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index 50363ed6..5e357a37 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -18,7 +18,7 @@ public class MonitoringHub: Hub public MonitoringHub(MonitoringService monitoringService){ _monitoringService = monitoringService; } - + [Authorize] public async Task LogConnection() { diff --git a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs index 907256b0..9ec8c6d3 100644 --- a/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Admin/Monitoring/Index.cshtml.cs @@ -15,6 +15,6 @@ namespace presentation.Pages.Monitoring { public class IndexModel : PageModel { - + } } diff --git a/cppseminar/presentation/Pages/Admin/Submissions/List.cshtml.cs b/cppseminar/presentation/Pages/Admin/Submissions/List.cshtml.cs index 90b83cf8..0c5691f6 100644 --- a/cppseminar/presentation/Pages/Admin/Submissions/List.cshtml.cs +++ b/cppseminar/presentation/Pages/Admin/Submissions/List.cshtml.cs @@ -21,7 +21,7 @@ public ListModel(ILogger logger, SubmissionService submissionService, } public async Task OnGetAsync() - { + { try { if (SelectedUser == "") diff --git a/cppseminar/presentation/Pages/Admin/TestCase/Edit.cshtml.cs b/cppseminar/presentation/Pages/Admin/TestCase/Edit.cshtml.cs new file mode 100644 index 00000000..f8d1482d --- /dev/null +++ b/cppseminar/presentation/Pages/Admin/TestCase/Edit.cshtml.cs @@ -0,0 +1,51 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using presentation.Model; +using presentation.Services; + +namespace presentation.Pages.Admin.TestCase +{ + public class EditModel : PageModel + { + private TestCaseService _testCaseService; + + [BindProperty] + public TestCaseRest TestCase { get; set; } + + private string testCaseId; + + public EditModel(TestCaseService testCaseService) + { + _testCaseService = testCaseService; + } + public async Task OnGetAsync([FromQuery] string caseId) + { + TestCase = await _testCaseService.GetById(caseId); + if (TestCase == null) // Error + { + ModelState.AddModelError(string.Empty, "Failed loading data"); + } + } + public async Task OnPostAsync([FromQuery] string caseId) + { + if (!ModelState.IsValid) + { + ModelState.AddModelError(string.Empty, "Model is not valid"); + return Page(); + } + try + { + // http post resets fields not in form and it ignores bindnever attribute, thats why we call updateTest with caseId from query + await _testCaseService.UpdateTest(caseId, TestCase); + return RedirectToPage("/Admin/TestCase/Index"); + } + catch (Exception) + { + ModelState.AddModelError(string.Empty, "Failed updating test case"); + return Page(); + } + } + } +} diff --git a/cppseminar/presentation/Pages/Admin/Users/Index.cshtml b/cppseminar/presentation/Pages/Admin/Users/Index.cshtml index c46f51ca..f9a2f16f 100644 --- a/cppseminar/presentation/Pages/Admin/Users/Index.cshtml +++ b/cppseminar/presentation/Pages/Admin/Users/Index.cshtml @@ -14,7 +14,7 @@ @foreach (var user in Model.AllUsers) { - @user + @user } diff --git a/cppseminar/presentation/Pages/Shared/_UserPanel.cshtml b/cppseminar/presentation/Pages/Shared/_UserPanel.cshtml index c90aab54..93ca0be2 100644 --- a/cppseminar/presentation/Pages/Shared/_UserPanel.cshtml +++ b/cppseminar/presentation/Pages/Shared/_UserPanel.cshtml @@ -1,4 +1,4 @@ -@using System.Security.Claims; +@using System.Security.Claims; @if(Context.User.Identity.IsAuthenticated) { diff --git a/cppseminar/presentation/Pages/Submissions/Detail.cshtml b/cppseminar/presentation/Pages/Submissions/Detail.cshtml index ae2244a2..f4ebda3f 100644 --- a/cppseminar/presentation/Pages/Submissions/Detail.cshtml +++ b/cppseminar/presentation/Pages/Submissions/Detail.cshtml @@ -59,5 +59,9 @@ else { @await Component.InvokeAsync( "TestList", +<<<<<<< HEAD new { userEmail = User.GetEmail(), submissionId = Model.MySubmission.Id }) +======= + new { userEmail = User.GetEmail(), submissionId = Model.MySubmission.Id}) +>>>>>>> d2a4751 (Code cleanup - removed some whitespaces) } diff --git a/cppseminar/presentation/Program.cs b/cppseminar/presentation/Program.cs index 39db39db..9097242f 100644 --- a/cppseminar/presentation/Program.cs +++ b/cppseminar/presentation/Program.cs @@ -41,7 +41,6 @@ public static IHostBuilder CreateHostBuilder(string[] args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); - }); } return Host.CreateDefaultBuilder(args) diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs index c381cb7a..4e31f1d9 100644 --- a/cppseminar/presentation/Services/MonitoringService.cs +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -27,7 +27,7 @@ public MonitoringService(ILogger logger, IConfiguration confi _client.DefaultRequestHeaders.Accept.Clear(); _client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); - _logger = logger; + _logger = logger; } public async Task LogConnectionAsync(ConnectionLog connectionLog) { diff --git a/cppseminar/presentation/Startup.cs b/cppseminar/presentation/Startup.cs index 56f302e2..ed709c76 100644 --- a/cppseminar/presentation/Startup.cs +++ b/cppseminar/presentation/Startup.cs @@ -117,10 +117,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // { // System.Console.WriteLine("Hello, World!"); // }); - }); app.UseStaticFiles(); - } } } diff --git a/cppseminar/presentation/wwwroot/js/connection_logging.js b/cppseminar/presentation/wwwroot/js/connection_logging.js index 5018ba4c..f57aa28e 100644 --- a/cppseminar/presentation/wwwroot/js/connection_logging.js +++ b/cppseminar/presentation/wwwroot/js/connection_logging.js @@ -19,7 +19,7 @@ function showLastLog() { } async function mainloop() { - while (true) { + while (true) { try { await connection.invoke("LogConnection"); showLastLog(); diff --git a/cppseminar/presentation/wwwroot/js/monitoring_admin.js b/cppseminar/presentation/wwwroot/js/monitoring_admin.js index 40d03326..7c0e761a 100644 --- a/cppseminar/presentation/wwwroot/js/monitoring_admin.js +++ b/cppseminar/presentation/wwwroot/js/monitoring_admin.js @@ -15,7 +15,6 @@ function setAlert(message){ // Define the ReceiveMessage method so that it can be triggered from the Hub connection.on("ReceiveUsers", (users) => { - console.log("Receive users"); try { users = JSON.parse(users); const tbl = document.getElementById("userLogs"); @@ -71,13 +70,10 @@ async function start() { } async function mainloop() { - console.log("Sme po starte"); - while (true){ try{ await connection.invoke("GetConnectedUsersRecentAsync"); - await new Promise(resolve => setTimeout(resolve, 2000)); - console.log("Cau"); + await new Promise(resolve => setTimeout(resolve, 1000)); } catch (err){ setAlert("Error when invoking GetconnectedUsers"); From 1d96070f8cf8eec6badfd7785ff58b47a06ea100 Mon Sep 17 00:00:00 2001 From: to-0 Date: Mon, 28 Aug 2023 11:50:27 +0200 Subject: [PATCH 36/55] Testing extraction if IP adress --- cppseminar/presentation/Hubs/MonitoringHub.cs | 2 +- cppseminar/presentation/Pages/Connection/Index.cshtml.cs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index 5e357a37..e7ba9af3 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -32,11 +32,11 @@ public async Task GetConnectedUsersRecentAsync(){ var responseJson = await _monitoringService.GetConnectedUsersRecentAsync(); if (responseJson == null) { - // TODO: invoke some function for admin await Clients.Caller.SendAsync("ErrorGettingUsers", "Monitoring service responded with null"); } else { + System.Console.WriteLine(responseJson); List transformedLogs = JsonSerializer.Deserialize>(responseJson); transformedLogs.Sort((log1, log2) => string.Compare(log1.UserEmail, log2.UserEmail)); var newResponse = JsonSerializer.Serialize(transformedLogs); diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs index 5ffbd43b..7e7dd75b 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs @@ -15,5 +15,12 @@ public class IndexModel : PageModel { private ILogger _logger; public bool IsAdmin = false; + public async Task OnGetAsync(){ + System.Console.WriteLine(Request.Headers["X-Forwarded-For"]); // this should be able to extract the original IP adress, after it goes through kubernetes + var clientIPAdress = Request.HttpContext.Connection.RemoteIpAddress.ToString(); // extracting ip adress locally + System.Console.WriteLine(); + + } } + } From 438e217263daeb3b024ccd4c33b4015f897fad9e Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Mon, 28 Aug 2023 12:54:21 +0200 Subject: [PATCH 37/55] monitoringservice refactoring - now uses controllers + sending lists of objects, not JSONs --- cppseminar/docker-compose.yml | 2 + .../Controllers/MonitoringController.cs | 61 +++++++++++++ cppseminar/monitoringservice/Program.cs | 91 ++++++++----------- .../Services/StorageService.cs | 22 ++--- cppseminar/monitoringservice/Startup.cs | 48 ++++++++++ .../monitoringservice.csproj | 1 + cppseminar/presentation/Hubs/MonitoringHub.cs | 21 +++-- .../Model/ConnectionLogTimeDiff.cs | 13 +-- .../Services/MonitoringService.cs | 4 +- .../wwwroot/js/monitoring_admin.js | 19 ++-- cppseminar/userservice/Program.cs | 2 +- 11 files changed, 192 insertions(+), 92 deletions(-) create mode 100644 cppseminar/monitoringservice/Controllers/MonitoringController.cs create mode 100644 cppseminar/monitoringservice/Startup.cs diff --git a/cppseminar/docker-compose.yml b/cppseminar/docker-compose.yml index eae27065..b4566989 100644 --- a/cppseminar/docker-compose.yml +++ b/cppseminar/docker-compose.yml @@ -282,8 +282,10 @@ services: target: dev volumes: - ./monitoringservice/Program.cs:/src/Program.cs + - ./monitoringservice/Startup.cs:/src/Startup.cs - ./monitoringservice/Model:/src/Model - ./monitoringservice/Services:/src/Services + - ./monitoringservice/Controllers:/src/Controllers - ./monitoringservice/monitoringservice.csproj:/src/monitoringservice.csproj networks: - sharednet diff --git a/cppseminar/monitoringservice/Controllers/MonitoringController.cs b/cppseminar/monitoringservice/Controllers/MonitoringController.cs new file mode 100644 index 00000000..3a9e60e9 --- /dev/null +++ b/cppseminar/monitoringservice/Controllers/MonitoringController.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System.Text.Json; +using monitoringservice.Model; +using monitoringservice.Services; + +namespace monitoringservice.Controllers; + +[Route("monitoring")] +[ApiController] +public class MonitoringController : ControllerBase +{ + private readonly ILogger _logger; + private readonly StorageService _service; + + public MonitoringController(ILogger logger, StorageService service) + { + _logger = logger; // TODO: Why only _logger.LogInformation() works? the other methods don't show in the console. + _service = service; + } + + [HttpGet("get/recents")] + public async Task>> OnGetAsync() + { + try + { + return await _service.getConnectionLogsAsync(); + } + catch (Exception e) + { + _logger.LogError("Exception occured while retrieving all ConnectionLog records. " + e); + return StatusCode(500); + } + } + + [HttpPost("post/log")] + public async Task LogConnection([FromBody] ConnectionLog connectionLog) + { + if (connectionLog.UserEmail == null || connectionLog.Timestamp == null) + { + return BadRequest(); + } + else + { + try + { + await _service.setConnectionlogAsync(connectionLog); + return Ok(); + } + catch (Exception e) + { + _logger.LogError("Exception occured while logging user connection. " + e); + return StatusCode(500); + } + } + } +} diff --git a/cppseminar/monitoringservice/Program.cs b/cppseminar/monitoringservice/Program.cs index cf912e71..739b55cc 100644 --- a/cppseminar/monitoringservice/Program.cs +++ b/cppseminar/monitoringservice/Program.cs @@ -1,9 +1,9 @@ using System; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; +using Serilog; +using Serilog.Events; +using Serilog.Formatting.Compact; using monitoringservice.Model; using monitoringservice.Services; @@ -12,62 +12,45 @@ namespace monitoringservice; public class Program { public static void Main(string[] args) - { - var builder = WebApplication.CreateBuilder(args); - builder.Services.AddSingleton(); - var app = builder.Build(); - - if (!app.Environment.IsDevelopment()) + { + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .Enrich.FromLogContext() + .WriteTo.Console(new RenderedCompactJsonFormatter()) + .CreateLogger(); + + try { - app.UseExceptionHandler("/Error"); + Log.Information("Starting web host"); + CreateHostBuilder(args).Build().Run(); } - app.Use((context, next) => + catch (Exception e) { - context.Request.EnableBuffering(); - return next(); - }); - - var logger = app.Services.GetRequiredService>(); - - app.MapGet("/monitoring/get/recents", async (StorageService db, HttpContext context) => { - try - { - return await db.getConnectionLogsJsonAsync(); - } - catch (Exception e) - { - logger.LogError("Exception occured while retrieving all ConnectionLog records. " + e); - context.Response.StatusCode = 500; - return ""; - } - }); + Log.Fatal("Host terminated unexpectedly. {e}", e); + } + finally + { + Log.CloseAndFlush(); + } + } - app.MapPost("/monitoring/post/log", async (ConnectionLog connectionLog, StorageService db, HttpContext context) => { - if (connectionLog.UserEmail == null || connectionLog.Timestamp == null) - { - context.Request.Body.Position = 0; - string body = await new StreamReader(context.Request.Body).ReadToEndAsync(); - logger.LogWarning($"ConnectionLog not found in the request: {body}"); - context.Response.StatusCode = 400; - return ""; - } - else - { - try - { - await db.setConnectionlogAsync(connectionLog); - return ""; - } - catch (Exception e) + public static IHostBuilder CreateHostBuilder(string[] args) + { + if (Environment.GetEnvironmentVariable("LOG_PRETTY") == "1") + { + return Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => { - logger.LogError("Exception occured while logging user connection. " + e); - context.Response.StatusCode = 500; - return ""; - } - } - }); - - app.Run(); + webBuilder.UseStartup(); + }); + } + return Host.CreateDefaultBuilder(args) + .UseSerilog() + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); } } diff --git a/cppseminar/monitoringservice/Services/StorageService.cs b/cppseminar/monitoringservice/Services/StorageService.cs index 6e24f597..053877ed 100644 --- a/cppseminar/monitoringservice/Services/StorageService.cs +++ b/cppseminar/monitoringservice/Services/StorageService.cs @@ -9,12 +9,14 @@ public class StorageService { private readonly IDatabase _db; private readonly IServer _server; + private readonly ILogger _logger; - public StorageService() + public StorageService(ILogger logger) { ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("redis.local"); _db = redis.GetDatabase(); _server = redis.GetServer("redis.local", 6379); + _logger = logger; } public async Task setConnectionlogAsync(ConnectionLog connectionLog) @@ -29,21 +31,17 @@ public async Task setConnectionlogAsync(ConnectionLog connectionLog) } /* This works only when key-value pairs of string-string are in redis */ - public async Task getConnectionLogsJsonAsync() + + public async Task> getConnectionLogsAsync() { List connectionLogsList = new List(); var emails = _server.Keys(); - try{ - foreach (var email in emails) - { - var timestamp = await _db.StringGetAsync(email); - connectionLogsList.Add(new ConnectionLog(email, DateTime.Parse(timestamp))); - } - return JsonSerializer.Serialize(connectionLogsList); - } - catch (Exception e){ - return ""; + foreach (var email in emails) + { + var timestamp = await _db.StringGetAsync(email); + connectionLogsList.Add(new ConnectionLog(email, DateTime.Parse(timestamp))); } + return connectionLogsList; } } \ No newline at end of file diff --git a/cppseminar/monitoringservice/Startup.cs b/cppseminar/monitoringservice/Startup.cs new file mode 100644 index 00000000..dd64d144 --- /dev/null +++ b/cppseminar/monitoringservice/Startup.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +using monitoringservice.Services; +using monitoringservice.Model; + +namespace monitoringservice; + +public class Startup +{ + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(); + services.AddSingleton(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } +} diff --git a/cppseminar/monitoringservice/monitoringservice.csproj b/cppseminar/monitoringservice/monitoringservice.csproj index c53217d3..992fe1ff 100644 --- a/cppseminar/monitoringservice/monitoringservice.csproj +++ b/cppseminar/monitoringservice/monitoringservice.csproj @@ -9,6 +9,7 @@ + diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index e7ba9af3..f9c4fff4 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -27,20 +27,23 @@ public async Task LogConnection() await _monitoringService.LogConnectionAsync(connectionLog); } - [Authorize(Policy="Administrator")] - public async Task GetConnectedUsersRecentAsync(){ - var responseJson = await _monitoringService.GetConnectedUsersRecentAsync(); - if (responseJson == null) + [Authorize(Policy="Administrator")] + public async Task GetConnectedUsersRecentAsync() + { + var responseData = await _monitoringService.GetConnectedUsersRecentAsync(); + if (responseData == null) { await Clients.Caller.SendAsync("ErrorGettingUsers", "Monitoring service responded with null"); } else { - System.Console.WriteLine(responseJson); - List transformedLogs = JsonSerializer.Deserialize>(responseJson); - transformedLogs.Sort((log1, log2) => string.Compare(log1.UserEmail, log2.UserEmail)); - var newResponse = JsonSerializer.Serialize(transformedLogs); - await Clients.Caller.SendAsync("ReceiveUsers", newResponse); + var connectionLogTimeDiffList = new List(); + foreach (var connectionLog in responseData) + { + connectionLogTimeDiffList.Add(new ConnectionLogTimeDiff(connectionLog)); + } + connectionLogTimeDiffList.Sort((log1, log2) => string.Compare(log1.UserEmail, log2.UserEmail)); + await Clients.Caller.SendAsync("ReceiveUsers", JsonSerializer.Serialize(connectionLogTimeDiffList)); } } } diff --git a/cppseminar/presentation/Model/ConnectionLogTimeDiff.cs b/cppseminar/presentation/Model/ConnectionLogTimeDiff.cs index a191f69a..8304b0d4 100644 --- a/cppseminar/presentation/Model/ConnectionLogTimeDiff.cs +++ b/cppseminar/presentation/Model/ConnectionLogTimeDiff.cs @@ -1,14 +1,15 @@ using System; -using System.Text.Json.Serialization; -using presentation.Converters; namespace presentation.Model; public class ConnectionLogTimeDiff { public string UserEmail { get; set; } - [JsonPropertyName("Timestamp")] - [JsonConverter(typeof(DateTimeDifferenceConverter))] - public string Seconds { get; set; } - + public double Seconds { get; set; } + + public ConnectionLogTimeDiff(ConnectionLog connectionLog) + { + UserEmail = connectionLog.UserEmail; + Seconds = (double)(DateTime.UtcNow - connectionLog.Timestamp).TotalSeconds; + } } \ No newline at end of file diff --git a/cppseminar/presentation/Services/MonitoringService.cs b/cppseminar/presentation/Services/MonitoringService.cs index 4e31f1d9..b47510b4 100644 --- a/cppseminar/presentation/Services/MonitoringService.cs +++ b/cppseminar/presentation/Services/MonitoringService.cs @@ -45,7 +45,7 @@ public async Task LogConnectionAsync(ConnectionLog connectionLog) { } } - public async Task GetConnectedUsersRecentAsync() + public async Task> GetConnectedUsersRecentAsync() { try { @@ -57,7 +57,7 @@ public async Task GetConnectedUsersRecentAsync() } else { - return await response.Content.ReadAsStringAsync(); + return await response.Content.ReadAsAsync>(); } } catch (Exception e) diff --git a/cppseminar/presentation/wwwroot/js/monitoring_admin.js b/cppseminar/presentation/wwwroot/js/monitoring_admin.js index 7c0e761a..bf8fda1d 100644 --- a/cppseminar/presentation/wwwroot/js/monitoring_admin.js +++ b/cppseminar/presentation/wwwroot/js/monitoring_admin.js @@ -9,8 +9,9 @@ connection.onclose(async () => { setAlert("Connection closed, trying to start a new connection..."); await start(); }); + function setAlert(message){ - document.getElementById("alertBox").textcontent = message; + document.getElementById("alertBox").innerText = message; } // Define the ReceiveMessage method so that it can be triggered from the Hub @@ -29,13 +30,16 @@ connection.on("ReceiveUsers", (users) => { let time = 0; let color = "black"; users.forEach(user => { - time = Math.round(user.Timestamp * 100) / 100; + time = (Math.round(user.Seconds * 100) / 100).toFixed(2); if (time > 5 && time < 15){ color = "orange"; } else if (time > 15) { color = "red"; } + else { + color = "green"; + } tbl.innerHTML += `${user.UserEmail}${time} seconds ago`; }) } @@ -44,8 +48,7 @@ connection.on("ReceiveUsers", (users) => { } }); connection.on("ErrorGettingUsers", (message)=>{ - const box = document.getElementById("alertBox"); - box.textContent = message; + setAlert(message); }) async function invokeGetConnectedUsersRecentAsync() { @@ -59,7 +62,7 @@ async function invokeGetConnectedUsersRecentAsync() { async function start() { try { await connection.start(); - document.getElementById("alertBox").textContent = ""; + setAlert(""); mainloop(); } catch (err) { @@ -71,12 +74,12 @@ async function start() { async function mainloop() { while (true){ - try{ + try { await connection.invoke("GetConnectedUsersRecentAsync"); await new Promise(resolve => setTimeout(resolve, 1000)); } - catch (err){ - setAlert("Error when invoking GetconnectedUsers"); + catch (err) { + setAlert("Error when invoking GetconnectedUsers."); break; } } diff --git a/cppseminar/userservice/Program.cs b/cppseminar/userservice/Program.cs index fd2bbb0b..f6715211 100644 --- a/cppseminar/userservice/Program.cs +++ b/cppseminar/userservice/Program.cs @@ -11,7 +11,7 @@ public class Program { public static void Main(string[] args) { - Log.Logger = new LoggerConfiguration() + Log.Logger = new LoggerConfiguration() .MinimumLevel.Verbose() .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .Enrich.FromLogContext() From e61515274ea394d56bc2c395db84a5450eb02ae0 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Mon, 28 Aug 2023 13:00:18 +0200 Subject: [PATCH 38/55] removed Converters from presentation --- cppseminar/docker-compose.yml | 1 - .../Converters/DateTimeDifferenceConverter.cs | 38 ------------------- 2 files changed, 39 deletions(-) delete mode 100644 cppseminar/presentation/Converters/DateTimeDifferenceConverter.cs diff --git a/cppseminar/docker-compose.yml b/cppseminar/docker-compose.yml index b4566989..569caf1a 100644 --- a/cppseminar/docker-compose.yml +++ b/cppseminar/docker-compose.yml @@ -40,7 +40,6 @@ services: - ./presentation/Services:/src/Services - ./presentation/wwwroot:/src/wwwroot - ./presentation/Hubs:/src/Hubs - - ./presentation/Converters:/src/Converters networks: - sharednet ports: diff --git a/cppseminar/presentation/Converters/DateTimeDifferenceConverter.cs b/cppseminar/presentation/Converters/DateTimeDifferenceConverter.cs deleted file mode 100644 index 84d1ebae..00000000 --- a/cppseminar/presentation/Converters/DateTimeDifferenceConverter.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Globalization; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace presentation.Converters; -public class DateTimeDifferenceConverter : JsonConverter -{ - // when deserializing takes the timestamp string value and calculates the time difference between timestamp and current time, returns the result in string format - public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.String) - { - string dateTimeStr = reader.GetString(); - try{ - DateTime timestamp = DateTime.Parse(dateTimeStr, CultureInfo.InvariantCulture); - - TimeSpan difference = DateTime.UtcNow - timestamp; - double secondsDifference = difference.TotalSeconds; - - return secondsDifference.ToString(); - } - catch (Exception e){ - throw new Exception($"Deserialization failed {e}"); - } - - } - - throw new JsonException($"Unexpected token type: {reader.TokenType}"); - } - - public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) - { - writer.WriteStringValue(value); - } -} - - From fc04d6c4bc27a501dbfcb5d3123587e932518c35 Mon Sep 17 00:00:00 2001 From: to-0 Date: Mon, 28 Aug 2023 13:24:14 +0200 Subject: [PATCH 39/55] Write out IP adress --- cppseminar/presentation/Pages/Connection/Index.cshtml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs index 7e7dd75b..c22f0c93 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs @@ -18,7 +18,7 @@ public class IndexModel : PageModel public async Task OnGetAsync(){ System.Console.WriteLine(Request.Headers["X-Forwarded-For"]); // this should be able to extract the original IP adress, after it goes through kubernetes var clientIPAdress = Request.HttpContext.Connection.RemoteIpAddress.ToString(); // extracting ip adress locally - System.Console.WriteLine(); + System.Console.WriteLine(clientIPAdress); } } From e15f843815b403f0c7e3343033b3b9a256f4a661 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Mon, 28 Aug 2023 14:58:50 +0200 Subject: [PATCH 40/55] monitoringservice changed log level --- cppseminar/docker-compose.yml | 1 + .../monitoringservice/Controllers/MonitoringController.cs | 2 +- cppseminar/monitoringservice/appsettings.json | 5 +++-- cppseminar/presentation/Pages/Connection/Index.cshtml.cs | 1 - 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cppseminar/docker-compose.yml b/cppseminar/docker-compose.yml index 569caf1a..e782d49b 100644 --- a/cppseminar/docker-compose.yml +++ b/cppseminar/docker-compose.yml @@ -286,6 +286,7 @@ services: - ./monitoringservice/Services:/src/Services - ./monitoringservice/Controllers:/src/Controllers - ./monitoringservice/monitoringservice.csproj:/src/monitoringservice.csproj + - ./monitoringservice/appsettings.json:/src/appsettings.json networks: - sharednet ports: diff --git a/cppseminar/monitoringservice/Controllers/MonitoringController.cs b/cppseminar/monitoringservice/Controllers/MonitoringController.cs index 3a9e60e9..b216c80c 100644 --- a/cppseminar/monitoringservice/Controllers/MonitoringController.cs +++ b/cppseminar/monitoringservice/Controllers/MonitoringController.cs @@ -19,7 +19,7 @@ public class MonitoringController : ControllerBase public MonitoringController(ILogger logger, StorageService service) { - _logger = logger; // TODO: Why only _logger.LogInformation() works? the other methods don't show in the console. + _logger = logger; _service = service; } diff --git a/cppseminar/monitoringservice/appsettings.json b/cppseminar/monitoringservice/appsettings.json index 10f68b8c..5784615a 100644 --- a/cppseminar/monitoringservice/appsettings.json +++ b/cppseminar/monitoringservice/appsettings.json @@ -1,8 +1,9 @@ { "Logging": { "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Default": "Trace", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs index c22f0c93..dd4fa597 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs @@ -19,7 +19,6 @@ public async Task OnGetAsync(){ System.Console.WriteLine(Request.Headers["X-Forwarded-For"]); // this should be able to extract the original IP adress, after it goes through kubernetes var clientIPAdress = Request.HttpContext.Connection.RemoteIpAddress.ToString(); // extracting ip adress locally System.Console.WriteLine(clientIPAdress); - } } From a450cb393838b6f03f9e42c0d3687cbc035c19be Mon Sep 17 00:00:00 2001 From: to-0 Date: Wed, 30 Aug 2023 11:14:30 +0200 Subject: [PATCH 41/55] Removed functions that are not related to signalR and are in other branches, which caused errors in files --- cppseminar/presentation/Pages/Admin/TestCase/Edit.cshtml.cs | 4 ++-- cppseminar/presentation/Pages/Submissions/Detail.cshtml | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cppseminar/presentation/Pages/Admin/TestCase/Edit.cshtml.cs b/cppseminar/presentation/Pages/Admin/TestCase/Edit.cshtml.cs index f8d1482d..e983049c 100644 --- a/cppseminar/presentation/Pages/Admin/TestCase/Edit.cshtml.cs +++ b/cppseminar/presentation/Pages/Admin/TestCase/Edit.cshtml.cs @@ -37,8 +37,8 @@ public async Task OnPostAsync([FromQuery] string caseId) } try { - // http post resets fields not in form and it ignores bindnever attribute, thats why we call updateTest with caseId from query - await _testCaseService.UpdateTest(caseId, TestCase); + // http post resets fields not in form and it ignores bindnever attribute, thats why we call updateTest with caseId from query await _testCaseService.UpdateTest(caseId, TestCase); + return RedirectToPage("/Admin/TestCase/Index"); } catch (Exception) diff --git a/cppseminar/presentation/Pages/Submissions/Detail.cshtml b/cppseminar/presentation/Pages/Submissions/Detail.cshtml index f4ebda3f..04bfe629 100644 --- a/cppseminar/presentation/Pages/Submissions/Detail.cshtml +++ b/cppseminar/presentation/Pages/Submissions/Detail.cshtml @@ -59,9 +59,5 @@ else { @await Component.InvokeAsync( "TestList", -<<<<<<< HEAD - new { userEmail = User.GetEmail(), submissionId = Model.MySubmission.Id }) -======= new { userEmail = User.GetEmail(), submissionId = Model.MySubmission.Id}) ->>>>>>> d2a4751 (Code cleanup - removed some whitespaces) } From 2eee61c18553f5d768fb399d57cf0cec4e9b8e39 Mon Sep 17 00:00:00 2001 From: to-0 Date: Wed, 30 Aug 2023 11:26:34 +0200 Subject: [PATCH 42/55] Merge conflict --- .../monitoringservice/Model/ConnectionLog.cs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/cppseminar/monitoringservice/Model/ConnectionLog.cs b/cppseminar/monitoringservice/Model/ConnectionLog.cs index 9053c276..310e9e8b 100644 --- a/cppseminar/monitoringservice/Model/ConnectionLog.cs +++ b/cppseminar/monitoringservice/Model/ConnectionLog.cs @@ -1,18 +1,3 @@ -<<<<<<< HEAD -namespace monitoringservice.Model; - -public class ConnectionLog -{ - public string? UserEmail { get; set; } - public string? Timestamp { get; set; } - - public ConnectionLog(string? email, string? timestamp) - { - UserEmail = email; - Timestamp = timestamp; - } -} -======= using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -32,4 +17,3 @@ public ConnectionLog(){ public DateTime Timestamp { get; set; } } } ->>>>>>> a09bc53 (Fixed errors with ConnectionLog in monitoringService) From 9ede99c4759305b1c461c2ef05594102ba5ebcde Mon Sep 17 00:00:00 2001 From: to-0 Date: Wed, 30 Aug 2023 13:20:02 +0200 Subject: [PATCH 43/55] Implemented ip filter --- cppseminar/docker-compose.yml | 1 + cppseminar/presentation/Filters/IPFilter.cs | 30 +++++++++++++++++++ .../Pages/Connection/Index.cshtml.cs | 5 ++-- 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 cppseminar/presentation/Filters/IPFilter.cs diff --git a/cppseminar/docker-compose.yml b/cppseminar/docker-compose.yml index e782d49b..2e263574 100644 --- a/cppseminar/docker-compose.yml +++ b/cppseminar/docker-compose.yml @@ -40,6 +40,7 @@ services: - ./presentation/Services:/src/Services - ./presentation/wwwroot:/src/wwwroot - ./presentation/Hubs:/src/Hubs + - ./presentation/Filters:/src/Filters networks: - sharednet ports: diff --git a/cppseminar/presentation/Filters/IPFilter.cs b/cppseminar/presentation/Filters/IPFilter.cs new file mode 100644 index 00000000..887088dc --- /dev/null +++ b/cppseminar/presentation/Filters/IPFilter.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc; +using System.Net; +namespace presentation.Filters; +public class TestIPFilter : ResultFilterAttribute +{ + private readonly IPAddress _allowedIPAddress; + + public TestIPFilter(string allowedIPAddress) + { + IPAddress.TryParse(allowedIPAddress, out _allowedIPAddress); + } + + public override void OnResultExecuting(ResultExecutingContext context) + { + System.Console.WriteLine("On result executing is here"); + string remoteIpAddress = context.HttpContext.Connection.RemoteIpAddress?.ToString(); + + if (remoteIpAddress != _allowedIPAddress?.ToString()) + { + context.Result = new ContentResult + { + StatusCode = (int)HttpStatusCode.Forbidden, + Content = "Access denied." + }; + } + } +} + + diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs index dd4fa597..dcf9725f 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs @@ -5,12 +5,11 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Logging; -using presentation.Model; -using presentation.Services; -using System.Net.Mime; +using presentation.Filters; namespace presentation.Pages.Connection { + [TestIPFilter("178.41.87.254")] public class IndexModel : PageModel { private ILogger _logger; From f94bb54844c0e27e1a2ba48a6d43ef7dd1579be8 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Thu, 31 Aug 2023 09:28:59 +0200 Subject: [PATCH 44/55] IP filter now supports range of IP addresses --- cppseminar/presentation/Filters/IPFilter.cs | 45 ++++++++++++++++--- .../Pages/Connection/Index.cshtml.cs | 15 ++++--- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/cppseminar/presentation/Filters/IPFilter.cs b/cppseminar/presentation/Filters/IPFilter.cs index 887088dc..532b7404 100644 --- a/cppseminar/presentation/Filters/IPFilter.cs +++ b/cppseminar/presentation/Filters/IPFilter.cs @@ -1,22 +1,53 @@ -using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using System; using System.Net; namespace presentation.Filters; + public class TestIPFilter : ResultFilterAttribute { - private readonly IPAddress _allowedIPAddress; + private readonly byte[] _allowedLowerBytes; + private readonly byte[] _allowedUpperBytes; + + public TestIPFilter(string allowedIPLowerStr, string allowedIPUpperStr) + { + IPAddress allowedIPLower; + IPAddress.TryParse(allowedIPLowerStr, out allowedIPLower); + _allowedLowerBytes = allowedIPLower.GetAddressBytes(); + + IPAddress allowedIPUpper; + IPAddress.TryParse(allowedIPUpperStr, out allowedIPUpper); + _allowedUpperBytes = allowedIPUpper.GetAddressBytes(); + + // Check if lower bound is indeed lower + for (int i = 0; i < _allowedLowerBytes.Length; i++) + { + if (_allowedLowerBytes[i] > _allowedUpperBytes[i]) + { + throw new ArgumentException("Invalid range of IP addresses."); + } + } + } - public TestIPFilter(string allowedIPAddress) + private bool AddressWithinRange(IPAddress clientAddress) { - IPAddress.TryParse(allowedIPAddress, out _allowedIPAddress); + byte[] clientAddressBytes = clientAddress.GetAddressBytes(); + for (int i = 0; i < _allowedLowerBytes.Length; i++) + { + if (clientAddressBytes[i] < _allowedLowerBytes[i] || clientAddressBytes[i] > _allowedUpperBytes[i]) + { + return false; + } + } + return true; } public override void OnResultExecuting(ResultExecutingContext context) { - System.Console.WriteLine("On result executing is here"); - string remoteIpAddress = context.HttpContext.Connection.RemoteIpAddress?.ToString(); + IPAddress clientIPAddress; + IPAddress.TryParse(context.HttpContext.Connection.RemoteIpAddress?.ToString(), out clientIPAddress); - if (remoteIpAddress != _allowedIPAddress?.ToString()) + if (!AddressWithinRange(clientIPAddress)) { context.Result = new ContentResult { diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs index dcf9725f..cc092dc8 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs @@ -9,15 +9,20 @@ namespace presentation.Pages.Connection { - [TestIPFilter("178.41.87.254")] + [TestIPFilter("172.18.0.0", "172.18.255.255")] public class IndexModel : PageModel { private ILogger _logger; - public bool IsAdmin = false; + + public IndexModel(ILogger logger) + { + _logger = logger; + } + public async Task OnGetAsync(){ - System.Console.WriteLine(Request.Headers["X-Forwarded-For"]); // this should be able to extract the original IP adress, after it goes through kubernetes - var clientIPAdress = Request.HttpContext.Connection.RemoteIpAddress.ToString(); // extracting ip adress locally - System.Console.WriteLine(clientIPAdress); + _logger.LogInformation(Request.Headers["X-Forwarded-For"]); // this should be able to extract the original IP adress, after it goes through kubernetes + var clientIPAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString(); // extracting ip adress locally + _logger.LogInformation($"Client IP address: {clientIPAddress}"); } } From c9e215bbab403ba5f46aac57820efc3c256873d7 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Thu, 31 Aug 2023 11:28:39 +0200 Subject: [PATCH 45/55] Changed filter type to ResourceFilter --- cppseminar/presentation/Filters/IPFilter.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cppseminar/presentation/Filters/IPFilter.cs b/cppseminar/presentation/Filters/IPFilter.cs index 532b7404..51fe44ae 100644 --- a/cppseminar/presentation/Filters/IPFilter.cs +++ b/cppseminar/presentation/Filters/IPFilter.cs @@ -4,7 +4,7 @@ using System.Net; namespace presentation.Filters; -public class TestIPFilter : ResultFilterAttribute +public class TestIPFilter : Attribute, IResourceFilter { private readonly byte[] _allowedLowerBytes; private readonly byte[] _allowedUpperBytes; @@ -42,7 +42,7 @@ private bool AddressWithinRange(IPAddress clientAddress) return true; } - public override void OnResultExecuting(ResultExecutingContext context) + public void OnResourceExecuting(ResourceExecutingContext context) { IPAddress clientIPAddress; IPAddress.TryParse(context.HttpContext.Connection.RemoteIpAddress?.ToString(), out clientIPAddress); @@ -56,6 +56,10 @@ public override void OnResultExecuting(ResultExecutingContext context) }; } } + + public void OnResourceExecuted(ResourceExecutedContext context) + { + } } From 8692631cde19b3b00f534fc4679969e43c5e1443 Mon Sep 17 00:00:00 2001 From: to-0 Date: Thu, 31 Aug 2023 13:52:55 +0200 Subject: [PATCH 46/55] Fiter for signalR hub, also trying to extract ip addresses from appsettings.json --- .../presentation/Filters/IPHubFilter.cs | 42 +++++++++++++++++++ cppseminar/presentation/Hubs/MonitoringHub.cs | 5 ++- .../Pages/Connection/Index.cshtml.cs | 8 +++- cppseminar/presentation/Startup.cs | 18 +++++++- cppseminar/presentation/appsettings.json | 6 ++- cppseminar/presentation/config.json | 6 +++ 6 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 cppseminar/presentation/Filters/IPHubFilter.cs create mode 100644 cppseminar/presentation/config.json diff --git a/cppseminar/presentation/Filters/IPHubFilter.cs b/cppseminar/presentation/Filters/IPHubFilter.cs new file mode 100644 index 00000000..193f57c7 --- /dev/null +++ b/cppseminar/presentation/Filters/IPHubFilter.cs @@ -0,0 +1,42 @@ +using Microsoft.AspNetCore.SignalR; +using System; +using System.Linq; +using System.Threading.Tasks; +namespace presentation.Filters; +public class IPHubFilter : IHubFilter +{ + private readonly string[] _allowedIpAddresses; + + public IPHubFilter(string[] allowedIpAddresses) + { + _allowedIpAddresses = allowedIpAddresses ?? throw new ArgumentNullException(nameof(allowedIpAddresses)); + } + + public Task OnConnectedAsync(HubLifetimeContext context, Func next) + { + var remoteIpAddress = context.Context.GetHttpContext()?.Connection.RemoteIpAddress; + System.Console.WriteLine(remoteIpAddress); + + if (remoteIpAddress != null && !_allowedIpAddresses.Contains(remoteIpAddress.ToString())) + { + System.Console.WriteLine("IP adress not allowed in onconnected"); + context.Context.Abort(); + } + return next(context); + } + + public async ValueTask InvokeMethodAsync(HubInvocationContext invocationContext, Func> next) + { + var remoteIpAddress = invocationContext.Context.GetHttpContext()?.Connection.RemoteIpAddress; + System.Console.WriteLine(remoteIpAddress); + + if (remoteIpAddress != null && !_allowedIpAddresses.Contains(remoteIpAddress.ToString())) + { + System.Console.WriteLine("IP adress not allowed"); + invocationContext.Context.Abort(); + return null; + } + + return await next(invocationContext); + } +} diff --git a/cppseminar/presentation/Hubs/MonitoringHub.cs b/cppseminar/presentation/Hubs/MonitoringHub.cs index f9c4fff4..5a8099cd 100644 --- a/cppseminar/presentation/Hubs/MonitoringHub.cs +++ b/cppseminar/presentation/Hubs/MonitoringHub.cs @@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Authorization; using System.Text.Json; using System.Collections.Generic; - +using presentation.Filters; namespace presentation.Hubs { @@ -18,6 +18,9 @@ public class MonitoringHub: Hub public MonitoringHub(MonitoringService monitoringService){ _monitoringService = monitoringService; } + public override async Task OnConnectedAsync(){ + + } [Authorize] public async Task LogConnection() diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs index dcf9725f..517a8aeb 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs @@ -9,11 +9,17 @@ namespace presentation.Pages.Connection { - [TestIPFilter("178.41.87.254")] + [TestIPFilter("172.24.0.1")] public class IndexModel : PageModel { private ILogger _logger; public bool IsAdmin = false; + public string upper; + public string lower; + public IndexModel(List allowedIpAddresses) { + this.upper = allowedIpAddresses[0]; + this.lower = allowedIpAddresses[1]; + } public async Task OnGetAsync(){ System.Console.WriteLine(Request.Headers["X-Forwarded-For"]); // this should be able to extract the original IP adress, after it goes through kubernetes var clientIPAdress = Request.HttpContext.Connection.RemoteIpAddress.ToString(); // extracting ip adress locally diff --git a/cppseminar/presentation/Startup.cs b/cppseminar/presentation/Startup.cs index ed709c76..9681fa86 100644 --- a/cppseminar/presentation/Startup.cs +++ b/cppseminar/presentation/Startup.cs @@ -14,6 +14,11 @@ using presentation.Services; using presentation.Hubs; +using presentation.Filters; +using Microsoft.AspNetCore.SignalR; +using System.Collections.Generic; +using System.Linq; + namespace presentation { @@ -32,7 +37,18 @@ public void ConfigureServices(IServiceCollection services) opts.Conventions.AuthorizeFolder("/Admin", "Administrator"); }); // modified this - services.AddSignalR(); + IConfigurationSection allowedIpAddressesconfig = Configuration.GetSection("AllowedIpAddresses"); + var allowedIpAddresses = allowedIpAddressesconfig.Get(); + services.AddSignalR(hubOptions => { + hubOptions.AddFilter(new IPHubFilter(allowedIpAddresses)); + }); + List allowedList = allowedIpAddresses.ToList(); + services.AddSingleton>(allowedList); + + + + //services.AddSingleton(new IPHubFilter(allowedIPAddress)); + services.AddControllers(); services.Configure(options => diff --git a/cppseminar/presentation/appsettings.json b/cppseminar/presentation/appsettings.json index 6c4b5612..316883aa 100644 --- a/cppseminar/presentation/appsettings.json +++ b/cppseminar/presentation/appsettings.json @@ -12,5 +12,9 @@ "ClientSecret": "" }, "API_GATEWAY": "http://gateway.local:5000/", - "STORAGE_CONNECTION_STRING": "" + "STORAGE_CONNECTION_STRING": "", + "AllowedIpAddresses": [ + "162.18.0.1", + "172.18.0.1" +] } diff --git a/cppseminar/presentation/config.json b/cppseminar/presentation/config.json new file mode 100644 index 00000000..bad88a09 --- /dev/null +++ b/cppseminar/presentation/config.json @@ -0,0 +1,6 @@ +{ + "AllowedIpAddresses": [ + "162.18.0.1", + "172.18.0.1" + ] +} \ No newline at end of file From 7d466054a7ae527fc3d573a12e32e546e9497fa7 Mon Sep 17 00:00:00 2001 From: to-0 Date: Thu, 31 Aug 2023 14:17:07 +0200 Subject: [PATCH 47/55] Deleted unnecessary attributes --- cppseminar/presentation/Pages/Connection/Index.cshtml.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs index 995bc8bf..9d073f6f 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs @@ -14,14 +14,10 @@ public class IndexModel : PageModel [TestIPFilter("172.18.0.0", "172.18.255.255")] private ILogger _logger; public bool IsAdmin = false; - public string upper; - public string lower; - public IndexModel(ILogger logger, List allowedIpAddresses) + public IndexModel(ILogger logger) { _logger = logger; - this.upper = allowedIpAddresses[0]; // we wont be able to use this in testipfilter cuz it needs to be static or constant... we dont have the information - this.lower = allowedIpAddresses[1]; } From 9961947538ebf5e3c3ba938a2fb545c7285bf2c1 Mon Sep 17 00:00:00 2001 From: to-0 Date: Mon, 4 Sep 2023 11:22:58 +0200 Subject: [PATCH 48/55] Changed IPHubFilter to work with ranges of IP addresses --- cppseminar/docker-compose.yml | 1 + .../presentation/Filters/IPHubFilter.cs | 61 +++++++++++++++---- cppseminar/presentation/Startup.cs | 6 +- cppseminar/presentation/appsettings.json | 4 +- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/cppseminar/docker-compose.yml b/cppseminar/docker-compose.yml index 2e263574..681960a9 100644 --- a/cppseminar/docker-compose.yml +++ b/cppseminar/docker-compose.yml @@ -41,6 +41,7 @@ services: - ./presentation/wwwroot:/src/wwwroot - ./presentation/Hubs:/src/Hubs - ./presentation/Filters:/src/Filters + - ./presentation/appsettings.json:/src/appsettings.json networks: - sharednet ports: diff --git a/cppseminar/presentation/Filters/IPHubFilter.cs b/cppseminar/presentation/Filters/IPHubFilter.cs index 193f57c7..23af17c8 100644 --- a/cppseminar/presentation/Filters/IPHubFilter.cs +++ b/cppseminar/presentation/Filters/IPHubFilter.cs @@ -2,37 +2,76 @@ using System; using System.Linq; using System.Threading.Tasks; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; namespace presentation.Filters; + public class IPHubFilter : IHubFilter { - private readonly string[] _allowedIpAddresses; + //private readonly string[] _allowedIpAddresses; + private readonly List> allowedIPRanges = new List>(); public IPHubFilter(string[] allowedIpAddresses) { - _allowedIpAddresses = allowedIpAddresses ?? throw new ArgumentNullException(nameof(allowedIpAddresses)); + + var length = allowedIpAddresses.Length; + if (length < 2 && length > 0){ + IPAddress allowedIPLower; + IPAddress.TryParse(allowedIpAddresses[0], out allowedIPLower); + allowedIPRanges.Add(new Tuple(allowedIPLower.GetAddressBytes(),new byte[]{})); + } + else{ + IPAddress allowedIPUpper; + IPAddress allowedIPLower; + for(var i = 0; i < length; i+=2){ + IPAddress.TryParse(allowedIpAddresses[i], out allowedIPLower); + if((i+1) < length){ + IPAddress.TryParse(allowedIpAddresses[i+1], out allowedIPUpper); + allowedIPRanges.Add(new Tuple(allowedIPLower.GetAddressBytes(), allowedIPUpper.GetAddressBytes())); + } + else{ + allowedIPRanges.Add(new Tuple(allowedIPLower.GetAddressBytes(),new byte[]{})); + } + } + } + } public Task OnConnectedAsync(HubLifetimeContext context, Func next) { - var remoteIpAddress = context.Context.GetHttpContext()?.Connection.RemoteIpAddress; - System.Console.WriteLine(remoteIpAddress); - - if (remoteIpAddress != null && !_allowedIpAddresses.Contains(remoteIpAddress.ToString())) + var remoteIpAddresStr = context.Context.GetHttpContext()?.Connection.RemoteIpAddress.ToString(); + IPAddress remoteIPAddress; + IPAddress.TryParse(remoteIpAddresStr, out remoteIPAddress); + + if (!AddressWithinRange(remoteIPAddress)) { - System.Console.WriteLine("IP adress not allowed in onconnected"); + System.Console.WriteLine("IP adress not allowed in onconnected "+remoteIpAddresStr); context.Context.Abort(); } return next(context); } + private bool AddressWithinRange(IPAddress clientAddress){ + byte[] clientAddressBytes = clientAddress.GetAddressBytes(); + foreach(var range in allowedIPRanges){ + for(int i=0; i < range.Item1.Length; i++){ + if(clientAddressBytes[i]< range.Item1[i] || (range.Item2.Length != 0 && clientAddressBytes[i]> range.Item2[i])){ + return false; + } + } + } + return true; + } public async ValueTask InvokeMethodAsync(HubInvocationContext invocationContext, Func> next) { - var remoteIpAddress = invocationContext.Context.GetHttpContext()?.Connection.RemoteIpAddress; - System.Console.WriteLine(remoteIpAddress); + var remoteIpAddresStr = invocationContext.Context.GetHttpContext()?.Connection.RemoteIpAddress.ToString(); + IPAddress remoteIPAddress; + IPAddress.TryParse(remoteIpAddresStr, out remoteIPAddress); - if (remoteIpAddress != null && !_allowedIpAddresses.Contains(remoteIpAddress.ToString())) + if (!AddressWithinRange(remoteIPAddress)) { - System.Console.WriteLine("IP adress not allowed"); + System.Console.WriteLine("IP adress not allowed in invoke method "+ remoteIpAddresStr); invocationContext.Context.Abort(); return null; } diff --git a/cppseminar/presentation/Startup.cs b/cppseminar/presentation/Startup.cs index 9681fa86..fcc70a6a 100644 --- a/cppseminar/presentation/Startup.cs +++ b/cppseminar/presentation/Startup.cs @@ -38,11 +38,11 @@ public void ConfigureServices(IServiceCollection services) }); // modified this IConfigurationSection allowedIpAddressesconfig = Configuration.GetSection("AllowedIpAddresses"); - var allowedIpAddresses = allowedIpAddressesconfig.Get(); + var allowedIpAddressesRanges = allowedIpAddressesconfig.Get(); services.AddSignalR(hubOptions => { - hubOptions.AddFilter(new IPHubFilter(allowedIpAddresses)); + hubOptions.AddFilter(new IPHubFilter(allowedIpAddressesRanges)); }); - List allowedList = allowedIpAddresses.ToList(); + List allowedList = allowedIpAddressesRanges.ToList(); services.AddSingleton>(allowedList); diff --git a/cppseminar/presentation/appsettings.json b/cppseminar/presentation/appsettings.json index 316883aa..05b2872c 100644 --- a/cppseminar/presentation/appsettings.json +++ b/cppseminar/presentation/appsettings.json @@ -14,7 +14,7 @@ "API_GATEWAY": "http://gateway.local:5000/", "STORAGE_CONNECTION_STRING": "", "AllowedIpAddresses": [ - "162.18.0.1", - "172.18.0.1" + "172.20.0.1", + "172.20.0.255" ] } From db053df1f86c3c73961eaf155dff7237625f1c16 Mon Sep 17 00:00:00 2001 From: to-0 Date: Mon, 4 Sep 2023 11:29:26 +0200 Subject: [PATCH 49/55] Added error handling when parsing IP address --- .../presentation/Filters/IPHubFilter.cs | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/cppseminar/presentation/Filters/IPHubFilter.cs b/cppseminar/presentation/Filters/IPHubFilter.cs index 23af17c8..dfa7d8c7 100644 --- a/cppseminar/presentation/Filters/IPHubFilter.cs +++ b/cppseminar/presentation/Filters/IPHubFilter.cs @@ -18,16 +18,23 @@ public IPHubFilter(string[] allowedIpAddresses) var length = allowedIpAddresses.Length; if (length < 2 && length > 0){ IPAddress allowedIPLower; - IPAddress.TryParse(allowedIpAddresses[0], out allowedIPLower); + bool res = IPAddress.TryParse(allowedIpAddresses[0], out allowedIPLower); + if (res ==false){ + throw new Exception("Failed to parse IP address"); + } allowedIPRanges.Add(new Tuple(allowedIPLower.GetAddressBytes(),new byte[]{})); } else{ IPAddress allowedIPUpper; IPAddress allowedIPLower; for(var i = 0; i < length; i+=2){ - IPAddress.TryParse(allowedIpAddresses[i], out allowedIPLower); + if(!IPAddress.TryParse(allowedIpAddresses[i], out allowedIPLower)){ + throw new Exception("Failed to parse IP address"); + } if((i+1) < length){ - IPAddress.TryParse(allowedIpAddresses[i+1], out allowedIPUpper); + if(!IPAddress.TryParse(allowedIpAddresses[i+1], out allowedIPUpper)){ + throw new Exception("Failed to parse IP address"); + } allowedIPRanges.Add(new Tuple(allowedIPLower.GetAddressBytes(), allowedIPUpper.GetAddressBytes())); } else{ @@ -42,7 +49,9 @@ public Task OnConnectedAsync(HubLifetimeContext context, Func Date: Mon, 4 Sep 2023 12:42:22 +0200 Subject: [PATCH 50/55] Ip filter for connection page registered as service, with ip range from appsettings.json. --- cppseminar/presentation/Filters/IPFilter.cs | 24 ++----------------- .../Pages/Connection/Index.cshtml.cs | 4 +++- cppseminar/presentation/Startup.cs | 6 +---- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/cppseminar/presentation/Filters/IPFilter.cs b/cppseminar/presentation/Filters/IPFilter.cs index a982c753..37c299ff 100644 --- a/cppseminar/presentation/Filters/IPFilter.cs +++ b/cppseminar/presentation/Filters/IPFilter.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Net; +using presentation.Services; namespace presentation.Filters; public class TestIPFilter : Attribute, IResourceFilter @@ -29,29 +30,8 @@ public TestIPFilter(string allowedIPLowerStr, string allowedIPUpperStr) } } } - public TestIPFilter(List allowedIPRanges) - { - System.Console.WriteLine("Test"); - string allowedIPUpperStr = allowedIPRanges[1]; - string allowedIPLowerStr = allowedIPRanges[0]; - IPAddress allowedIPLower; - IPAddress.TryParse(allowedIPLowerStr, out allowedIPLower); - _allowedLowerBytes = allowedIPLower.GetAddressBytes(); - IPAddress allowedIPUpper; - IPAddress.TryParse(allowedIPUpperStr, out allowedIPUpper); - _allowedUpperBytes = allowedIPUpper.GetAddressBytes(); - - // Check if lower bound is indeed lower - for (int i = 0; i < _allowedLowerBytes.Length; i++) - { - if (_allowedLowerBytes[i] > _allowedUpperBytes[i]) - { - throw new ArgumentException("Invalid range of IP addresses."); - } - } - } private bool AddressWithinRange(IPAddress clientAddress) { @@ -70,7 +50,7 @@ public void OnResourceExecuting(ResourceExecutingContext context) { IPAddress clientIPAddress; IPAddress.TryParse(context.HttpContext.Connection.RemoteIpAddress?.ToString(), out clientIPAddress); - + System.Console.WriteLine("This is client ip address: " + clientIPAddress); if (!AddressWithinRange(clientIPAddress)) { context.Result = new ContentResult diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs index 9d073f6f..973b5304 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs @@ -6,12 +6,14 @@ using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Logging; using presentation.Filters; +using Microsoft.AspNetCore.Mvc; namespace presentation.Pages.Connection { + [ServiceFilter(typeof(TestIPFilter))] public class IndexModel : PageModel { - [TestIPFilter("172.18.0.0", "172.18.255.255")] + private ILogger _logger; public bool IsAdmin = false; diff --git a/cppseminar/presentation/Startup.cs b/cppseminar/presentation/Startup.cs index fcc70a6a..ab63aed7 100644 --- a/cppseminar/presentation/Startup.cs +++ b/cppseminar/presentation/Startup.cs @@ -42,12 +42,8 @@ public void ConfigureServices(IServiceCollection services) services.AddSignalR(hubOptions => { hubOptions.AddFilter(new IPHubFilter(allowedIpAddressesRanges)); }); - List allowedList = allowedIpAddressesRanges.ToList(); - services.AddSingleton>(allowedList); + services.AddSingleton(new TestIPFilter(allowedIpAddressesRanges[0], allowedIpAddressesRanges[1])); - - - //services.AddSingleton(new IPHubFilter(allowedIPAddress)); services.AddControllers(); From bf7eeb759e8407b0ce0a5214ac9c2b72156e6139 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Mon, 4 Sep 2023 12:50:34 +0200 Subject: [PATCH 51/55] Hub Filter accepts 1 range of IP addresses supplied in appsettings.json --- .../presentation/Filters/IPHubFilter.cs | 91 ++++++++----------- cppseminar/presentation/Startup.cs | 11 ++- cppseminar/presentation/appsettings.json | 8 +- 3 files changed, 47 insertions(+), 63 deletions(-) diff --git a/cppseminar/presentation/Filters/IPHubFilter.cs b/cppseminar/presentation/Filters/IPHubFilter.cs index dfa7d8c7..e78eb32b 100644 --- a/cppseminar/presentation/Filters/IPHubFilter.cs +++ b/cppseminar/presentation/Filters/IPHubFilter.cs @@ -9,84 +9,67 @@ namespace presentation.Filters; public class IPHubFilter : IHubFilter { - //private readonly string[] _allowedIpAddresses; - private readonly List> allowedIPRanges = new List>(); + private readonly byte[] _allowedLowerBytes; + private readonly byte[] _allowedUpperBytes; - public IPHubFilter(string[] allowedIpAddresses) + public IPHubFilter(string allowedIPLowerStr, string allowedIPUpperStr) { + IPAddress allowedIPLower; + IPAddress allowedIPUpper; + if (!IPAddress.TryParse(allowedIPLowerStr, out allowedIPLower) || !IPAddress.TryParse(allowedIPUpperStr, out allowedIPUpper)) + { + throw new ArgumentException($"Failed to parse IP address: {allowedIPLowerStr} {allowedIPUpperStr}"); + } + + _allowedLowerBytes = allowedIPLower.GetAddressBytes(); + _allowedUpperBytes = allowedIPUpper.GetAddressBytes(); - var length = allowedIpAddresses.Length; - if (length < 2 && length > 0){ - IPAddress allowedIPLower; - bool res = IPAddress.TryParse(allowedIpAddresses[0], out allowedIPLower); - if (res ==false){ - throw new Exception("Failed to parse IP address"); + // Check if lower bound is indeed lower + for (int i = 0; i < _allowedLowerBytes.Length; i++) + { + if (_allowedLowerBytes[i] > _allowedUpperBytes[i]) + { + throw new ArgumentException("Invalid range of IP addresses."); } - allowedIPRanges.Add(new Tuple(allowedIPLower.GetAddressBytes(),new byte[]{})); } - else{ - IPAddress allowedIPUpper; - IPAddress allowedIPLower; - for(var i = 0; i < length; i+=2){ - if(!IPAddress.TryParse(allowedIpAddresses[i], out allowedIPLower)){ - throw new Exception("Failed to parse IP address"); - } - if((i+1) < length){ - if(!IPAddress.TryParse(allowedIpAddresses[i+1], out allowedIPUpper)){ - throw new Exception("Failed to parse IP address"); - } - allowedIPRanges.Add(new Tuple(allowedIPLower.GetAddressBytes(), allowedIPUpper.GetAddressBytes())); - } - else{ - allowedIPRanges.Add(new Tuple(allowedIPLower.GetAddressBytes(),new byte[]{})); - } + } + + private bool AddressWithinRange(IPAddress clientAddress) + { + byte[] clientAddressBytes = clientAddress.GetAddressBytes(); + for (int i = 0; i < _allowedLowerBytes.Length; i++) + { + if (clientAddressBytes[i] < _allowedLowerBytes[i] || clientAddressBytes[i] > _allowedUpperBytes[i]) + { + return false; } } - + return true; } - public Task OnConnectedAsync(HubLifetimeContext context, Func next) + public Task OnConnectedAsync(HubLifetimeContext context, Func next) { var remoteIpAddresStr = context.Context.GetHttpContext()?.Connection.RemoteIpAddress.ToString(); IPAddress remoteIPAddress; - if(!IPAddress.TryParse(remoteIpAddresStr, out remoteIPAddress)){ - throw new Exception("Failed to parse IP address"); - } - - if (!AddressWithinRange(remoteIPAddress)) + if (!IPAddress.TryParse(remoteIpAddresStr, out remoteIPAddress) || !AddressWithinRange(remoteIPAddress)) { - System.Console.WriteLine("IP adress not allowed in onconnected "+remoteIpAddresStr); - context.Context.Abort(); - } - return next(context); - } - private bool AddressWithinRange(IPAddress clientAddress){ - byte[] clientAddressBytes = clientAddress.GetAddressBytes(); - foreach(var range in allowedIPRanges){ - for(int i=0; i < range.Item1.Length; i++){ - if(clientAddressBytes[i]< range.Item1[i] || (range.Item2.Length != 0 && clientAddressBytes[i]> range.Item2[i])){ - return false; - } - } + System.Console.WriteLine("IP Address failed to parse or not allowed in OnConnected. " + remoteIpAddresStr); + context.Context.Abort(); } - return true; + return next(context); } public async ValueTask InvokeMethodAsync(HubInvocationContext invocationContext, Func> next) { var remoteIpAddresStr = invocationContext.Context.GetHttpContext()?.Connection.RemoteIpAddress.ToString(); IPAddress remoteIPAddress; - if(!IPAddress.TryParse(remoteIpAddresStr, out remoteIPAddress)){ - throw new Exception("Failed to parse IP address"); - } - if (!AddressWithinRange(remoteIPAddress)) + if (!IPAddress.TryParse(remoteIpAddresStr, out remoteIPAddress) || !AddressWithinRange(remoteIPAddress)) { - System.Console.WriteLine("IP adress not allowed in invoke method "+ remoteIpAddresStr); + System.Console.WriteLine("IP Address failed to parse or not allowed in invoke method. " + remoteIpAddresStr); invocationContext.Context.Abort(); return null; } - return await next(invocationContext); } -} +} \ No newline at end of file diff --git a/cppseminar/presentation/Startup.cs b/cppseminar/presentation/Startup.cs index fcc70a6a..3ef92bd2 100644 --- a/cppseminar/presentation/Startup.cs +++ b/cppseminar/presentation/Startup.cs @@ -37,13 +37,14 @@ public void ConfigureServices(IServiceCollection services) opts.Conventions.AuthorizeFolder("/Admin", "Administrator"); }); // modified this - IConfigurationSection allowedIpAddressesconfig = Configuration.GetSection("AllowedIpAddresses"); - var allowedIpAddressesRanges = allowedIpAddressesconfig.Get(); + + IConfigurationSection allowedIpAddresses = Configuration.GetSection("ALLOWED_IP_RANGE"); + System.Console.WriteLine(allowedIpAddresses["Lower"]); services.AddSignalR(hubOptions => { - hubOptions.AddFilter(new IPHubFilter(allowedIpAddressesRanges)); + hubOptions.AddFilter(new IPHubFilter(allowedIpAddresses["Lower"], allowedIpAddresses["Upper"])); }); - List allowedList = allowedIpAddressesRanges.ToList(); - services.AddSingleton>(allowedList); + // List allowedList = allowedIpAddressesRanges.ToList(); + // services.AddSingleton>(allowedList); diff --git a/cppseminar/presentation/appsettings.json b/cppseminar/presentation/appsettings.json index 05b2872c..0312bbff 100644 --- a/cppseminar/presentation/appsettings.json +++ b/cppseminar/presentation/appsettings.json @@ -13,8 +13,8 @@ }, "API_GATEWAY": "http://gateway.local:5000/", "STORAGE_CONNECTION_STRING": "", - "AllowedIpAddresses": [ - "172.20.0.1", - "172.20.0.255" -] + "ALLOWED_IP_RANGE": { + "Lower": "172.0.0.0", + "Upper": "172.255.255.255" + } } From ef1894b70521a68b90239ac2baf478c0edcb2171 Mon Sep 17 00:00:00 2001 From: to-0 Date: Mon, 4 Sep 2023 13:37:55 +0200 Subject: [PATCH 52/55] Renamed IpFilter --- .../presentation/Filters/{IPFilter.cs => PageIPFilter.cs} | 4 ++-- cppseminar/presentation/Pages/Connection/Index.cshtml.cs | 2 +- cppseminar/presentation/Startup.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename cppseminar/presentation/Filters/{IPFilter.cs => PageIPFilter.cs} (94%) diff --git a/cppseminar/presentation/Filters/IPFilter.cs b/cppseminar/presentation/Filters/PageIPFilter.cs similarity index 94% rename from cppseminar/presentation/Filters/IPFilter.cs rename to cppseminar/presentation/Filters/PageIPFilter.cs index 37c299ff..77c346e4 100644 --- a/cppseminar/presentation/Filters/IPFilter.cs +++ b/cppseminar/presentation/Filters/PageIPFilter.cs @@ -6,12 +6,12 @@ using presentation.Services; namespace presentation.Filters; -public class TestIPFilter : Attribute, IResourceFilter +public class PageIPFilter : Attribute, IResourceFilter { private readonly byte[] _allowedLowerBytes; private readonly byte[] _allowedUpperBytes; - public TestIPFilter(string allowedIPLowerStr, string allowedIPUpperStr) + public PageIPFilter(string allowedIPLowerStr, string allowedIPUpperStr) { IPAddress allowedIPLower; IPAddress.TryParse(allowedIPLowerStr, out allowedIPLower); diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs index 973b5304..e7e2ad14 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs @@ -10,7 +10,7 @@ namespace presentation.Pages.Connection { - [ServiceFilter(typeof(TestIPFilter))] + [ServiceFilter(typeof(PageIPFilter))] public class IndexModel : PageModel { diff --git a/cppseminar/presentation/Startup.cs b/cppseminar/presentation/Startup.cs index 5a73cb60..d2ccd890 100644 --- a/cppseminar/presentation/Startup.cs +++ b/cppseminar/presentation/Startup.cs @@ -43,7 +43,7 @@ public void ConfigureServices(IServiceCollection services) services.AddSignalR(hubOptions => { hubOptions.AddFilter(new IPHubFilter(allowedIpAddresses["Lower"], allowedIpAddresses["Upper"])); }); - services.AddSingleton(new TestIPFilter(allowedIpAddresses["Lower"], allowedIpAddresses["Upper"])); + services.AddSingleton(new PageIPFilter(allowedIpAddresses["Lower"], allowedIpAddresses["Upper"])); services.AddControllers(); From 7fab26c0f5193927900c8a045878eae14fd22cce Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Mon, 4 Sep 2023 14:03:22 +0200 Subject: [PATCH 53/55] IP Filters refactoring --- .../presentation/Filters/GenericIPFilter.cs | 46 +++++++++++++++++++ .../presentation/Filters/IPHubFilter.cs | 38 +-------------- .../presentation/Filters/PageIPFilter.cs | 39 +--------------- 3 files changed, 50 insertions(+), 73 deletions(-) create mode 100644 cppseminar/presentation/Filters/GenericIPFilter.cs diff --git a/cppseminar/presentation/Filters/GenericIPFilter.cs b/cppseminar/presentation/Filters/GenericIPFilter.cs new file mode 100644 index 00000000..1f666be6 --- /dev/null +++ b/cppseminar/presentation/Filters/GenericIPFilter.cs @@ -0,0 +1,46 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using System; +using System.Collections.Generic; +using System.Net; +using presentation.Services; +namespace presentation.Filters; + +public class GenericIPFilter +{ + private readonly byte[] _allowedLowerBytes; + private readonly byte[] _allowedUpperBytes; + + public GenericIPFilter(string allowedIPLowerStr, string allowedIPUpperStr) + { + IPAddress allowedIPLower; + IPAddress.TryParse(allowedIPLowerStr, out allowedIPLower); + _allowedLowerBytes = allowedIPLower.GetAddressBytes(); + + IPAddress allowedIPUpper; + IPAddress.TryParse(allowedIPUpperStr, out allowedIPUpper); + _allowedUpperBytes = allowedIPUpper.GetAddressBytes(); + + // Check if lower bound is indeed lower + for (int i = 0; i < _allowedLowerBytes.Length; i++) + { + if (_allowedLowerBytes[i] > _allowedUpperBytes[i]) + { + throw new ArgumentException("Invalid range of IP addresses."); + } + } + } + + public bool AddressWithinRange(IPAddress clientAddress) + { + byte[] clientAddressBytes = clientAddress.GetAddressBytes(); + for (int i = 0; i < _allowedLowerBytes.Length; i++) + { + if (clientAddressBytes[i] < _allowedLowerBytes[i] || clientAddressBytes[i] > _allowedUpperBytes[i]) + { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/cppseminar/presentation/Filters/IPHubFilter.cs b/cppseminar/presentation/Filters/IPHubFilter.cs index e78eb32b..d77d14ae 100644 --- a/cppseminar/presentation/Filters/IPHubFilter.cs +++ b/cppseminar/presentation/Filters/IPHubFilter.cs @@ -7,44 +7,10 @@ using System.Net.Http; namespace presentation.Filters; -public class IPHubFilter : IHubFilter +public class IPHubFilter : GenericIPFilter, IHubFilter { - private readonly byte[] _allowedLowerBytes; - private readonly byte[] _allowedUpperBytes; - - public IPHubFilter(string allowedIPLowerStr, string allowedIPUpperStr) + public IPHubFilter(string IPLower, string IPUpper) : base(IPLower, IPUpper) { - IPAddress allowedIPLower; - IPAddress allowedIPUpper; - if (!IPAddress.TryParse(allowedIPLowerStr, out allowedIPLower) || !IPAddress.TryParse(allowedIPUpperStr, out allowedIPUpper)) - { - throw new ArgumentException($"Failed to parse IP address: {allowedIPLowerStr} {allowedIPUpperStr}"); - } - - _allowedLowerBytes = allowedIPLower.GetAddressBytes(); - _allowedUpperBytes = allowedIPUpper.GetAddressBytes(); - - // Check if lower bound is indeed lower - for (int i = 0; i < _allowedLowerBytes.Length; i++) - { - if (_allowedLowerBytes[i] > _allowedUpperBytes[i]) - { - throw new ArgumentException("Invalid range of IP addresses."); - } - } - } - - private bool AddressWithinRange(IPAddress clientAddress) - { - byte[] clientAddressBytes = clientAddress.GetAddressBytes(); - for (int i = 0; i < _allowedLowerBytes.Length; i++) - { - if (clientAddressBytes[i] < _allowedLowerBytes[i] || clientAddressBytes[i] > _allowedUpperBytes[i]) - { - return false; - } - } - return true; } public Task OnConnectedAsync(HubLifetimeContext context, Func next) diff --git a/cppseminar/presentation/Filters/PageIPFilter.cs b/cppseminar/presentation/Filters/PageIPFilter.cs index 77c346e4..bb9b8cc4 100644 --- a/cppseminar/presentation/Filters/PageIPFilter.cs +++ b/cppseminar/presentation/Filters/PageIPFilter.cs @@ -6,51 +6,16 @@ using presentation.Services; namespace presentation.Filters; -public class PageIPFilter : Attribute, IResourceFilter +public class PageIPFilter : GenericIPFilter, IResourceFilter { - private readonly byte[] _allowedLowerBytes; - private readonly byte[] _allowedUpperBytes; - - public PageIPFilter(string allowedIPLowerStr, string allowedIPUpperStr) - { - IPAddress allowedIPLower; - IPAddress.TryParse(allowedIPLowerStr, out allowedIPLower); - _allowedLowerBytes = allowedIPLower.GetAddressBytes(); - - IPAddress allowedIPUpper; - IPAddress.TryParse(allowedIPUpperStr, out allowedIPUpper); - _allowedUpperBytes = allowedIPUpper.GetAddressBytes(); - - // Check if lower bound is indeed lower - for (int i = 0; i < _allowedLowerBytes.Length; i++) - { - if (_allowedLowerBytes[i] > _allowedUpperBytes[i]) - { - throw new ArgumentException("Invalid range of IP addresses."); - } - } - } - - - - private bool AddressWithinRange(IPAddress clientAddress) + public PageIPFilter(string IPLower, string IPUpper) : base(IPLower, IPUpper) { - byte[] clientAddressBytes = clientAddress.GetAddressBytes(); - for (int i = 0; i < _allowedLowerBytes.Length; i++) - { - if (clientAddressBytes[i] < _allowedLowerBytes[i] || clientAddressBytes[i] > _allowedUpperBytes[i]) - { - return false; - } - } - return true; } public void OnResourceExecuting(ResourceExecutingContext context) { IPAddress clientIPAddress; IPAddress.TryParse(context.HttpContext.Connection.RemoteIpAddress?.ToString(), out clientIPAddress); - System.Console.WriteLine("This is client ip address: " + clientIPAddress); if (!AddressWithinRange(clientIPAddress)) { context.Result = new ContentResult From 04950165ac85d54b6cbb0e58dbcb148015ffe584 Mon Sep 17 00:00:00 2001 From: to-0 Date: Tue, 5 Sep 2023 12:39:09 +0200 Subject: [PATCH 54/55] IP filters check the content of X-Forwarded-For header first, if it contains IP address check, if not continue with remoteIPAddress. --- .../presentation/Filters/GenericIPFilter.cs | 17 +++++++++++++++++ cppseminar/presentation/Filters/IPHubFilter.cs | 11 ++++++----- cppseminar/presentation/Filters/PageIPFilter.cs | 10 +++++++--- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/cppseminar/presentation/Filters/GenericIPFilter.cs b/cppseminar/presentation/Filters/GenericIPFilter.cs index 1f666be6..d9259094 100644 --- a/cppseminar/presentation/Filters/GenericIPFilter.cs +++ b/cppseminar/presentation/Filters/GenericIPFilter.cs @@ -42,5 +42,22 @@ public bool AddressWithinRange(IPAddress clientAddress) } } return true; + } + public IPAddress GetRemoteIP(string remoteIpAddresStr, string forwardedForHeader){ + IPAddress remoteIPAddress; + // if X-Forwarded-For is not empty + if(!string.IsNullOrEmpty(forwardedForHeader)){ + System.Console.WriteLine("Forwarded-For " + forwardedForHeader); + // check if the header is a valid IP address + if(IPAddress.TryParse(forwardedForHeader, out remoteIPAddress)){ + return remoteIPAddress; + } + } + // if X-Forwarded-For is empty or not a valid IP address continue with remoteIPAddressStr + if (IPAddress.TryParse(remoteIpAddresStr, out remoteIPAddress)) + { + return remoteIPAddress; + } + return null; } } \ No newline at end of file diff --git a/cppseminar/presentation/Filters/IPHubFilter.cs b/cppseminar/presentation/Filters/IPHubFilter.cs index d77d14ae..29668601 100644 --- a/cppseminar/presentation/Filters/IPHubFilter.cs +++ b/cppseminar/presentation/Filters/IPHubFilter.cs @@ -16,8 +16,9 @@ public IPHubFilter(string IPLower, string IPUpper) : base(IPLower, IPUpper) public Task OnConnectedAsync(HubLifetimeContext context, Func next) { var remoteIpAddresStr = context.Context.GetHttpContext()?.Connection.RemoteIpAddress.ToString(); - IPAddress remoteIPAddress; - if (!IPAddress.TryParse(remoteIpAddresStr, out remoteIPAddress) || !AddressWithinRange(remoteIPAddress)) + var forwardedForHeader = context.Context.GetHttpContext()?.Request.Headers["X-Forwarded-For"].FirstOrDefault(); + IPAddress remoteIPAddress = GetRemoteIP(remoteIpAddresStr, forwardedForHeader); + if (remoteIPAddress == null || !AddressWithinRange(remoteIPAddress)) { System.Console.WriteLine("IP Address failed to parse or not allowed in OnConnected. " + remoteIpAddresStr); context.Context.Abort(); @@ -28,9 +29,9 @@ public Task OnConnectedAsync(HubLifetimeContext context, Func InvokeMethodAsync(HubInvocationContext invocationContext, Func> next) { var remoteIpAddresStr = invocationContext.Context.GetHttpContext()?.Connection.RemoteIpAddress.ToString(); - IPAddress remoteIPAddress; - - if (!IPAddress.TryParse(remoteIpAddresStr, out remoteIPAddress) || !AddressWithinRange(remoteIPAddress)) + var forwardedForHeader = invocationContext.Context.GetHttpContext()?.Request.Headers["X-Forwarded-For"].FirstOrDefault(); + IPAddress remoteIPAddress = GetRemoteIP(remoteIpAddresStr, forwardedForHeader); + if (remoteIPAddress == null || !AddressWithinRange(remoteIPAddress)) { System.Console.WriteLine("IP Address failed to parse or not allowed in invoke method. " + remoteIpAddresStr); invocationContext.Context.Abort(); diff --git a/cppseminar/presentation/Filters/PageIPFilter.cs b/cppseminar/presentation/Filters/PageIPFilter.cs index bb9b8cc4..62db9141 100644 --- a/cppseminar/presentation/Filters/PageIPFilter.cs +++ b/cppseminar/presentation/Filters/PageIPFilter.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Net; using presentation.Services; +using System.Linq; namespace presentation.Filters; public class PageIPFilter : GenericIPFilter, IResourceFilter @@ -14,9 +15,12 @@ public PageIPFilter(string IPLower, string IPUpper) : base(IPLower, IPUpper) public void OnResourceExecuting(ResourceExecutingContext context) { - IPAddress clientIPAddress; - IPAddress.TryParse(context.HttpContext.Connection.RemoteIpAddress?.ToString(), out clientIPAddress); - if (!AddressWithinRange(clientIPAddress)) + + var remoteIpAddresStr = context.HttpContext.Connection.RemoteIpAddress.ToString(); + var forwardedForHeader = context.HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault(); + IPAddress clientIPAddress = GetRemoteIP(remoteIpAddresStr, forwardedForHeader); + + if (clientIPAddress == null || !AddressWithinRange(clientIPAddress)) { context.Result = new ContentResult { From cbc9de2cfcfe6aaa628c9d8e331734386a1cc946 Mon Sep 17 00:00:00 2001 From: Adam Berenik Date: Tue, 5 Sep 2023 13:15:03 +0200 Subject: [PATCH 55/55] GetRemoteIP() refactoring --- .../presentation/Filters/GenericIPFilter.cs | 16 ++++++++-------- cppseminar/presentation/Filters/IPHubFilter.cs | 17 +++++++++-------- cppseminar/presentation/Filters/PageIPFilter.cs | 8 ++++---- .../Pages/Connection/Index.cshtml.cs | 8 -------- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/cppseminar/presentation/Filters/GenericIPFilter.cs b/cppseminar/presentation/Filters/GenericIPFilter.cs index d9259094..b4265c3c 100644 --- a/cppseminar/presentation/Filters/GenericIPFilter.cs +++ b/cppseminar/presentation/Filters/GenericIPFilter.cs @@ -43,18 +43,18 @@ public bool AddressWithinRange(IPAddress clientAddress) } return true; } - public IPAddress GetRemoteIP(string remoteIpAddresStr, string forwardedForHeader){ + public IPAddress GetRemoteIP(string remoteIpAddressStr, string forwardedForHeaderStr) + { IPAddress remoteIPAddress; - // if X-Forwarded-For is not empty - if(!string.IsNullOrEmpty(forwardedForHeader)){ - System.Console.WriteLine("Forwarded-For " + forwardedForHeader); - // check if the header is a valid IP address - if(IPAddress.TryParse(forwardedForHeader, out remoteIPAddress)){ + if(!string.IsNullOrEmpty(forwardedForHeaderStr)) + { + if(IPAddress.TryParse(forwardedForHeaderStr, out remoteIPAddress)) // check if the header is a valid IP address + { return remoteIPAddress; - } + } } // if X-Forwarded-For is empty or not a valid IP address continue with remoteIPAddressStr - if (IPAddress.TryParse(remoteIpAddresStr, out remoteIPAddress)) + if (IPAddress.TryParse(remoteIpAddressStr, out remoteIPAddress)) { return remoteIPAddress; } diff --git a/cppseminar/presentation/Filters/IPHubFilter.cs b/cppseminar/presentation/Filters/IPHubFilter.cs index 29668601..87e4290b 100644 --- a/cppseminar/presentation/Filters/IPHubFilter.cs +++ b/cppseminar/presentation/Filters/IPHubFilter.cs @@ -15,12 +15,13 @@ public IPHubFilter(string IPLower, string IPUpper) : base(IPLower, IPUpper) public Task OnConnectedAsync(HubLifetimeContext context, Func next) { - var remoteIpAddresStr = context.Context.GetHttpContext()?.Connection.RemoteIpAddress.ToString(); - var forwardedForHeader = context.Context.GetHttpContext()?.Request.Headers["X-Forwarded-For"].FirstOrDefault(); - IPAddress remoteIPAddress = GetRemoteIP(remoteIpAddresStr, forwardedForHeader); + var remoteIpAddressStr = context.Context.GetHttpContext()?.Connection.RemoteIpAddress.ToString(); + var forwardedForHeaderStr = context.Context.GetHttpContext()?.Request.Headers["X-Forwarded-For"].FirstOrDefault(); + IPAddress remoteIPAddress = GetRemoteIP(remoteIpAddressStr, forwardedForHeaderStr); + if (remoteIPAddress == null || !AddressWithinRange(remoteIPAddress)) { - System.Console.WriteLine("IP Address failed to parse or not allowed in OnConnected. " + remoteIpAddresStr); + System.Console.WriteLine($"IP Address failed to parse or not allowed in OnConnected. {remoteIpAddressStr} {forwardedForHeaderStr}"); context.Context.Abort(); } return next(context); @@ -28,12 +29,12 @@ public Task OnConnectedAsync(HubLifetimeContext context, Func InvokeMethodAsync(HubInvocationContext invocationContext, Func> next) { - var remoteIpAddresStr = invocationContext.Context.GetHttpContext()?.Connection.RemoteIpAddress.ToString(); - var forwardedForHeader = invocationContext.Context.GetHttpContext()?.Request.Headers["X-Forwarded-For"].FirstOrDefault(); - IPAddress remoteIPAddress = GetRemoteIP(remoteIpAddresStr, forwardedForHeader); + var remoteIpAddressStr = invocationContext.Context.GetHttpContext()?.Connection.RemoteIpAddress.ToString(); + var forwardedForHeaderStr = invocationContext.Context.GetHttpContext()?.Request.Headers["X-Forwarded-For"].FirstOrDefault(); + IPAddress remoteIPAddress = GetRemoteIP(remoteIpAddressStr, forwardedForHeaderStr); if (remoteIPAddress == null || !AddressWithinRange(remoteIPAddress)) { - System.Console.WriteLine("IP Address failed to parse or not allowed in invoke method. " + remoteIpAddresStr); + System.Console.WriteLine($"IP Address failed to parse or not allowed in invoke method. {remoteIpAddressStr} {forwardedForHeaderStr}"); invocationContext.Context.Abort(); return null; } diff --git a/cppseminar/presentation/Filters/PageIPFilter.cs b/cppseminar/presentation/Filters/PageIPFilter.cs index 62db9141..a045e816 100644 --- a/cppseminar/presentation/Filters/PageIPFilter.cs +++ b/cppseminar/presentation/Filters/PageIPFilter.cs @@ -15,13 +15,13 @@ public PageIPFilter(string IPLower, string IPUpper) : base(IPLower, IPUpper) public void OnResourceExecuting(ResourceExecutingContext context) { - - var remoteIpAddresStr = context.HttpContext.Connection.RemoteIpAddress.ToString(); - var forwardedForHeader = context.HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault(); - IPAddress clientIPAddress = GetRemoteIP(remoteIpAddresStr, forwardedForHeader); + var remoteIpAddressStr = context.HttpContext.Connection.RemoteIpAddress.ToString(); + var forwardedForHeaderStr = context.HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault(); + IPAddress clientIPAddress = GetRemoteIP(remoteIpAddressStr, forwardedForHeaderStr); if (clientIPAddress == null || !AddressWithinRange(clientIPAddress)) { + System.Console.WriteLine($"IP Address failed to parse or not allowed on this page. {remoteIpAddressStr} {forwardedForHeaderStr}"); context.Result = new ContentResult { StatusCode = (int)HttpStatusCode.Forbidden, diff --git a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs index e7e2ad14..90ea5615 100644 --- a/cppseminar/presentation/Pages/Connection/Index.cshtml.cs +++ b/cppseminar/presentation/Pages/Connection/Index.cshtml.cs @@ -21,13 +21,5 @@ public IndexModel(ILogger logger) { _logger = logger; } - - - public async Task OnGetAsync(){ - _logger.LogInformation(Request.Headers["X-Forwarded-For"]); // this should be able to extract the original IP adress, after it goes through kubernetes - var clientIPAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString(); // extracting ip adress locally - _logger.LogInformation($"Client IP address: {clientIPAddress}"); - } } - }