From 5b2588b47f684c48345574dd0ce7d8bc925ff34d Mon Sep 17 00:00:00 2001 From: Guilherme Werner Date: Mon, 2 Jun 2025 08:58:34 -0300 Subject: [PATCH] Add shared packages --- Directory.Packages.props | 9 + Tribufu.sln | 84 ++++++++ scripts/package.ps1 | 5 + scripts/package.sh | 3 - .../EnumMemberConverter.cs | 30 +++ src/Tribufu.ComponentModel/README.md | 1 + .../Tribufu.ComponentModel.csproj | 16 ++ .../ConfigurationManager.cs | 53 +++++ src/Tribufu.Configuration/README.md | 1 + .../Tribufu.Configuration.csproj | 30 +++ src/Tribufu.Database/DatabaseConfiguration.cs | 55 ++++++ src/Tribufu.Database/DatabaseConstants.cs | 12 ++ src/Tribufu.Database/DatabaseDriver.cs | 22 +++ src/Tribufu.Database/README.md | 1 + .../Repositories/IRepository.cs | 39 ++++ .../Repositories/Repository.cs | 113 +++++++++++ src/Tribufu.Database/Tribufu.Database.csproj | 25 +++ src/Tribufu.Example/Program.cs | 11 +- src/Tribufu.Example/Tribufu.Example.csproj | 1 + src/Tribufu.Logging/LogLevel.cs | 22 +++ src/Tribufu.Logging/Logger.cs | 59 ++++++ src/Tribufu.Logging/README.md | 1 + src/Tribufu.Logging/Tribufu.Logging.csproj | 18 ++ src/Tribufu.Runtime/ApplicationContext.cs | 183 ++++++++++++++++++ src/Tribufu.Runtime/README.md | 1 + src/Tribufu.Runtime/Tribufu.Runtime.csproj | 19 ++ .../DecimalNullableStringConverter.cs | 46 +++++ .../DecimalStringConverter.cs | 32 +++ src/Tribufu.Serialization/README.md | 1 + .../Tribufu.Serialization.csproj | 19 ++ .../ULongNullableStringConverter.cs | 45 +++++ .../ULongStringConverter.cs | 31 +++ 32 files changed, 981 insertions(+), 7 deletions(-) create mode 100644 scripts/package.ps1 delete mode 100644 scripts/package.sh create mode 100644 src/Tribufu.ComponentModel/EnumMemberConverter.cs create mode 100644 src/Tribufu.ComponentModel/README.md create mode 100644 src/Tribufu.ComponentModel/Tribufu.ComponentModel.csproj create mode 100644 src/Tribufu.Configuration/ConfigurationManager.cs create mode 100644 src/Tribufu.Configuration/README.md create mode 100644 src/Tribufu.Configuration/Tribufu.Configuration.csproj create mode 100644 src/Tribufu.Database/DatabaseConfiguration.cs create mode 100644 src/Tribufu.Database/DatabaseConstants.cs create mode 100644 src/Tribufu.Database/DatabaseDriver.cs create mode 100644 src/Tribufu.Database/README.md create mode 100644 src/Tribufu.Database/Repositories/IRepository.cs create mode 100644 src/Tribufu.Database/Repositories/Repository.cs create mode 100644 src/Tribufu.Database/Tribufu.Database.csproj create mode 100644 src/Tribufu.Logging/LogLevel.cs create mode 100644 src/Tribufu.Logging/Logger.cs create mode 100644 src/Tribufu.Logging/README.md create mode 100644 src/Tribufu.Logging/Tribufu.Logging.csproj create mode 100644 src/Tribufu.Runtime/ApplicationContext.cs create mode 100644 src/Tribufu.Runtime/README.md create mode 100644 src/Tribufu.Runtime/Tribufu.Runtime.csproj create mode 100644 src/Tribufu.Serialization/DecimalNullableStringConverter.cs create mode 100644 src/Tribufu.Serialization/DecimalStringConverter.cs create mode 100644 src/Tribufu.Serialization/README.md create mode 100644 src/Tribufu.Serialization/Tribufu.Serialization.csproj create mode 100644 src/Tribufu.Serialization/ULongNullableStringConverter.cs create mode 100644 src/Tribufu.Serialization/ULongStringConverter.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index e95a987..94e2d6a 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,9 +5,18 @@ + + + + + + + + + diff --git a/Tribufu.sln b/Tribufu.sln index b3ff43a..fd461d5 100644 --- a/Tribufu.sln +++ b/Tribufu.sln @@ -7,6 +7,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tribufu.Generated", "src\Tr EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tribufu.Example", "src\Tribufu.Example\Tribufu.Example.csproj", "{D6392A29-E2DC-4050-B4C1-B279DD2D226D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tribufu.Logging", "src\Tribufu.Logging\Tribufu.Logging.csproj", "{CFD80847-9B98-4991-BADF-8714E7D8D81C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tribufu.Configuration", "src\Tribufu.Configuration\Tribufu.Configuration.csproj", "{C0A841C8-9FC5-4AC0-B9AD-6BBFCEDCBE5F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tribufu.Runtime", "src\Tribufu.Runtime\Tribufu.Runtime.csproj", "{26EEB407-733C-4383-9211-B083CD5F593B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tribufu.Database", "src\Tribufu.Database\Tribufu.Database.csproj", "{E7F9A76F-C087-410B-B4B5-A928A6CDC2BA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tribufu.Serialization", "src\Tribufu.Serialization\Tribufu.Serialization.csproj", "{D6DAE078-2F80-49DD-97A3-B1223FE04F91}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tribufu.ComponentModel", "src\Tribufu.ComponentModel\Tribufu.ComponentModel.csproj", "{7CB04FFD-8F4B-4B40-BB4B-2BAA19D783E1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -53,6 +65,78 @@ Global {D6392A29-E2DC-4050-B4C1-B279DD2D226D}.Release|x64.Build.0 = Release|Any CPU {D6392A29-E2DC-4050-B4C1-B279DD2D226D}.Release|x86.ActiveCfg = Release|Any CPU {D6392A29-E2DC-4050-B4C1-B279DD2D226D}.Release|x86.Build.0 = Release|Any CPU + {CFD80847-9B98-4991-BADF-8714E7D8D81C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CFD80847-9B98-4991-BADF-8714E7D8D81C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CFD80847-9B98-4991-BADF-8714E7D8D81C}.Debug|x64.ActiveCfg = Debug|Any CPU + {CFD80847-9B98-4991-BADF-8714E7D8D81C}.Debug|x64.Build.0 = Debug|Any CPU + {CFD80847-9B98-4991-BADF-8714E7D8D81C}.Debug|x86.ActiveCfg = Debug|Any CPU + {CFD80847-9B98-4991-BADF-8714E7D8D81C}.Debug|x86.Build.0 = Debug|Any CPU + {CFD80847-9B98-4991-BADF-8714E7D8D81C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CFD80847-9B98-4991-BADF-8714E7D8D81C}.Release|Any CPU.Build.0 = Release|Any CPU + {CFD80847-9B98-4991-BADF-8714E7D8D81C}.Release|x64.ActiveCfg = Release|Any CPU + {CFD80847-9B98-4991-BADF-8714E7D8D81C}.Release|x64.Build.0 = Release|Any CPU + {CFD80847-9B98-4991-BADF-8714E7D8D81C}.Release|x86.ActiveCfg = Release|Any CPU + {CFD80847-9B98-4991-BADF-8714E7D8D81C}.Release|x86.Build.0 = Release|Any CPU + {C0A841C8-9FC5-4AC0-B9AD-6BBFCEDCBE5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C0A841C8-9FC5-4AC0-B9AD-6BBFCEDCBE5F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C0A841C8-9FC5-4AC0-B9AD-6BBFCEDCBE5F}.Debug|x64.ActiveCfg = Debug|Any CPU + {C0A841C8-9FC5-4AC0-B9AD-6BBFCEDCBE5F}.Debug|x64.Build.0 = Debug|Any CPU + {C0A841C8-9FC5-4AC0-B9AD-6BBFCEDCBE5F}.Debug|x86.ActiveCfg = Debug|Any CPU + {C0A841C8-9FC5-4AC0-B9AD-6BBFCEDCBE5F}.Debug|x86.Build.0 = Debug|Any CPU + {C0A841C8-9FC5-4AC0-B9AD-6BBFCEDCBE5F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C0A841C8-9FC5-4AC0-B9AD-6BBFCEDCBE5F}.Release|Any CPU.Build.0 = Release|Any CPU + {C0A841C8-9FC5-4AC0-B9AD-6BBFCEDCBE5F}.Release|x64.ActiveCfg = Release|Any CPU + {C0A841C8-9FC5-4AC0-B9AD-6BBFCEDCBE5F}.Release|x64.Build.0 = Release|Any CPU + {C0A841C8-9FC5-4AC0-B9AD-6BBFCEDCBE5F}.Release|x86.ActiveCfg = Release|Any CPU + {C0A841C8-9FC5-4AC0-B9AD-6BBFCEDCBE5F}.Release|x86.Build.0 = Release|Any CPU + {26EEB407-733C-4383-9211-B083CD5F593B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {26EEB407-733C-4383-9211-B083CD5F593B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {26EEB407-733C-4383-9211-B083CD5F593B}.Debug|x64.ActiveCfg = Debug|Any CPU + {26EEB407-733C-4383-9211-B083CD5F593B}.Debug|x64.Build.0 = Debug|Any CPU + {26EEB407-733C-4383-9211-B083CD5F593B}.Debug|x86.ActiveCfg = Debug|Any CPU + {26EEB407-733C-4383-9211-B083CD5F593B}.Debug|x86.Build.0 = Debug|Any CPU + {26EEB407-733C-4383-9211-B083CD5F593B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {26EEB407-733C-4383-9211-B083CD5F593B}.Release|Any CPU.Build.0 = Release|Any CPU + {26EEB407-733C-4383-9211-B083CD5F593B}.Release|x64.ActiveCfg = Release|Any CPU + {26EEB407-733C-4383-9211-B083CD5F593B}.Release|x64.Build.0 = Release|Any CPU + {26EEB407-733C-4383-9211-B083CD5F593B}.Release|x86.ActiveCfg = Release|Any CPU + {26EEB407-733C-4383-9211-B083CD5F593B}.Release|x86.Build.0 = Release|Any CPU + {E7F9A76F-C087-410B-B4B5-A928A6CDC2BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7F9A76F-C087-410B-B4B5-A928A6CDC2BA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7F9A76F-C087-410B-B4B5-A928A6CDC2BA}.Debug|x64.ActiveCfg = Debug|Any CPU + {E7F9A76F-C087-410B-B4B5-A928A6CDC2BA}.Debug|x64.Build.0 = Debug|Any CPU + {E7F9A76F-C087-410B-B4B5-A928A6CDC2BA}.Debug|x86.ActiveCfg = Debug|Any CPU + {E7F9A76F-C087-410B-B4B5-A928A6CDC2BA}.Debug|x86.Build.0 = Debug|Any CPU + {E7F9A76F-C087-410B-B4B5-A928A6CDC2BA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E7F9A76F-C087-410B-B4B5-A928A6CDC2BA}.Release|Any CPU.Build.0 = Release|Any CPU + {E7F9A76F-C087-410B-B4B5-A928A6CDC2BA}.Release|x64.ActiveCfg = Release|Any CPU + {E7F9A76F-C087-410B-B4B5-A928A6CDC2BA}.Release|x64.Build.0 = Release|Any CPU + {E7F9A76F-C087-410B-B4B5-A928A6CDC2BA}.Release|x86.ActiveCfg = Release|Any CPU + {E7F9A76F-C087-410B-B4B5-A928A6CDC2BA}.Release|x86.Build.0 = Release|Any CPU + {D6DAE078-2F80-49DD-97A3-B1223FE04F91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6DAE078-2F80-49DD-97A3-B1223FE04F91}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6DAE078-2F80-49DD-97A3-B1223FE04F91}.Debug|x64.ActiveCfg = Debug|Any CPU + {D6DAE078-2F80-49DD-97A3-B1223FE04F91}.Debug|x64.Build.0 = Debug|Any CPU + {D6DAE078-2F80-49DD-97A3-B1223FE04F91}.Debug|x86.ActiveCfg = Debug|Any CPU + {D6DAE078-2F80-49DD-97A3-B1223FE04F91}.Debug|x86.Build.0 = Debug|Any CPU + {D6DAE078-2F80-49DD-97A3-B1223FE04F91}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6DAE078-2F80-49DD-97A3-B1223FE04F91}.Release|Any CPU.Build.0 = Release|Any CPU + {D6DAE078-2F80-49DD-97A3-B1223FE04F91}.Release|x64.ActiveCfg = Release|Any CPU + {D6DAE078-2F80-49DD-97A3-B1223FE04F91}.Release|x64.Build.0 = Release|Any CPU + {D6DAE078-2F80-49DD-97A3-B1223FE04F91}.Release|x86.ActiveCfg = Release|Any CPU + {D6DAE078-2F80-49DD-97A3-B1223FE04F91}.Release|x86.Build.0 = Release|Any CPU + {7CB04FFD-8F4B-4B40-BB4B-2BAA19D783E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7CB04FFD-8F4B-4B40-BB4B-2BAA19D783E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7CB04FFD-8F4B-4B40-BB4B-2BAA19D783E1}.Debug|x64.ActiveCfg = Debug|Any CPU + {7CB04FFD-8F4B-4B40-BB4B-2BAA19D783E1}.Debug|x64.Build.0 = Debug|Any CPU + {7CB04FFD-8F4B-4B40-BB4B-2BAA19D783E1}.Debug|x86.ActiveCfg = Debug|Any CPU + {7CB04FFD-8F4B-4B40-BB4B-2BAA19D783E1}.Debug|x86.Build.0 = Debug|Any CPU + {7CB04FFD-8F4B-4B40-BB4B-2BAA19D783E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7CB04FFD-8F4B-4B40-BB4B-2BAA19D783E1}.Release|Any CPU.Build.0 = Release|Any CPU + {7CB04FFD-8F4B-4B40-BB4B-2BAA19D783E1}.Release|x64.ActiveCfg = Release|Any CPU + {7CB04FFD-8F4B-4B40-BB4B-2BAA19D783E1}.Release|x64.Build.0 = Release|Any CPU + {7CB04FFD-8F4B-4B40-BB4B-2BAA19D783E1}.Release|x86.ActiveCfg = Release|Any CPU + {7CB04FFD-8F4B-4B40-BB4B-2BAA19D783E1}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/scripts/package.ps1 b/scripts/package.ps1 new file mode 100644 index 0000000..7408aae --- /dev/null +++ b/scripts/package.ps1 @@ -0,0 +1,5 @@ +#!/usr/bin/env sh + +dotnet clean +dotnet build -c Release +dotnet pack diff --git a/scripts/package.sh b/scripts/package.sh deleted file mode 100644 index 58f8eb2..0000000 --- a/scripts/package.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env sh - -dotnet pack diff --git a/src/Tribufu.ComponentModel/EnumMemberConverter.cs b/src/Tribufu.ComponentModel/EnumMemberConverter.cs new file mode 100644 index 0000000..38d62e3 --- /dev/null +++ b/src/Tribufu.ComponentModel/EnumMemberConverter.cs @@ -0,0 +1,30 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +using System; +using System.ComponentModel; +using System.Globalization; +using System.Runtime.Serialization; + +namespace Tribufu.ComponentModel +{ + public class EnumMemberConverter : EnumConverter + { + public EnumMemberConverter(Type type) : base(type) { } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + var type = typeof(T); + + foreach (var field in type.GetFields()) + { + if (Attribute.GetCustomAttribute(field, typeof(EnumMemberAttribute)) is EnumMemberAttribute attribute && value is string enumValue && attribute.Value == enumValue) + { + return field.GetValue(null); + } + } + + return base.ConvertFrom(context, culture, value); + } + } +} diff --git a/src/Tribufu.ComponentModel/README.md b/src/Tribufu.ComponentModel/README.md new file mode 100644 index 0000000..54c1ab5 --- /dev/null +++ b/src/Tribufu.ComponentModel/README.md @@ -0,0 +1 @@ +# Tribufu diff --git a/src/Tribufu.ComponentModel/Tribufu.ComponentModel.csproj b/src/Tribufu.ComponentModel/Tribufu.ComponentModel.csproj new file mode 100644 index 0000000..4bcae0c --- /dev/null +++ b/src/Tribufu.ComponentModel/Tribufu.ComponentModel.csproj @@ -0,0 +1,16 @@ + + + Tribufu.ComponentModel + Tribufu ComponentModel Extensions + README.md + + + Properties + true + Library + netstandard2.0;net45;net5.0 + + + + + diff --git a/src/Tribufu.Configuration/ConfigurationManager.cs b/src/Tribufu.Configuration/ConfigurationManager.cs new file mode 100644 index 0000000..009b6e7 --- /dev/null +++ b/src/Tribufu.Configuration/ConfigurationManager.cs @@ -0,0 +1,53 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +using Microsoft.Extensions.Configuration; +using System.IO; +using Tomlyn.Extensions.Configuration; +using Tribufu.Logging; +using Tribufu.Runtime; + +namespace Tribufu.Configuration +{ + public static class ConfigurationManager + { + public static IConfiguration Configuration { get; private set; } + + public static IConfiguration Load(string[] fileNames) + { + var configDirectory = ApplicationContext.GetConfigDirectory(); + var configurationBuilder = new ConfigurationBuilder(); + configurationBuilder.AddEnvironmentVariables(); + + foreach (var fileName in fileNames) + { + var fullPath = Path.Combine(configDirectory, fileName); + if (!File.Exists(fullPath)) + { + Logger.Debug($"Config file '{fullPath}' not found, skipping."); + continue; + } + + var ext = Path.GetExtension(fullPath).ToLowerInvariant(); + switch (ext) + { + case ".ini": + configurationBuilder.AddIniFile(fullPath, true, false); + break; + case ".json": + configurationBuilder.AddJsonFile(fullPath, true, false); + break; + case ".toml": + configurationBuilder.AddTomlFile(fullPath, true, false); + break; + default: + Logger.Warn($"Unsupported config file extension: {ext}"); + break; + } + } + + Configuration = configurationBuilder.Build(); + return Configuration; + } + } +} diff --git a/src/Tribufu.Configuration/README.md b/src/Tribufu.Configuration/README.md new file mode 100644 index 0000000..54c1ab5 --- /dev/null +++ b/src/Tribufu.Configuration/README.md @@ -0,0 +1 @@ +# Tribufu diff --git a/src/Tribufu.Configuration/Tribufu.Configuration.csproj b/src/Tribufu.Configuration/Tribufu.Configuration.csproj new file mode 100644 index 0000000..475a02c --- /dev/null +++ b/src/Tribufu.Configuration/Tribufu.Configuration.csproj @@ -0,0 +1,30 @@ + + + Tribufu.Configuration + Tribufu Configuration Extensions + README.md + + + Properties + true + Library + netstandard2.0;net6.0 + + + + + + + + + + + + + + + + + + + diff --git a/src/Tribufu.Database/DatabaseConfiguration.cs b/src/Tribufu.Database/DatabaseConfiguration.cs new file mode 100644 index 0000000..915f1d2 --- /dev/null +++ b/src/Tribufu.Database/DatabaseConfiguration.cs @@ -0,0 +1,55 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +using Microsoft.Extensions.Configuration; +using System; + +namespace Tribufu.Database +{ + public class DatabaseConfiguration + { + public DatabaseDriver Driver { get; set; } + + public string? Version { get; set; } + + public string? Host { get; set; } + + public string? Port { get; set; } + + public string? User { get; set; } + + public string? Password { get; set; } + + public string? Schema { get; set; } + + /// + /// Loads the from the "database" section or from root-level keys prefixed with "database_". + /// + /// The configuration source. + /// The populated instance. + public static DatabaseConfiguration Load(IConfiguration configuration) + { + var section = configuration.GetSection("database"); + var useRootFallback = !section.Exists(); + + string? GetConfig(string key) => useRootFallback ? configuration[$"database_{key}"] : section[key]; + + var driverString = GetConfig("driver") ?? throw new Exception("Missing database driver"); + if (!Enum.TryParse(driverString, true, out var driver)) + { + throw new Exception($"Unsupported database driver: {driverString}"); + } + + return new DatabaseConfiguration + { + Driver = driver, + Version = GetConfig("version"), + Host = GetConfig("host"), + Port = GetConfig("port"), + User = GetConfig("user"), + Password = GetConfig("password"), + Schema = GetConfig("schema") + }; + } + } +} diff --git a/src/Tribufu.Database/DatabaseConstants.cs b/src/Tribufu.Database/DatabaseConstants.cs new file mode 100644 index 0000000..bfff4b2 --- /dev/null +++ b/src/Tribufu.Database/DatabaseConstants.cs @@ -0,0 +1,12 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +namespace Tribufu.Database +{ + public static class DatabaseConstants + { + public const uint DEFAULT_PAGINATION = 20; + + public const uint MAX_PAGINATION = 100; + } +} diff --git a/src/Tribufu.Database/DatabaseDriver.cs b/src/Tribufu.Database/DatabaseDriver.cs new file mode 100644 index 0000000..8c3f8f3 --- /dev/null +++ b/src/Tribufu.Database/DatabaseDriver.cs @@ -0,0 +1,22 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +namespace Tribufu.Database +{ + public enum DatabaseDriver : byte + { + MySql = 0, + + Postgres = 1, + + SqlServer = 2, + + Oracle = 3, + + Firebird = 4, + + Sqlite = 5, + + MongoDb = 6, + } +} diff --git a/src/Tribufu.Database/README.md b/src/Tribufu.Database/README.md new file mode 100644 index 0000000..54c1ab5 --- /dev/null +++ b/src/Tribufu.Database/README.md @@ -0,0 +1 @@ +# Tribufu diff --git a/src/Tribufu.Database/Repositories/IRepository.cs b/src/Tribufu.Database/Repositories/IRepository.cs new file mode 100644 index 0000000..97f2750 --- /dev/null +++ b/src/Tribufu.Database/Repositories/IRepository.cs @@ -0,0 +1,39 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Tribufu.Database.Repositories +{ + public interface IRepository where T : class + { + IList GetAll(); + + Task> GetAllAsync(); + + IList GetPage(uint page, uint limit); + + Task> GetPageAsync(uint page, uint limit); + + T? GetOne(K key); + + Task GetOneAsync(K key); + + T? Create(T entity); + + Task CreateAsync(T entity); + + T? Update(T entity); + + Task UpdateAsync(T entity); + + void Delete(K key); + + Task DeleteAsync(K key); + + void Delete(T entity); + + Task DeleteAsync(T entity); + } +} diff --git a/src/Tribufu.Database/Repositories/Repository.cs b/src/Tribufu.Database/Repositories/Repository.cs new file mode 100644 index 0000000..a929382 --- /dev/null +++ b/src/Tribufu.Database/Repositories/Repository.cs @@ -0,0 +1,113 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Tribufu.Database.Repositories +{ + public class Repository : IRepository where C : DbContext where T : class + { + protected readonly C _context; + + protected readonly DbSet _dbSet; + + public Repository(C context) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + _dbSet = context.Set(); + } + + public virtual IList GetAll() + { + return [.. _dbSet]; + } + + public virtual async Task> GetAllAsync() + { + return await _dbSet.ToListAsync(); + } + + public virtual IList GetPage(uint page, uint limit) + { + return _dbSet.Skip((int)((page < 1 ? 0 : page - 1) * limit)).Take((int)limit).ToList(); + } + + public virtual async Task> GetPageAsync(uint page, uint limit) + { + return await _dbSet.Skip((int)((page < 1 ? 0 : page - 1) * limit)).Take((int)limit).ToListAsync(); + } + + public virtual T? GetOne(K key) + { + return _dbSet.Find(key); + } + + public virtual async Task GetOneAsync(K key) + { + return await _dbSet.FindAsync(key); + } + + public virtual T? Create(T entity) + { + _dbSet.Add(entity); + + var result = _context.SaveChanges(); + return result > 0 ? entity : null; + } + + public virtual async Task CreateAsync(T entity) + { + await _dbSet.AddAsync(entity); + var result = await _context.SaveChangesAsync(); + return result > 0 ? entity : null; + } + + public virtual T? Update(T entity) + { + _dbSet.Update(entity); + var result = _context.SaveChanges(); + return result > 0 ? entity : null; + } + + public virtual async Task UpdateAsync(T entity) + { + _dbSet.Update(entity); + var result = await _context.SaveChangesAsync(); + return result > 0 ? entity : null; + } + + public virtual void Delete(K key) + { + var entity = _dbSet.Find(key); + if (entity != null) + { + Delete(entity); + } + } + + public virtual async Task DeleteAsync(K key) + { + var entity = await _dbSet.FindAsync(key); + if (entity != null) + { + await DeleteAsync(entity); + } + } + + public virtual void Delete(T entity) + { + _dbSet.Remove(entity); + _context.SaveChanges(); + } + + public virtual async Task DeleteAsync(T entity) + { + _dbSet.Remove(entity); + await _context.SaveChangesAsync(); + } + } +} diff --git a/src/Tribufu.Database/Tribufu.Database.csproj b/src/Tribufu.Database/Tribufu.Database.csproj new file mode 100644 index 0000000..dd69953 --- /dev/null +++ b/src/Tribufu.Database/Tribufu.Database.csproj @@ -0,0 +1,25 @@ + + + Tribufu.Database + Tribufu Database Extensions + README.md + + + Properties + true + enable + Library + net8.0 + + + + + + + + + + + + + diff --git a/src/Tribufu.Example/Program.cs b/src/Tribufu.Example/Program.cs index 5462790..c6f9e1d 100644 --- a/src/Tribufu.Example/Program.cs +++ b/src/Tribufu.Example/Program.cs @@ -1,8 +1,9 @@ // Copyright (c) Tribufu. All Rights Reserved. -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT using dotenv.net; using Tribufu.Generated.Client; +using Tribufu.Logging; namespace Tribufu.Test { @@ -10,21 +11,23 @@ namespace Tribufu.Test { public static async Task Main(string[] args) { + Logger.Initialize(LogLevel.All); + DotEnv.Load(new DotEnvOptions(ignoreExceptions: true, envFilePaths: [".env", "../../.env"])); var apiKey = Environment.GetEnvironmentVariable("TRIBUFU_API_KEY"); var tribufu = new TribufuApi(apiKey ?? ""); - Console.WriteLine(TribufuApi.GetVersion()); + Logger.Debug(TribufuApi.GetVersion()); try { var result = await tribufu.GetUserInfoAsync(); - Console.WriteLine(result); + Logger.Debug(result.ToString()); } catch (ApiException e) { - Console.WriteLine(e.Message); + Logger.Debug(e.Message); } } } diff --git a/src/Tribufu.Example/Tribufu.Example.csproj b/src/Tribufu.Example/Tribufu.Example.csproj index a6fbc73..c5cbd10 100644 --- a/src/Tribufu.Example/Tribufu.Example.csproj +++ b/src/Tribufu.Example/Tribufu.Example.csproj @@ -9,6 +9,7 @@ + diff --git a/src/Tribufu.Logging/LogLevel.cs b/src/Tribufu.Logging/LogLevel.cs new file mode 100644 index 0000000..f13e62c --- /dev/null +++ b/src/Tribufu.Logging/LogLevel.cs @@ -0,0 +1,22 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +namespace Tribufu.Logging +{ + public enum LogLevel : byte + { + Off = 0, + + Trace = 1, + + Debug = 2, + + Info = 3, + + Warn = 4, + + Error = 5, + + All = 6, + } +} diff --git a/src/Tribufu.Logging/Logger.cs b/src/Tribufu.Logging/Logger.cs new file mode 100644 index 0000000..38e01f6 --- /dev/null +++ b/src/Tribufu.Logging/Logger.cs @@ -0,0 +1,59 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +using System; + +namespace Tribufu.Logging +{ + public static class Logger + { + private static LogLevel _level = LogLevel.Off; + + public static void Initialize(LogLevel level = LogLevel.Off) + { + _level = level; + } + + public static void Info(string message) + { + Log(LogLevel.Info, message, ConsoleColor.Green); + } + + public static void Warn(string message) + { + Log(LogLevel.Warn, message, ConsoleColor.Yellow); + } + + public static void Error(string message) + { + Log(LogLevel.Error, message, ConsoleColor.Red); + } + + public static void Debug(string message) + { + Log(LogLevel.Debug, message, ConsoleColor.White); + } + + public static void Trace(string message) + { + Log(LogLevel.Trace, message, ConsoleColor.Gray); + } + + private static void Log(LogLevel level, string message, ConsoleColor color) + { + if (_level == LogLevel.Off) + { + return; + } + + if (_level == LogLevel.All || level >= _level) + { + var defaultColor = Console.ForegroundColor; + Console.ForegroundColor = color; + var timestamp = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss"); + Console.WriteLine($"[{timestamp}] [{level.ToString().ToUpper()}]: {message}"); + Console.ForegroundColor = defaultColor; + } + } + } +} diff --git a/src/Tribufu.Logging/README.md b/src/Tribufu.Logging/README.md new file mode 100644 index 0000000..54c1ab5 --- /dev/null +++ b/src/Tribufu.Logging/README.md @@ -0,0 +1 @@ +# Tribufu diff --git a/src/Tribufu.Logging/Tribufu.Logging.csproj b/src/Tribufu.Logging/Tribufu.Logging.csproj new file mode 100644 index 0000000..516c7f9 --- /dev/null +++ b/src/Tribufu.Logging/Tribufu.Logging.csproj @@ -0,0 +1,18 @@ + + + Tribufu.Logging + Tribufu Logging Extensions + README.md + + + Properties + true + Library + netstandard2.0;net45;net5.0 + + + + + + + diff --git a/src/Tribufu.Runtime/ApplicationContext.cs b/src/Tribufu.Runtime/ApplicationContext.cs new file mode 100644 index 0000000..ef26266 --- /dev/null +++ b/src/Tribufu.Runtime/ApplicationContext.cs @@ -0,0 +1,183 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +using System; +using System.IO; +using System.Runtime.InteropServices; +using Tribufu.Logging; + +namespace Tribufu.Runtime +{ + /// + /// Provides standardized access to important application directories, such as config, saved data, logs, and platform-specific binaries. + /// This is especially useful for abstracting file path logic across environments (development, production, etc). + /// + public static class ApplicationContext + { + /// + /// Gets the root base directory of the application. + /// + /// + /// - In development, this resolves to the root of the repository (five levels above bin/Debug or bin/Release). + /// - In production, it resolves to two levels above the binary location. + /// - It uses case-insensitive checks and runtime heuristics to improve accuracy. + /// + /// The absolute path to the base directory. + public static string GetBaseDirectory() + { + try + { + string baseDirectory; + string defaultBaseDirectory = AppContext.BaseDirectory; + + bool isDevelopment = defaultBaseDirectory.ToLowerInvariant().Contains("debug"); + + if (isDevelopment) + { + // Go 5 levels up to simulate project root + baseDirectory = Path.Combine(defaultBaseDirectory, "..", "..", "..", "..", ".."); + } + else + { + baseDirectory = Path.Combine(defaultBaseDirectory, "..", ".."); + } + + return Path.GetFullPath(baseDirectory); + } + catch (Exception ex) + { + Logger.Warn($"(ApplicationContext) Failed to resolve base directory: {ex.Message}"); + return AppContext.BaseDirectory; + } + } + + /// + /// Gets the path to the platform-specific binary directory. + /// + /// + /// The absolute path to bin/<runtime-identifier> if available, + /// otherwise falls back to bin/dotnet. + /// + public static string GetBinDirectory() + { + var binDirectory = Path.Combine(GetBaseDirectory(), "bin"); + +#if NETSTANDARD + var runtimeIdentifier = GetRuntimeIdentifierLegacy(); + + if (!string.IsNullOrEmpty(runtimeIdentifier)) + { + binDirectory = Path.Combine(binDirectory, runtimeIdentifier); + } + else + { + binDirectory = Path.Combine(binDirectory, "dotnet"); + } +#else + if (!string.IsNullOrEmpty(RuntimeInformation.RuntimeIdentifier)) + { + binDirectory = Path.Combine(binDirectory, RuntimeInformation.RuntimeIdentifier); + } + else + { + binDirectory = Path.Combine(binDirectory, "dotnet"); + } +#endif + + return binDirectory; + } + + private static string GetRuntimeIdentifierLegacy() + { + string osPart; + PlatformID platform = Environment.OSVersion.Platform; + + switch (platform) + { + case PlatformID.Win32NT: + osPart = "win"; + break; + case PlatformID.Unix: + if (IsMacOS()) + osPart = "osx"; + else + osPart = "linux"; + break; + case PlatformID.MacOSX: + osPart = "osx"; + break; + default: + osPart = "unknown"; + break; + } + + var archPart = Environment.Is64BitProcess ? "x64" : "x86"; + if (osPart == "unknown") + { + return null; + } + + return $"{osPart}-{archPart}"; + } + + private static bool IsMacOS() + { + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + Version version = Environment.OSVersion.Version; + + if (version.Major >= 19) + { + return true; + } + } + + return false; + } + + /// + /// Gets the path to the configuration directory. + /// + /// The absolute path to the config directory. + public static string GetConfigDirectory() + { + return Path.Combine(GetBaseDirectory(), "config"); + } + + /// + /// Gets the path to the assets directory. + /// + /// The absolute path to the assets directory. + public static string GetAssetsDirectory() + { + return Path.Combine(GetBaseDirectory(), "assets"); + } + + /// + /// Gets the path to the saved data directory. + /// + /// The absolute path to the saved directory. + public static string GetSavedDirectory() + { + return Path.Combine(GetBaseDirectory(), "saved"); + } + + /// + /// Gets the path to the cache directory inside saved. + /// + /// The absolute path to the saved/cache directory. + public static string GetCacheDirectory() + { + return Path.Combine(GetSavedDirectory(), "cache"); + } + + /// + /// Gets the path to the logs directory inside saved. + /// + /// The absolute path to the saved/logs directory. + public static string GetLogsDirectory() + { + return Path.Combine(GetSavedDirectory(), "logs"); + } + } +} diff --git a/src/Tribufu.Runtime/README.md b/src/Tribufu.Runtime/README.md new file mode 100644 index 0000000..54c1ab5 --- /dev/null +++ b/src/Tribufu.Runtime/README.md @@ -0,0 +1 @@ +# Tribufu diff --git a/src/Tribufu.Runtime/Tribufu.Runtime.csproj b/src/Tribufu.Runtime/Tribufu.Runtime.csproj new file mode 100644 index 0000000..0d16370 --- /dev/null +++ b/src/Tribufu.Runtime/Tribufu.Runtime.csproj @@ -0,0 +1,19 @@ + + + Tribufu.Runtime + Tribufu Runtime Extensions + README.md + + + Properties + true + Library + netstandard2.0;net5.0 + + + + + + + + diff --git a/src/Tribufu.Serialization/DecimalNullableStringConverter.cs b/src/Tribufu.Serialization/DecimalNullableStringConverter.cs new file mode 100644 index 0000000..fee4870 --- /dev/null +++ b/src/Tribufu.Serialization/DecimalNullableStringConverter.cs @@ -0,0 +1,46 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +using Newtonsoft.Json; +using System; +using System.Globalization; + +namespace Tribufu.Serialization +{ + public class DecimalNullableStringConverter : JsonConverter + { + public override decimal? ReadJson(JsonReader reader, Type objectType, decimal? existingValue, bool hasExistingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + { + return null; + } + + if (reader.TokenType == JsonToken.String || reader.TokenType == JsonToken.Integer) + { + string value = reader.Value?.ToString(); + + if (string.IsNullOrWhiteSpace(value)) + { + return null; + } + + return decimal.Parse(value); + } + + throw new JsonSerializationException($"Unexpected token {reader.TokenType} when parsing decimal?."); + } + + public override void WriteJson(JsonWriter writer, decimal? value, JsonSerializer serializer) + { + if (value.HasValue) + { + writer.WriteValue(value.Value.ToString(CultureInfo.InvariantCulture)); + } + else + { + writer.WriteNull(); + } + } + } +} diff --git a/src/Tribufu.Serialization/DecimalStringConverter.cs b/src/Tribufu.Serialization/DecimalStringConverter.cs new file mode 100644 index 0000000..2794fa3 --- /dev/null +++ b/src/Tribufu.Serialization/DecimalStringConverter.cs @@ -0,0 +1,32 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +using Newtonsoft.Json; +using System; +using System.Globalization; + +namespace Tribufu.Serialization +{ + public class DecimalStringConverter : JsonConverter + { + public override decimal ReadJson(JsonReader reader, Type objectType, decimal existingValue, bool hasExistingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.String && decimal.TryParse(reader.Value?.ToString(), out var result)) + { + return result; + } + + if (reader.TokenType == JsonToken.Integer) + { + return Convert.ToUInt64(reader.Value); + } + + throw new JsonSerializationException($"Unexpected token {reader.TokenType} when parsing decimal."); + } + + public override void WriteJson(JsonWriter writer, decimal value, JsonSerializer serializer) + { + writer.WriteValue(value.ToString(CultureInfo.InvariantCulture)); + } + } +} diff --git a/src/Tribufu.Serialization/README.md b/src/Tribufu.Serialization/README.md new file mode 100644 index 0000000..54c1ab5 --- /dev/null +++ b/src/Tribufu.Serialization/README.md @@ -0,0 +1 @@ +# Tribufu diff --git a/src/Tribufu.Serialization/Tribufu.Serialization.csproj b/src/Tribufu.Serialization/Tribufu.Serialization.csproj new file mode 100644 index 0000000..e0b4fc8 --- /dev/null +++ b/src/Tribufu.Serialization/Tribufu.Serialization.csproj @@ -0,0 +1,19 @@ + + + Tribufu.Serialization + Tribufu Serialization Extensions + README.md + + + Properties + true + Library + netstandard2.0;net45;net5.0 + + + + + + + + diff --git a/src/Tribufu.Serialization/ULongNullableStringConverter.cs b/src/Tribufu.Serialization/ULongNullableStringConverter.cs new file mode 100644 index 0000000..0beb8e4 --- /dev/null +++ b/src/Tribufu.Serialization/ULongNullableStringConverter.cs @@ -0,0 +1,45 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +using Newtonsoft.Json; +using System; + +namespace Tribufu.Serialization +{ + public class ULongNullableStringConverter : JsonConverter + { + public override ulong? ReadJson(JsonReader reader, Type objectType, ulong? existingValue, bool hasExistingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + { + return null; + } + + if (reader.TokenType == JsonToken.String || reader.TokenType == JsonToken.Integer) + { + string value = reader.Value?.ToString(); + + if (string.IsNullOrWhiteSpace(value)) + { + return null; + } + + return ulong.Parse(value); + } + + throw new JsonSerializationException($"Unexpected token {reader.TokenType} when parsing ulong?."); + } + + public override void WriteJson(JsonWriter writer, ulong? value, JsonSerializer serializer) + { + if (value.HasValue) + { + writer.WriteValue(value.Value.ToString()); + } + else + { + writer.WriteNull(); + } + } + } +} diff --git a/src/Tribufu.Serialization/ULongStringConverter.cs b/src/Tribufu.Serialization/ULongStringConverter.cs new file mode 100644 index 0000000..5cb6f33 --- /dev/null +++ b/src/Tribufu.Serialization/ULongStringConverter.cs @@ -0,0 +1,31 @@ +// Copyright (c) Tribufu. All Rights Reserved. +// SPDX-License-Identifier: MIT + +using Newtonsoft.Json; +using System; + +namespace Tribufu.Serialization +{ + public class ULongStringConverter : JsonConverter + { + public override ulong ReadJson(JsonReader reader, Type objectType, ulong existingValue, bool hasExistingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.String && ulong.TryParse(reader.Value?.ToString(), out var result)) + { + return result; + } + + if (reader.TokenType == JsonToken.Integer) + { + return Convert.ToUInt64(reader.Value); + } + + throw new JsonSerializationException($"Unexpected token {reader.TokenType} when parsing ulong."); + } + + public override void WriteJson(JsonWriter writer, ulong value, JsonSerializer serializer) + { + writer.WriteValue(value.ToString()); + } + } +}