From 2699dbe6aa562293300fdfa3f2c62e34f6ae3584 Mon Sep 17 00:00:00 2001 From: Slendergo Date: Sat, 12 Dec 2020 23:36:58 +0000 Subject: [PATCH 01/14] Reverted Formatting --- PSTk.Diagnostics/Profiling/TimedProfiler.cs | 29 ++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/PSTk.Diagnostics/Profiling/TimedProfiler.cs b/PSTk.Diagnostics/Profiling/TimedProfiler.cs index 014af74..8d3b2b7 100644 --- a/PSTk.Diagnostics/Profiling/TimedProfiler.cs +++ b/PSTk.Diagnostics/Profiling/TimedProfiler.cs @@ -9,6 +9,11 @@ namespace PSTk.Diagnostics /// public sealed class TimedProfiler : IDisposable { + private string Message { get; } + private Func Condition { get; } + private Action Output { get; } + private Stopwatch Stopwatch { get; } + /// /// Create a new instance of . /// @@ -17,17 +22,11 @@ public sealed class TimedProfiler : IDisposable /// public TimedProfiler(string message, Func condition = null, Action output = null) { - this.message = message; - this.condition = condition; - this.output = output; - stopwatch = Stopwatch.StartNew(); + Message = message; + Condition = condition; + Output = output; + Stopwatch = Stopwatch.StartNew(); } - - private Func condition { get; } - private string message { get; } - private Action output { get; } - private Stopwatch stopwatch { get; } - /// /// Called automatically at the end of the scope when used along side a using statment or explicitly called in the code /// It will only print out the elapsed time when the condition is met if there is a condition to the desired output if set @@ -35,14 +34,14 @@ public TimedProfiler(string message, Func condition = null, Action /// public void Dispose() { - if (condition != null && !condition.Invoke()) + if (Condition != null && !Condition.Invoke()) return; - stopwatch.Stop(); + Stopwatch.Stop(); - var result = $"{message} | Elapsed: {stopwatch.Elapsed} ({stopwatch.ElapsedMilliseconds}ms)"; - output?.Invoke(result); - if (output == null) + var result = $"{Message} | Elapsed: {Stopwatch.Elapsed} ({Stopwatch.ElapsedMilliseconds}ms)"; + Output?.Invoke(result); + if (Output == null) Console.WriteLine(result); } } From e812e7af3fb1b51e875e59223443c356e7d21641 Mon Sep 17 00:00:00 2001 From: Devwarlt Date: Sat, 6 Mar 2021 16:27:55 -0300 Subject: [PATCH 02/14] Working on support for different targets of .NET --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b42dd4a..2967d18 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ For more details, consider to check our [**API documentation**][api-docs]. ## Language & Framework -![language-badge] ![framework-badge] +![language-badge] ![net-core-framework-badge] ![net-framework-badge] ![net-five-framework-badge] ## Build status | Branch | .NET CI Status | GitHub Pages CI Status | @@ -40,7 +40,9 @@ For more details, consider to check our [**API documentation**][api-docs]. [license-badge]: https://img.shields.io/badge/MIT-gray?style=plastic [language-badge]: https://img.shields.io/github/languages/top/Devwarlt/pstk-core?style=plastic&color=purple -[framework-badge]: https://img.shields.io/badge/Core-3.1-purple?logo=.net&style=plastic +[net-framework-badge]: https://img.shields.io/badge/Framework-4.7.2%2B-purple?logo=.net&style=plastic +[net-core-framework-badge]: https://img.shields.io/badge/Core-3.1%2B-purple?logo=.net&style=plastic +[net-five-framework-badge]: https://img.shields.io/badge/%20-5.0%2B-purple?logo=.net&style=plastic [version-badge]: https://img.shields.io/github/release/Devwarlt/pstk-core?color=success&logo=github&style=plastic [size-badge]: https://img.shields.io/github/repo-size/Devwarlt/pstk-core?style=plastic [visitors-badge]: https://visitor-badge.glitch.me/badge?page_id=Devwarlt.pstk-core From 3e1f0da592e8fab13934ff7ea1a224573f5c8d03 Mon Sep 17 00:00:00 2001 From: Devwarlt Date: Sat, 6 Mar 2021 16:29:20 -0300 Subject: [PATCH 03/14] Added support to .NET 4.7.2, .NET Core 3.1 and .NET 5 --- PSTk Distribution.sln | 6 ++++++ PSTk.Core/PSTk.Core.csproj | 11 ++++++----- PSTk.Diagnostics/PSTk.Diagnostics.csproj | 10 +++++----- PSTk.Extensions/PSTk.Extensions.csproj | 10 +++++----- PSTk.Networking/PSTk.Networking.csproj | 9 +++++---- PSTk.Threading/PSTk.Threading.csproj | 10 +++++----- 6 files changed, 32 insertions(+), 24 deletions(-) diff --git a/PSTk Distribution.sln b/PSTk Distribution.sln index 50b7e3c..56b861e 100644 --- a/PSTk Distribution.sln +++ b/PSTk Distribution.sln @@ -47,6 +47,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Articles", "Articles", "{D2 docs\articles\toc.yml = docs\articles\toc.yml EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PSTk.Redis", "PSTk.Redis\PSTk.Redis.csproj", "{70734C00-A57D-44C2-A9AF-8C53438867C9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -73,6 +75,10 @@ Global {3023C538-B4F6-45C4-A683-923BF7AF2E09}.Debug|Any CPU.Build.0 = Debug|Any CPU {3023C538-B4F6-45C4-A683-923BF7AF2E09}.Release|Any CPU.ActiveCfg = Release|Any CPU {3023C538-B4F6-45C4-A683-923BF7AF2E09}.Release|Any CPU.Build.0 = Release|Any CPU + {70734C00-A57D-44C2-A9AF-8C53438867C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {70734C00-A57D-44C2-A9AF-8C53438867C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {70734C00-A57D-44C2-A9AF-8C53438867C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {70734C00-A57D-44C2-A9AF-8C53438867C9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PSTk.Core/PSTk.Core.csproj b/PSTk.Core/PSTk.Core.csproj index 755ba48..238aae9 100644 --- a/PSTk.Core/PSTk.Core.csproj +++ b/PSTk.Core/PSTk.Core.csproj @@ -1,11 +1,11 @@  - netcoreapp3.1 + netcoreapp3.1;net472;net5.0 true true PSTk Core Team - Copyright © PSTk Core Team 2020 + Copyright © PSTk Core Team 2021 PSTk Core Team PSTk.Core PSTk is a collection of features available in .NET Core that enhances your game server performance. This toolkit contains optimized code and utilities commonly used on game development. @@ -21,18 +21,18 @@ true PSTk.Core ICON.ico - 1.0.2 + 1.1.2 DEBUG;TRACE - bin\Debug\netcoreapp3.1\PSTk.Core.xml + bin\Debug\$(TargetFramework)\PSTk.Core.xml true x64 - bin\Release\netcoreapp3.1\PSTk.Core.xml + bin\Release\$(TargetFramework)\PSTk.Core.xml @@ -47,6 +47,7 @@ true true + true true diff --git a/PSTk.Diagnostics/PSTk.Diagnostics.csproj b/PSTk.Diagnostics/PSTk.Diagnostics.csproj index 2a9aee9..a8392b3 100644 --- a/PSTk.Diagnostics/PSTk.Diagnostics.csproj +++ b/PSTk.Diagnostics/PSTk.Diagnostics.csproj @@ -1,33 +1,33 @@  - netcoreapp3.1 + netcoreapp3.1;net472;net5.0 Contains diagnostic utilities part of PSTk.Core toolkit. true true LICENSE true PSTk Core Team - Copyright © PSTk Core Team 2020 + Copyright © PSTk Core Team 2021 https://github.com/Devwarlt/pstk-core https://github.com/Devwarlt/pstk-core ICON.png Git dotnet;toolkit;game-tools;pserver ICON.ico - 1.1.0 + 1.2.0 DEBUG;TRACE false false - bin\Debug\netcoreapp3.1\PSTk.Diagnostics.xml + bin\Debug\$(TargetFramework)\PSTk.Diagnostics.xml true - bin\Release\netcoreapp3.1\PSTk.Diagnostics.xml + bin\Release\$(TargetFramework)\PSTk.Diagnostics.xml x64 diff --git a/PSTk.Extensions/PSTk.Extensions.csproj b/PSTk.Extensions/PSTk.Extensions.csproj index a161a3d..4f1986a 100644 --- a/PSTk.Extensions/PSTk.Extensions.csproj +++ b/PSTk.Extensions/PSTk.Extensions.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1 + netcoreapp3.1;net472;net5.0 true LICENSE true @@ -9,24 +9,24 @@ PSTk Core Team true Contains extension utilities part of PSTk.Core toolkit. - Copyright © PSTk Core Team 2020 + Copyright © PSTk Core Team 2021 https://github.com/Devwarlt/pstk-core https://github.com/Devwarlt/pstk-core ICON.png Git dotnet;toolkit;game-tools;pserver ICON.ico - 1.1.0 + 1.2.0 DEBUG;TRACE - bin\Debug\netcoreapp3.1\PSTk.Extensions.xml + bin\Debug\$(TargetFramework)\PSTk.Extensions.xml true - bin\Release\netcoreapp3.1\PSTk.Extensions.xml + bin\Release\$(TargetFramework)\PSTk.Extensions.xml x64 diff --git a/PSTk.Networking/PSTk.Networking.csproj b/PSTk.Networking/PSTk.Networking.csproj index 8d1a01d..b1d9660 100644 --- a/PSTk.Networking/PSTk.Networking.csproj +++ b/PSTk.Networking/PSTk.Networking.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1 + netcoreapp3.1;net472;net5.0 true LICENSE true @@ -9,24 +9,25 @@ PSTk Core Team true Contains networking utilities part of PSTk.Core toolkit. - Copyright © PSTk Core Team 2020 + Copyright © PSTk Core Team 2021 https://github.com/Devwarlt/pstk-core https://github.com/Devwarlt/pstk-core ICON.png Git dotnet;toolkit;game-tools;pserver ICON.ico + 1.1.0 DEBUG;TRACE - bin\Debug\netcoreapp3.1\PSTk.Networking.xml + bin\Debug\$(TargetFramework)\PSTk.Networking.xml x64 true - bin\Release\netcoreapp3.1\PSTk.Networking.xml + bin\Release\$(TargetFramework)\PSTk.Networking.xml diff --git a/PSTk.Threading/PSTk.Threading.csproj b/PSTk.Threading/PSTk.Threading.csproj index eab14c8..0fb491d 100644 --- a/PSTk.Threading/PSTk.Threading.csproj +++ b/PSTk.Threading/PSTk.Threading.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1 + netcoreapp3.1;net472;net5.0 true LICENSE true @@ -9,25 +9,25 @@ PSTk Core Team true Contains threading utilities part of PSTk.Core toolkit. - Copyright © PSTk Core Team 2020 + Copyright © PSTk Core Team 2021 https://github.com/Devwarlt/pstk-core https://github.com/Devwarlt/pstk-core ICON.png Git dotnet;toolkit;game-tools;pserver ICON.ico - 1.2.0 + 1.3.0 DEBUG;TRACE - bin\Debug\netcoreapp3.1\PSTk.Threading.xml + bin\Debug\$(TargetFramework)\PSTk.Threading.xml true x64 - bin\Release\netcoreapp3.1\PSTk.Threading.xml + bin\Release\$(TargetFramework)\PSTk.Threading.xml From 7c317fcf2a689176d2d09b00e2f35c0d59e9d216 Mon Sep 17 00:00:00 2001 From: Devwarlt Date: Sat, 6 Mar 2021 16:29:57 -0300 Subject: [PATCH 04/14] WIP: template for new distribution PSTk.Redis --- PSTk.Redis/ICON.ico | Bin 0 -> 16446 bytes PSTk.Redis/PSTk.Redis.csproj | 47 +++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 PSTk.Redis/ICON.ico create mode 100644 PSTk.Redis/PSTk.Redis.csproj diff --git a/PSTk.Redis/ICON.ico b/PSTk.Redis/ICON.ico new file mode 100644 index 0000000000000000000000000000000000000000..c888c0b99164b5236e3157195e0c2bddbbbfca63 GIT binary patch literal 16446 zcmeHLYfKea5MI>!Zi=;$T4PJC25O5mq?pj4Qktku2#x=2ghpsuk;DiJR#5PkKnYc_ zX^I#F8Zq`?BUG@8b&9dFScklIA(}67K-raNN%s2DR zH)k=7F!h_1WT?N9Mzk7-8HN$9F7?sysSEere#kILE{TC~KsX>A5Do|jgag6>;ec>J zI3OGl4hRQ?1Hu8}fN(bIZ*@RE8H7Kd*B2v#$UQ<5tS7d(w~ziY0TKOAvIO6fzQ9E zq&V*3B{o+4lecfDsE!VT-~QIJ@9?8~_G~IDDbcZuJ#c{DIeV7gx_FTyy1FRh$`y+2 z?4)fd>wUl2uz|*$I6>q0?W2MB?&|D_HLpKX^88*)q*9;P0hufSZZU%{1otaT8f^z+`MV#fN{fbtoFFVHA8}y(=zq|E@CkeL zfABzS`EcboYx%op&d~P?57x2&j2HaLRQfZovQlFP?u3>W?I(26o-1C@`X5OD#vVRw z))@RlEny5r^PKX}_*ws9+v$RqC-2x{o;b@wp3ifvBkLmj77BiF5_t#rk%utV zZ)UDu9WwXfiyMB{Da=8?1J8fV%cH@n-hd1BK1-cHX4TZtICU<8Puv3-H@;_AS3CL_ zDt>4nv_4_a9_|I@}sO5M0o_djqE^;nsk zYxV%}1=z6$=Ue27?eSQbkwKqt-b_PPFGFvK4V$bdeI}Gy@jQv^v1PoIuGbiQ`Fh)n^mjK-iIFWfzs{)FZwFZan`S&CE4xh~JZV9!B(ZXd3hl{TBB|t1}PIS2$<7<=-nlFZ1vY#rRmm+(xTD!Zvsq z=={&U8kn5klic=#reF=urgr{&!4=FL_~_;b?xWWHowebseZ5m{I?c1MX9L z9}HHRt0Ju8Dwo7SI3OGl4hRQ?1Hu8}fN(%KARG`52nU1%!U5rca6mX991so&2ZRH{ Jf&VH8{stIo$p!!b literal 0 HcmV?d00001 diff --git a/PSTk.Redis/PSTk.Redis.csproj b/PSTk.Redis/PSTk.Redis.csproj new file mode 100644 index 0000000..49ea96b --- /dev/null +++ b/PSTk.Redis/PSTk.Redis.csproj @@ -0,0 +1,47 @@ + + + + netcoreapp3.1;net472;net5.0 + true + LICENSE + true + PSTk Core Team + PSTk Core Team + true + Contains Redis utilities part of PSTk.Core toolkit. + Copyright © PSTk Core Team 2021 + https://github.com/Devwarlt/pstk-core + https://github.com/Devwarlt/pstk-core + ICON.png + Git + dotnet;toolkit;game-tools;pserver + ICON.ico + 1.0.0 + + + + DEBUG;TRACE + bin\Debug\$(TargetFramework)\PSTk.Threading.xml + + + + true + x64 + bin\Release\$(TargetFramework)\PSTk.Threading.xml + + + + + + + + + True + + + + True + + + + From f8cdcfcd1bc2a275a8627df37180aba400bae9d3 Mon Sep 17 00:00:00 2001 From: Devwarlt Date: Sat, 6 Mar 2021 16:32:17 -0300 Subject: [PATCH 05/14] Include new distribution stats info from Nuget API --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 2967d18..9f7fa96 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ For more details, consider to check our [**API documentation**][api-docs]. | **`PSTk.Extensions`** | [![pstk-extensions-badge]][pstk-extensions-nuget] | [![pstk-extensions-downloads-badge]][pstk-extensions-nuget] | | **`PSTk.Networking`** | [![pstk-networking-badge]][pstk-networking-nuget] | [![pstk-networking-downloads-badge]][pstk-networking-nuget] | | **`PSTk.Threading`** | [![pstk-threading-badge]][pstk-threading-nuget] | [![pstk-threading-downloads-badge]][pstk-threading-nuget] | +| **`PSTk.Redis`** | [![pstk-redis-badge]][pstk-redis-nuget] | [![pstk-redis-downloads-badge]][pstk-redis-nuget] | ### Contributors - [@Devwarlt][devwarlt-ref] @@ -74,3 +75,7 @@ For more details, consider to check our [**API documentation**][api-docs]. [pstk-threading-badge]: https://img.shields.io/nuget/v/PSTk.Threading.svg?logo=nuget&style=plastic [pstk-threading-downloads-badge]: https://img.shields.io/nuget/dt/PSTk.Threading.svg?logo=nuget&style=plastic [pstk-threading-nuget]: https://www.nuget.org/packages/PSTk.Threading/ + +[pstk-redis-badge]: https://img.shields.io/nuget/v/PSTk.Redis.svg?logo=nuget&style=plastic +[pstk-redis-downloads-badge]: https://img.shields.io/nuget/dt/PSTk.Redis.svg?logo=nuget&style=plastic +[pstk-redis-nuget]: https://www.nuget.org/packages/PSTk.Redis/ From e9b08cb3139b75be853427df1f5f816d202ea917 Mon Sep 17 00:00:00 2001 From: Devwarlt Date: Sat, 6 Mar 2021 18:17:00 -0300 Subject: [PATCH 06/14] Create .editorconfig --- .editorconfig | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4e13c08 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[*.cs] + +# IDE0063: Use simple 'using' statement +csharp_prefer_simple_using_statement = false:suggestion From b46403568fe584bcb311f9d8ce42d98f7d445e88 Mon Sep 17 00:00:00 2001 From: Devwarlt Date: Sat, 6 Mar 2021 18:17:33 -0300 Subject: [PATCH 07/14] Update package versions + new distribution config: PSTk.Redis --- nuget-push-all.bat | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/nuget-push-all.bat b/nuget-push-all.bat index e1b14d1..06c8e17 100644 --- a/nuget-push-all.bat +++ b/nuget-push-all.bat @@ -14,11 +14,12 @@ IF "%~2"=="" (SET /P TOKEN="Enter API token: ") ECHO. -SET CORE_PKG_VERSION=1.0.2 -SET DIAGNOSTICS_PKG_VERSION=1.1.0 -SET EXTENSIONS_PKG_VERSION=1.1.0 -SET NETWORKING_PKG_VERSION=1.0.0 -SET THREADING_PKG_VERSION=1.2.0 +SET CORE_PKG_VERSION=1.1.2 +SET DIAGNOSTICS_PKG_VERSION=1.2.0 +SET EXTENSIONS_PKG_VERSION=1.2.0 +SET NETWORKING_PKG_VERSION=1.1.0 +SET REDIS_PKG_VERSION=1.0.0 +SET THREADING_PKG_VERSION=1.3.0 ECHO Packing all distributions... @@ -29,4 +30,5 @@ START nuget-push-package.bat PSTk.Diagnostics %DIAGNOSTICS_PKG_VERSION% %SOURCE% START nuget-push-package.bat PSTk.Extensions %EXTENSIONS_PKG_VERSION% %SOURCE% %TOKEN% START nuget-push-package.bat PSTk.Networking %NETWORKING_PKG_VERSION% %SOURCE% %TOKEN% START nuget-push-package.bat PSTk.Threading %THREADING_PKG_VERSION% %SOURCE% %TOKEN% +START nuget-push-package.bat PSTk.Redis %REDIS_PKG_VERSION% %SOURCE% %TOKEN% ENDLOCAL \ No newline at end of file From 6d85192f2e26758ceebbe1a82a774614ef41653c Mon Sep 17 00:00:00 2001 From: Devwarlt Date: Sat, 6 Mar 2021 18:17:42 -0300 Subject: [PATCH 08/14] Update PSTk Distribution.sln --- PSTk Distribution.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/PSTk Distribution.sln b/PSTk Distribution.sln index 56b861e..25164e5 100644 --- a/PSTk Distribution.sln +++ b/PSTk Distribution.sln @@ -22,6 +22,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Deployment Scripts", "Deplo EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{923F2816-ACF9-4BBE-8D75-E17F3F0E7376}" ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig .gitattributes = .gitattributes .gitignore = .gitignore LICENSE = LICENSE From b25b3fc313a83b1d980be05690b938d3c03eeb79 Mon Sep 17 00:00:00 2001 From: Devwarlt Date: Sat, 6 Mar 2021 18:18:15 -0300 Subject: [PATCH 09/14] [PSTk.Core] Support to .NET 4.7.2 (updated code syntax) --- PSTk.Core/Tools/Google/GMailValidator.cs | 24 +++++++++++------- PSTk.Core/Tools/SerialNumberGenerator.cs | 32 +++++++++++++----------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/PSTk.Core/Tools/Google/GMailValidator.cs b/PSTk.Core/Tools/Google/GMailValidator.cs index 8db420b..07058d9 100644 --- a/PSTk.Core/Tools/Google/GMailValidator.cs +++ b/PSTk.Core/Tools/Google/GMailValidator.cs @@ -37,15 +37,21 @@ public GMailValidator(string emailRegistry) /// public bool IsValid(string email) { - using var client = new TcpClient(SMTP_DNS, SMTP_PORT); - using var stream = client.GetStream(); - using var rdr = new StreamReader(stream); - PerformHELO(stream, rdr); - PerformMAIL(emailRegistry, stream, rdr); - PerformRCPT(stream, rdr, email, out var isValid); - PerformQUITE(stream); - client.Close(); - return isValid; + using (var client = new TcpClient(SMTP_DNS, SMTP_PORT)) + { + using (var stream = client.GetStream()) + { + using (var rdr = new StreamReader(stream)) + { + PerformHELO(stream, rdr); + PerformMAIL(emailRegistry, stream, rdr); + PerformRCPT(stream, rdr, email, out var isValid); + PerformQUITE(stream); + client.Close(); + return isValid; + } + } + } } private static void PerformHELO(NetworkStream stream, StreamReader rdr) diff --git a/PSTk.Core/Tools/SerialNumberGenerator.cs b/PSTk.Core/Tools/SerialNumberGenerator.cs index 88401af..a09b92b 100644 --- a/PSTk.Core/Tools/SerialNumberGenerator.cs +++ b/PSTk.Core/Tools/SerialNumberGenerator.cs @@ -39,23 +39,25 @@ public SerialNumberGenerator(string secret, int pieceSize = 4, char pieceSeparat /// public string Create(string text) { - using var sha256 = new SHA256Managed(); - var buffer = Encoding.UTF8.GetBytes(text + secret); - var hash = sha256.ComputeHash(buffer); - var encoder = Convert.ToBase64String(hash); - var byteHash = EightByteHash(encoder); - var byteHashAbs = Math.Abs(byteHash) * 10f + (byteHash < 0 ? 1d : 0d); - var key = new StringBuilder(); - var hashStr = byteHashAbs.ToString(); - var pieces = hashStr.ChunkSplit(pieceSize).ToArray(); - for (var i = 0; i < pieces.Length; i++) + using (var sha256 = new SHA256Managed()) { - var piece = ushort.Parse(pieces[i]); - key.Append($"{piece:X4}"); - if (i + 1 < pieces.Length) - key.Append(pieceSeparator); + var buffer = Encoding.UTF8.GetBytes(text + secret); + var hash = sha256.ComputeHash(buffer); + var encoder = Convert.ToBase64String(hash); + var byteHash = EightByteHash(encoder); + var byteHashAbs = Math.Abs(byteHash) * 10f + (byteHash < 0 ? 1d : 0d); + var key = new StringBuilder(); + var hashStr = byteHashAbs.ToString(); + var pieces = hashStr.ChunkSplit(pieceSize).ToArray(); + for (var i = 0; i < pieces.Length; i++) + { + var piece = ushort.Parse(pieces[i]); + key.Append($"{piece:X4}"); + if (i + 1 < pieces.Length) + key.Append(pieceSeparator); + } + return key.ToString(); } - return key.ToString(); } private int EightByteHash(string text) From 2dd5b628b5744a0021a497987f7f383c6d521ff6 Mon Sep 17 00:00:00 2001 From: Devwarlt Date: Sat, 6 Mar 2021 18:18:30 -0300 Subject: [PATCH 10/14] [PSTk.Diagnostics] Support to .NET 4.7.2 (updated code syntax) --- PSTk.Diagnostics/Logging/LogSlim.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/PSTk.Diagnostics/Logging/LogSlim.cs b/PSTk.Diagnostics/Logging/LogSlim.cs index 678cdc0..536a388 100644 --- a/PSTk.Diagnostics/Logging/LogSlim.cs +++ b/PSTk.Diagnostics/Logging/LogSlim.cs @@ -98,6 +98,21 @@ public void OnUnhandledException(object sender, UnhandledExceptionEventArgs args public void PrintWarn(string message) => OnConsoleLog(Wrn, message, ConsoleColor.Yellow); private static string GenerateTimePattern(LogTimeOptions options) +#if NET472 + { + switch (options) + { + case LogTimeOptions.Classic: return "MM/dd/yyyy hh:mm tt"; + case LogTimeOptions.ClassicRegular: return "MM/dd/yyyy hh:mm:ss tt"; + case LogTimeOptions.ClassicScientific: return "MM/dd/yyyy hh:mm:ss:ffff tt"; + case LogTimeOptions.FullRegular: return "dddd, dd MMMM yyyy - HH:mm:ss tt"; + case LogTimeOptions.FullScientific: return "dddd, dd MMMM yyyy - HH:mm:ss:ffff"; + case LogTimeOptions.Regular: return "HH:mm:ss tt"; + case LogTimeOptions.Scientific: return "HH:mm:ss:ffff"; + default: return string.Empty; + } + } +#else => options switch { LogTimeOptions.Classic => "MM/dd/yyyy hh:mm tt", @@ -110,6 +125,8 @@ private static string GenerateTimePattern(LogTimeOptions options) _ => string.Empty }; +#endif + private string LogHeader(string level) => $"[{LogTimer()}] | [{level}] | <{typeof(T).Name}> -> "; private string LogTimer() => DateTime.Now.ToString(timePattern); From 0abb34328927f36738e452ee1dc56eb1dcba7948 Mon Sep 17 00:00:00 2001 From: Devwarlt Date: Sat, 6 Mar 2021 18:18:40 -0300 Subject: [PATCH 11/14] [PSTk.Extensions] Support to .NET 4.7.2 (updated code syntax) --- PSTk.Extensions/PSTk.Extensions.csproj | 1 + PSTk.Extensions/Utils/BufferExtensions.cs | 30 ++++++++++++++------- PSTk.Extensions/Utils/DateTimeExtensions.cs | 4 +++ PSTk.Extensions/Utils/StringExtensions.cs | 9 ++++++- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/PSTk.Extensions/PSTk.Extensions.csproj b/PSTk.Extensions/PSTk.Extensions.csproj index 4f1986a..66904e2 100644 --- a/PSTk.Extensions/PSTk.Extensions.csproj +++ b/PSTk.Extensions/PSTk.Extensions.csproj @@ -31,6 +31,7 @@ + True diff --git a/PSTk.Extensions/Utils/BufferExtensions.cs b/PSTk.Extensions/Utils/BufferExtensions.cs index 93b2d73..c052b30 100644 --- a/PSTk.Extensions/Utils/BufferExtensions.cs +++ b/PSTk.Extensions/Utils/BufferExtensions.cs @@ -20,11 +20,15 @@ public static byte[] GZipCompress(this byte[] buffer) if (buffer == null) throw new ArgumentNullException(nameof(buffer), "Cannot compress a null buffer."); - using var stream = new MemoryStream(); - using var zip = new GZipStream(stream, CompressionMode.Compress); - zip.Write(buffer, 0, buffer.Length); - zip.Close(); - return stream.ToArray(); + using (var stream = new MemoryStream()) + { + using (var zip = new GZipStream(stream, CompressionMode.Compress)) + { + zip.Write(buffer, 0, buffer.Length); + zip.Close(); + return stream.ToArray(); + } + } } /// @@ -38,11 +42,17 @@ public static byte[] GZipDecompress(this byte[] buffer) if (buffer == null) throw new ArgumentNullException(nameof(buffer), "Cannot decompress a null buffer."); - using var zipStream = new MemoryStream(buffer); - using var stream = new MemoryStream(); - using var unzip = new GZipStream(zipStream, CompressionMode.Decompress); - unzip.CopyTo(stream); - return stream.ToArray(); + using (var zipStream = new MemoryStream(buffer)) + { + using (var stream = new MemoryStream()) + { + using (var unzip = new GZipStream(zipStream, CompressionMode.Decompress)) + { + unzip.CopyTo(stream); + return stream.ToArray(); + } + } + } } } } diff --git a/PSTk.Extensions/Utils/DateTimeExtensions.cs b/PSTk.Extensions/Utils/DateTimeExtensions.cs index 43fc2d4..8108fef 100644 --- a/PSTk.Extensions/Utils/DateTimeExtensions.cs +++ b/PSTk.Extensions/Utils/DateTimeExtensions.cs @@ -71,7 +71,11 @@ public static string GetElapsedTime(this DateTime date, string header) } sb.Append(" and "); +#if NET472 + sb.Append(format[format.Count - 1]); +#else sb.Append(format[^1]); +#endif } else { diff --git a/PSTk.Extensions/Utils/StringExtensions.cs b/PSTk.Extensions/Utils/StringExtensions.cs index 6be0b68..c9d7229 100644 --- a/PSTk.Extensions/Utils/StringExtensions.cs +++ b/PSTk.Extensions/Utils/StringExtensions.cs @@ -51,6 +51,13 @@ public static string ToHumanReadable(this string text) /// /// /// - public static string ToUpperFirst(this string text) => char.ToUpper(text[0]) + text[1..]; + public static string ToUpperFirst(this string text) + => char.ToUpper(text[0]) + +#if NET472 + text.Substring(1); +#else + text[1..]; + +#endif } } From d3473c6db3277b1829ac688f9e87608ae5b273c1 Mon Sep 17 00:00:00 2001 From: Devwarlt Date: Sat, 6 Mar 2021 18:18:49 -0300 Subject: [PATCH 12/14] Delete ConnectionCentral.cs --- PSTk.Networking/ConnectionCentral.cs | 177 --------------------------- 1 file changed, 177 deletions(-) delete mode 100644 PSTk.Networking/ConnectionCentral.cs diff --git a/PSTk.Networking/ConnectionCentral.cs b/PSTk.Networking/ConnectionCentral.cs deleted file mode 100644 index db16be4..0000000 --- a/PSTk.Networking/ConnectionCentral.cs +++ /dev/null @@ -1,177 +0,0 @@ -using PSTk.Networking.Utils; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -namespace PSTk.Networking -{ - /// - /// Represents a local instance of server listener, using TCP protocol, that could be configured for any . - /// - /// - /// - /// - [Obsolete("This feature isn't completed, avoid use it for your projects. No test was made within its development period.", true)] - public sealed class ConnectionCentral - { - private readonly int bufferSize; - private readonly List connections; - private readonly TcpListener listener; - private readonly ushort maxPacketsPerEndPoint; - private readonly CancellationTokenSource source; - -#pragma warning disable - - public ConnectionCentral(int port, ushort maxConnections, ushort maxPacketsPerEndPoint, int bufferSize) - : this(port, maxConnections, maxPacketsPerEndPoint, bufferSize, ConnectionType.Local) { } - - public ConnectionCentral(int port, ushort maxConnections, ushort maxPacketsPerEndPoint, int bufferSize, ConnectionType type, Action errorLogger = null) - -#pragma warning restore - - { - if (maxConnections == 0) - throw new ArgumentException("This service needs to listen for at least 1 inbound connection.", nameof(maxConnections)); - - if (maxPacketsPerEndPoint == 0) - throw new ArgumentException("This service needs to handle at least 1 inbound packet per endpoint.", nameof(maxPacketsPerEndPoint)); - - if (!Enum.IsDefined(typeof(ConnectionType), (short)type)) - throw new ArgumentOutOfRangeException(nameof(type), $"ConnectionType {(ushort)type} is invalid."); - - if (bufferSize <= 0) throw new ArgumentOutOfRangeException(nameof(bufferSize), "Only non-zero and non-negative values are permitted."); - - this.maxPacketsPerEndPoint = maxPacketsPerEndPoint; - this.bufferSize = bufferSize; - - listener = TcpListener.Create(port); - listener.Server.NoDelay = true; - listener.Server.UseOnlyOverlappedIO = true; - listener.Server.Ttl = (short)type; - source = new CancellationTokenSource(); - connections = new List(maxConnections); - onError += (s, e) => errorLogger?.Invoke(e.ToString()); - } - - private event EventHandler onError; - - /// - /// Get the current flag. - /// - public ConnectionFlag GetFlag { get; private set; } = ConnectionFlag.Idle; - - /// - /// Get the maximum number of associated per . - /// - public int MaxInboundConnectionsByIp { get; private set; } - - /// - /// Gets a matrix of all from all . - /// - /// - public InboundPacket[][] GetAllInboundPackets() - { - var matrix = new List(); - var conns = connections.ToArray(); - - for (var i = 0; i < conns.Length; i++) - { - var packets = conns[i].GetEndPointPackets().ToArray(); - - if (packets.Length == 0) continue; - - matrix.Add(packets); - } - - return matrix.ToArray(); - } - - /// - /// Start listening for new clients. - /// - /// - public void Start() - { - try - { - if (GetFlag == ConnectionFlag.Listening) - throw new InvalidOperationException("This service can only run in a single thread for inbound connections."); - - GetFlag = ConnectionFlag.Listening; - - Accept(); - } - catch (InvalidOperationException e) { onError.Invoke(null, e); } - } - - /// - /// Stop listening for new clients. - /// - /// - public void Stop() - { - try - { - if (source.IsCancellationRequested || GetFlag == ConnectionFlag.Aborted) - throw new InvalidOperationException("This server was already stopped."); - - GetFlag = ConnectionFlag.Aborted; - - var conns = connections.ToArray(); - - for (var i = 0; i < conns.Length; i++) - try { conns[i].Stop(); } - catch (InvalidOperationException) { } - } - catch (InvalidOperationException e) { onError.Invoke(null, e); } - } - - private void Accept() - { - Initialize(async () => - { - var conn = await listener.AcceptTcpClientAsync(); - var ip = conn.Client.GetIpAddress(); - - if (ip != null) - { - var currConn = connections.FirstOrDefault(connection => connection.Equals(ip)); - - if (currConn == default) - { - var inboundConn = new InboundConnection(this, bufferSize, maxPacketsPerEndPoint); - - try - { - inboundConn.Add(conn); - inboundConn.AttachToParent(source.Token); - connections.Add(inboundConn); - } - catch (InvalidCastException e) { onError.Invoke(null, e); } - } - else - currConn.Add(conn); - } - }); - - if (GetFlag != ConnectionFlag.Listening) return; - - Accept(); - } - - private void Initialize(Action method) - { - try - { - source.Token.ThrowIfCancellationRequested(); - - Task.Run(() => method.Invoke(), source.Token); - } - catch (OperationCanceledException) { Stop(); } - } - } -} From 109533290c05941acc15b956bd53e5d7f3404313 Mon Sep 17 00:00:00 2001 From: Devwarlt Date: Sat, 6 Mar 2021 18:18:52 -0300 Subject: [PATCH 13/14] Delete InboundConnection.cs --- PSTk.Networking/InboundConnection.cs | 265 --------------------------- 1 file changed, 265 deletions(-) delete mode 100644 PSTk.Networking/InboundConnection.cs diff --git a/PSTk.Networking/InboundConnection.cs b/PSTk.Networking/InboundConnection.cs deleted file mode 100644 index 0786381..0000000 --- a/PSTk.Networking/InboundConnection.cs +++ /dev/null @@ -1,265 +0,0 @@ -using PSTk.Networking.Utils; -using PSTk.Threading.Tasks.Procedures; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -namespace PSTk.Networking -{ - /// - /// Represents an inbound connection type. - /// - /// - /// - /// - /// - [Obsolete("This feature isn't completed, avoid use it for your projects. No test was made within its development period.", true)] - public class InboundConnection : IAttachedTask - { - private readonly int bufferSize; - private readonly object inboundLocker; - private readonly List inboundTraffics; - private readonly int maxConnections; - private readonly ushort maxPacketsPerEndPoint; - -#pragma warning disable - - private CancellationToken token; - - public InboundConnection(ConnectionCentral central, int bufferSize, ushort maxPacketsPerEndPoint) - { - this.bufferSize = bufferSize; - this.maxPacketsPerEndPoint = maxPacketsPerEndPoint; - - inboundLocker = new object(); - maxConnections = central.MaxInboundConnectionsByIp; - token = default; - inboundTraffics = new List(); - - GetFlag = ConnectionFlag.Idle; - Clients = new List(); - - onAdd = null; - } - -#pragma warning restore - - private event EventHandler onAdd; - - /// - /// Get a list of all sockets associated to . - /// - public List Clients { get; private set; } - - /// - /// Get number of connections associated to . - /// - public int GetConnections { get { lock (inboundLocker) return Clients.Count; } } - - /// - /// Get the current flag. - /// - public ConnectionFlag GetFlag { get; private set; } - - /// - /// Returns the from remote associated . - /// - public IPAddress GetIPAddress - { - get - { - lock (inboundLocker) - if (Clients.Count == 0) - throw new InvalidOperationException("There is no IP associated to any socket yet."); - - return Clients.Where(skt => skt != null).First().Client.GetIpAddress(); - } - } - -#pragma warning disable - - public string Name => throw new NotImplementedException(); - -#pragma warning restore - - /// - /// Get the of attached task. - /// - public CancellationToken Token => token; - -#pragma warning disable - - public static bool operator !=(InboundConnection a, InboundConnection b) => !a.Equals(b); - - public static bool operator ==(InboundConnection a, InboundConnection b) => a.Equals(b); - -#pragma warning restore - - /// - /// Add to current inbound connection of current thread. - /// - /// - /// - public void Add(TcpClient tcpClient) - { - lock (inboundLocker) - if (Clients.Count == maxConnections) - throw new InvalidCastException($"Cannot associate more sockets to current IP {tcpClient.Client.GetIpAddress()}, limit is set to {maxConnections}."); - - Clients.Add(tcpClient); - - onAdd.Invoke(null, tcpClient); - } - - /// - /// Attach a process to parent in case of external task cancellation request. - /// - /// - public void AttachToParent(CancellationToken token) => this.token = token; - - /// - /// Compare two by . - /// - /// - /// - public override bool Equals(object obj) - { - if (!(obj is InboundConnection)) return false; - - var toCompare = (InboundConnection)obj; - - return toCompare.GetIPAddress.Equals(toCompare.GetIPAddress); - } - - /// - /// Get an enumerable of from . - /// All pending packets are enqueued into for each . - /// - /// - public IEnumerable GetEndPointPackets() - { - var traffics = inboundTraffics.ToArray(); - - for (var i = 0; i < traffics.Length; i++) - { - if (GetFlag == ConnectionFlag.Aborted) yield break; - - var inboundTraffic = traffics[i]; - - if (!inboundTraffic.HasPackets) continue; - - yield return new InboundPacket(traffics[i].EndPoint, traffics[i].Dequeue()); - } - } - -#pragma warning disable - - public override int GetHashCode() => GetIPAddress.GetHashCode(); - -#pragma warning restore - - /// - /// Remove to current inbound connection of current thread. - /// - /// - /// - /// - public void Remove(TcpClient tcpClient) - { - lock (inboundLocker) - if (Clients.Count == 0) - throw new InvalidOperationException($"There is no socket to remove from current IP {tcpClient.Client.GetIpAddress()}."); - - if (Clients.Contains(tcpClient)) - { - Clients.Remove(tcpClient); - tcpClient.Close(); - } - } - - /// - /// Start listening for inbound traffic. - /// - /// - public void Start() - { - if (token == default) throw new InvalidOperationException("InboundConnection task is not attached to parent."); - - if (GetFlag == ConnectionFlag.Listening) - throw new InvalidOperationException("This listener can only run in a single thread for inbound traffic."); - - GetFlag = ConnectionFlag.Listening; - - onAdd += OnAddSocket; - } - - /// - /// Stop listening for inbound traffic. - /// - /// - public void Stop() - { - if (token.IsCancellationRequested || GetFlag == ConnectionFlag.Aborted) - throw new InvalidOperationException("This listener was already stopped."); - - GetFlag = ConnectionFlag.Aborted; - - onAdd -= OnAddSocket; - - lock (inboundLocker) - for (var i = 0; i < Clients.Count; i++) - Clients[i].Close(); - } - - private void OnAddSocket(object sender, TcpClient tcpClient) - { - if (sender == null) return; - - if (tcpClient.Connected) - { - var procedure = new AsyncProcedure>( - $"{GetIPAddress} - PID: #{Clients.Count + 1}", - new KeyValuePair((InboundConnection)sender, tcpClient), - (instance, name, input) => - { - var inboundConn = input.Key; - var socket = input.Value; - - do - { - if (!socket.Connected) break; - - var buffer = new byte[inboundConn.bufferSize]; - var receiveTask = Task.Run(async () => await socket.GetStream().ReadAsync(buffer.AsMemory(0, buffer.Length))); - - Task.WaitAll(receiveTask); - - var data = receiveTask.Result; - var inboundTraffic = inboundConn.inboundTraffics.FirstOrDefault(inb => inb.EndPoint == socket.Client.RemoteEndPoint); - - if (inboundTraffic == default) - { - inboundTraffic = new InboundTraffic(socket.Client.RemoteEndPoint, inboundConn.maxPacketsPerEndPoint); - inboundConn.inboundTraffics.Add(inboundTraffic); - } - - inboundTraffic.Enqueue(data); - } while (inboundConn.GetFlag == ConnectionFlag.Listening); - - inboundConn.Remove(socket); - - return new AsyncProcedureEventArgs>(input, true); - } - ); - procedure.AttachToParent(Token); - procedure.Execute(); - } - else - throw new SocketException((int)SocketError.NotConnected); - } - } -} From d00a36fe98ccac7d33f68b723b2af0868c1332c2 Mon Sep 17 00:00:00 2001 From: Devwarlt Date: Sat, 6 Mar 2021 18:19:31 -0300 Subject: [PATCH 14/14] PSTk.Redis implementation --- PSTk.Redis/Database/RedisEngine.cs | 74 ++++ PSTk.Redis/Database/RedisField.cs | 40 +++ PSTk.Redis/Database/RedisObject.cs | 360 +++++++++++++++++++ PSTk.Redis/Database/RedisSettings.cs | 46 +++ PSTk.Redis/Exceptions/ConnectionException.cs | 18 + PSTk.Redis/GlobalSuppressions.cs | 8 + PSTk.Redis/PSTk.Redis.csproj | 5 + 7 files changed, 551 insertions(+) create mode 100644 PSTk.Redis/Database/RedisEngine.cs create mode 100644 PSTk.Redis/Database/RedisField.cs create mode 100644 PSTk.Redis/Database/RedisObject.cs create mode 100644 PSTk.Redis/Database/RedisSettings.cs create mode 100644 PSTk.Redis/Exceptions/ConnectionException.cs create mode 100644 PSTk.Redis/GlobalSuppressions.cs diff --git a/PSTk.Redis/Database/RedisEngine.cs b/PSTk.Redis/Database/RedisEngine.cs new file mode 100644 index 0000000..de45ced --- /dev/null +++ b/PSTk.Redis/Database/RedisEngine.cs @@ -0,0 +1,74 @@ +using PSTk.Redis.Exceptions; +using StackExchange.Redis; +using System; +using System.Text; + +namespace PSTk.Redis.Database +{ + /// + /// Base class to initialize Redis storage engine. + /// + public sealed class RedisEngine : IDisposable + { + private readonly RedisSettings redisSettings; + + private IConnectionMultiplexer connectionMultiplexer; + private IDatabase database; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + + public RedisEngine(RedisSettings redisSettings) => this.redisSettings = redisSettings; + +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + + /// + /// Gets attached of current instance. + /// + public IDatabase Database => database; + + /// + /// Verify if is connected. + /// + public bool IsConnected => connectionMultiplexer != null && connectionMultiplexer.IsConnected; + + /// + /// Dispose asynchronously and close connection. + /// + public async void Dispose() + { + if (!IsConnected) + return; + + await connectionMultiplexer.CloseAsync(); + connectionMultiplexer.Dispose(); + } + + /// + /// Tries to create a new connection asynchronously. + /// + /// + public async void StartAsync() + { + var connectionStr = new StringBuilder(); + connectionStr.Append($"{redisSettings.Host}:{redisSettings.Port}"); + if (!string.IsNullOrWhiteSpace(redisSettings.Password)) + connectionStr.Append($",password={redisSettings.Password}"); + + connectionStr.Append($",syncTimeout={redisSettings.SyncTimeout}"); + connectionStr.Append($",asyncTimeout={redisSettings.AsyncTimeout}"); + + try + { + connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync(connectionStr.ToString()); + database = connectionMultiplexer.GetDatabase(redisSettings.Index); + } + catch (RedisConnectionException e) + { + throw new ConnectionException( + "Redis service cannot initialize. Turn on cluster server to begin database transactions.", + e + ); + } + } + } +} diff --git a/PSTk.Redis/Database/RedisField.cs b/PSTk.Redis/Database/RedisField.cs new file mode 100644 index 0000000..c678b9d --- /dev/null +++ b/PSTk.Redis/Database/RedisField.cs @@ -0,0 +1,40 @@ +namespace PSTk.Redis.Database +{ + /// + /// Base class to iterate with . + /// + /// + public sealed class RedisField + { + private string key; + private RedisObject redisObject; + + private RedisField() + { } + + /// + /// Getter and setter for current . + /// + public T Field + { + get => redisObject.GetValue(key); + set => redisObject.SetValue(key, value); + } + + /// + /// Create a generic version of object for . + /// + /// + /// + /// + public static RedisField Create(RedisObject redisObject, string key) + { + var redisField = new RedisField() + { + redisObject = redisObject, + key = key + }; + return redisField; + } + } +} diff --git a/PSTk.Redis/Database/RedisObject.cs b/PSTk.Redis/Database/RedisObject.cs new file mode 100644 index 0000000..071b1fc --- /dev/null +++ b/PSTk.Redis/Database/RedisObject.cs @@ -0,0 +1,360 @@ +using Newtonsoft.Json; +using StackExchange.Redis; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PSTk.Redis.Database +{ + /// + /// Represents the base class for object manipulation. + /// + public abstract class RedisObject + { + private Dictionary> entries; + private string key; + private List update; + + /// + /// Gets all keys from . + /// + public IEnumerable AllKeys => entries.Keys; + + /// + /// Gets current assigned to the base class. + /// + public IDatabase Database { get; private set; } + + /// + /// Verifies if number of are empty. + /// + public bool IsNull => entries.Count == 0; + + /// + /// Gets the currrent key assigned to this object. + /// + public string Key { get; private set; } + + /// + /// Performs a flush operation asynchronously. Also, enables configuration for + /// execution. + /// + /// + /// + public Task FlushAsync(ITransaction transaction = null) + { + ReadyFlush(); + return transaction == null + ? Database.HashSetAsync(Key, update.ToArray()) + : transaction.HashSetAsync(Key, update.ToArray()); + } + + /// + /// Gets value from . + /// + /// Supported types: , , , + /// , , , , + /// , , , [], + /// [], [], [], and + /// []. + /// + /// + /// + /// + /// + /// + public T GetValue(RedisValue key, T def = default) + { + if (key.IsNullOrEmpty || !entries.TryGetValue(key, out KeyValuePair val) || val.Key == null) + return def; + + if (typeof(T) == typeof(byte)) + try { return (T)(object)byte.Parse(Encoding.UTF8.GetString(val.Key)); } + catch (OverflowException) { return (T)(object)byte.MaxValue; } + + if (typeof(T) == typeof(int)) + try { return (T)(object)int.Parse(Encoding.UTF8.GetString(val.Key)); } + catch (OverflowException) { return (T)(object)int.MaxValue; } + + if (typeof(T) == typeof(uint)) + try { return (T)(object)uint.Parse(Encoding.UTF8.GetString(val.Key)); } + catch (OverflowException) { return (T)(object)uint.MaxValue; } + + if (typeof(T) == typeof(ushort)) + try { return (T)(object)ushort.Parse(Encoding.UTF8.GetString(val.Key)); } + catch (OverflowException) { return (T)(object)ushort.MaxValue; } + + if (typeof(T) == typeof(float)) + try { return (T)(object)float.Parse(Encoding.UTF8.GetString(val.Key)); } + catch (OverflowException) { return (T)(object)float.MaxValue; } + + if (typeof(T) == typeof(long)) + try { return (T)(object)long.Parse(Encoding.UTF8.GetString(val.Key)); } + catch (OverflowException) { return (T)(object)long.MaxValue; } + + if (typeof(T) == typeof(ulong)) + try { return (T)(object)ulong.Parse(Encoding.UTF8.GetString(val.Key)); } + catch (OverflowException) { return (T)(object)ulong.MaxValue; } + + if (typeof(T) == typeof(double)) + try { return (T)(object)double.Parse(Encoding.UTF8.GetString(val.Key)); } + catch (OverflowException) { return (T)(object)double.MaxValue; } + + if (typeof(T) == typeof(bool)) + return (T)(object)(val.Key[0] != 0); + + if (typeof(T) == typeof(DateTime)) + return (T)(object)DateTime.FromBinary(BitConverter.ToInt64(val.Key, 0)); + + if (typeof(T) == typeof(byte[])) + return (T)(object)val.Key; + + if (typeof(T) == typeof(ushort[])) + { + var ret = new ushort[val.Key.Length / 2]; + Buffer.BlockCopy(val.Key, 0, ret, 0, val.Key.Length); + return (T)(object)ret; + } + + if (typeof(T) == typeof(int[]) || typeof(T) == typeof(uint[])) + { + var ret = new int[val.Key.Length / 4]; + Buffer.BlockCopy(val.Key, 0, ret, 0, val.Key.Length); + return (T)(object)ret; + } + + if (typeof(T) == typeof(string)) + return (T)(object)Encoding.UTF8.GetString(val.Key); + + if (typeof(T) == typeof(string[])) + return (T)(object)JsonConvert.SerializeObject(val.Key); + + throw new NotSupportedException(); + } + + /// + /// Performs a reload operation to a specific field from . + /// + /// + public void Reload(string field = null) + { + if (field != null && entries != null) + { + entries[field] = +#if NET472 + new KeyValuePair(Database.HashGet(Key, field), false); +#else + KeyValuePair.Create(Database.HashGet(Key, field), false); +#endif + return; + } + + entries = Database.HashGetAll(Key).ToDictionary( + x => x.Name, +#if NET472 + x => new KeyValuePair(x.Value, false) +#else + x => KeyValuePair.Create(x.Value, false) +#endif + ); + } + + /// + /// Performs a reload operation to a specific filed from asynchornously. + /// Also, enables configuration for execution. + /// + /// + /// + /// + public async Task ReloadAsync(ITransaction trans = null, string field = null) + { + if (field != null && entries != null) + { + var tf = trans != null + ? trans.HashGetAsync(Key, field) + : Database.HashGetAsync(Key, field); + + try + { + await tf; + entries[field] = +#if NET472 + new KeyValuePair(tf.Result, false); +#else + KeyValuePair.Create(tf.Result, false); +#endif + } + catch { } + return; + } + + var t = trans != null ? trans.HashGetAllAsync(Key) : Database.HashGetAllAsync(Key); + + try + { + await t; + entries = t.Result.ToDictionary( + x => x.Name, +#if NET472 + x => new KeyValuePair(x.Value, false) +#else + x => KeyValuePair.Create(x.Value, false) +#endif + ); + } + catch { } + } + + /// + /// Sets value to . + /// + /// Supported types: , , , + /// , , , , + /// , , , [], + /// [], [], [], and + /// []. + /// + /// + /// + /// + /// + public void SetValue(RedisValue key, T val) + { + if (val == null) + return; + + byte[] buff; + + if (typeof(T) == typeof(byte) + || typeof(T) == typeof(int) + || typeof(T) == typeof(uint) + || typeof(T) == typeof(ushort) + || typeof(T) == typeof(string) + || typeof(T) == typeof(float) + || typeof(T) == typeof(long) + || typeof(T) == typeof(ulong) + || typeof(T) == typeof(double)) + buff = Encoding.UTF8.GetBytes(val.ToString()); + else if (typeof(T) == typeof(bool)) + buff = new byte[] { (byte)((bool)(object)val ? 1 : 0) }; + else if (typeof(T) == typeof(DateTime)) + buff = BitConverter.GetBytes(((DateTime)(object)val).ToBinary()); + else if (typeof(T) == typeof(byte[])) + buff = (byte[])(object)val; + else if (typeof(T) == typeof(ushort[])) + { + var v = (ushort[])(object)val; + buff = new byte[v.Length * 2]; + Buffer.BlockCopy(v, 0, buff, 0, buff.Length); + } + else if (typeof(T) == typeof(int[]) || typeof(T) == typeof(uint[])) + { + var v = (int[])(object)val; + buff = new byte[v.Length * 4]; + Buffer.BlockCopy(v, 0, buff, 0, buff.Length); + } + else if (typeof(T) == typeof(string[])) + buff = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(val)); + else + throw new NotSupportedException(); + + if (!entries.ContainsKey(Key) || entries[Key].Key == null || !buff.SequenceEqual(entries[Key].Key)) + entries[key] = +#if NET472 + new KeyValuePair(buff, true); +#else + KeyValuePair.Create(buff, true); +#endif + } + + /// + /// Gets all entries asynchronously. + /// + protected async void GetAllEntriesAsync() + { + var result = await Database.HashGetAllAsync(key); + entries = result.ToDictionary( + x => x.Name, +#if NET472 + x => new KeyValuePair(x.Value, false) +#else + x => KeyValuePair.Create(x.Value, false) +#endif + ); + } + + /// + /// Gets raw value from . + /// + /// + /// + protected byte[] GetValueRaw(RedisValue key) + { + if (!entries.TryGetValue(key, out var val)) + return null; + + if (val.Key == null) + return null; + + return (byte[])val.Key.Clone(); + } + + /// + /// Internally initialize the base class to fetch all from . + /// + /// + /// + /// + protected void Init(IDatabase db, string key, string field = null) + { + Key = key; + Database = db; + + this.key = key; + + if (field == null) + entries = db.HashGetAll(key).ToDictionary( + x => x.Name, +#if NET472 + x => new KeyValuePair(x.Value, false) +#else + x => KeyValuePair.Create(x.Value, false) +#endif + ); + else + { + var entry = new HashEntry[] { new HashEntry(field, db.HashGet(key, field)) }; + entries = entry.ToDictionary( + x => x.Name, +#if NET472 + x => new KeyValuePair(x.Value, false) +#else + x => KeyValuePair.Create(x.Value, false) +#endif + ); + } + } + + private void ReadyFlush() + { + if (update == null) + update = new List(); + + update.Clear(); + + foreach (var name in entries.Keys.ToList()) + if (entries[name].Value) + update.Add(new HashEntry(name, entries[name].Key)); + + foreach (var update in update) + entries[update.Name] = +#if NET472 + new KeyValuePair(entries[update.Name].Key, false); +#else + KeyValuePair.Create(entries[update.Name].Key, false); +#endif + } + } +} diff --git a/PSTk.Redis/Database/RedisSettings.cs b/PSTk.Redis/Database/RedisSettings.cs new file mode 100644 index 0000000..9783bcb --- /dev/null +++ b/PSTk.Redis/Database/RedisSettings.cs @@ -0,0 +1,46 @@ +namespace PSTk.Redis.Database +{ + /// + /// Standard configuration for . + /// + public sealed class RedisSettings + { + /// + /// The host name, default value: + /// localhost + /// + public string Host { get; set; } = "localhost"; + + /// + /// The cluster index, default value: + /// 0 + /// + public sbyte Index { get; set; } = 0; + + /// + /// The password, default value: + /// + /// + public string Password { get; set; } = string.Empty; + + /// + /// The connection port, default value: + /// 6379 + /// + public int Port { get; set; } = 6379; + + /// + /// Time in milliseconds to allow for synchronous operations. + /// Default value: + /// 5000 + /// + public int SyncTimeout { get; set; } = 5000; + + /// + /// Time in milliseconds to allow for asynchronous operations. + /// Default value: + /// 5000 + /// + public int AsyncTimeout { get; set; } = 5000; + } +} diff --git a/PSTk.Redis/Exceptions/ConnectionException.cs b/PSTk.Redis/Exceptions/ConnectionException.cs new file mode 100644 index 0000000..aa61af4 --- /dev/null +++ b/PSTk.Redis/Exceptions/ConnectionException.cs @@ -0,0 +1,18 @@ +using System; + +namespace PSTk.Redis.Exceptions +{ + /// + /// Represents errors that occur during connection attempt to a Redis server. + /// + public sealed class ConnectionException : Exception + { +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + + public ConnectionException(string message, Exception innerException = null) + +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + : base(message, innerException) + { } + } +} diff --git a/PSTk.Redis/GlobalSuppressions.cs b/PSTk.Redis/GlobalSuppressions.cs new file mode 100644 index 0000000..57c3c8e --- /dev/null +++ b/PSTk.Redis/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Style", "IDE0021:Use block body for constructors", Justification = "", Scope = "member", Target = "~M:PSTk.Redis.Database.RedisEngine.#ctor(PSTk.Redis.Database.RedisSettings)")] diff --git a/PSTk.Redis/PSTk.Redis.csproj b/PSTk.Redis/PSTk.Redis.csproj index 49ea96b..582ea4c 100644 --- a/PSTk.Redis/PSTk.Redis.csproj +++ b/PSTk.Redis/PSTk.Redis.csproj @@ -44,4 +44,9 @@ + + + + +