Skip to content

Commit 5c46ec0

Browse files
authored
Merge pull request #4 from g4-api/development
Development
2 parents 049e410 + 3d54f3f commit 5c46ec0

11 files changed

Lines changed: 292 additions & 97 deletions

File tree

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using G4.Converters;
2+
3+
using Microsoft.Extensions.Configuration;
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.IO;
8+
using System.Text;
9+
using System.Text.Json;
10+
using System.Text.Json.Serialization;
11+
12+
namespace ChromiumPeek.Settings
13+
{
14+
/// <summary>
15+
/// Represents the application settings including configuration, JSON options, and LiteDB connection.
16+
/// </summary>
17+
public static class AppSettings
18+
{
19+
#region *** Constants ***
20+
/// <summary>
21+
/// The version of the API.
22+
/// </summary>
23+
public const string ApiVersion = "4";
24+
#endregion
25+
26+
#region *** Fields ***
27+
/// <summary>
28+
/// Gets the application configuration.
29+
/// </summary>
30+
public static readonly IConfigurationRoot Configuration = NewConfiguraion();
31+
32+
/// <summary>
33+
/// Gets the JSON serialization options.
34+
/// </summary>
35+
public static readonly JsonSerializerOptions JsonOptions = NewJsonOptions();
36+
#endregion
37+
38+
#region *** Methods ***
39+
// Creates a new instance of IConfigurationRoot by configuring it with settings from appsettings.json and environment variables.
40+
private static IConfigurationRoot NewConfiguraion()
41+
{
42+
// Create a new ConfigurationBuilder instance
43+
new ConfigurationBuilder()
44+
.SetBasePath(Directory.GetCurrentDirectory())
45+
.AddJsonFile(path: "appsettings.json", optional: true, reloadOnChange: false)
46+
.AddEnvironmentVariables()
47+
.Build();
48+
49+
// Create a new ConfigurationBuilder instance
50+
var configurationBuilder = new ConfigurationBuilder();
51+
52+
// Set the base path for the configuration file to the current directory
53+
configurationBuilder.SetBasePath(Directory.GetCurrentDirectory());
54+
55+
// Add the appsettings.json file as a configuration source, if it exists (optional), without reloading it on change
56+
configurationBuilder.AddJsonFile(path: "appsettings.json", optional: true, reloadOnChange: false);
57+
58+
// Add environment variables as a configuration source
59+
configurationBuilder.AddEnvironmentVariables();
60+
61+
// Build and return the IConfigurationRoot instance
62+
return configurationBuilder.Build();
63+
}
64+
65+
// Creates a new instance of JsonSerializerOptions with custom settings and converters.
66+
private static JsonSerializerOptions NewJsonOptions()
67+
{
68+
// Initialize JSON serialization options.
69+
var jsonOptions = new JsonSerializerOptions()
70+
{
71+
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
72+
PropertyNameCaseInsensitive = true,
73+
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
74+
WriteIndented = false
75+
};
76+
77+
// Add a custom exception converter
78+
jsonOptions.Converters.Add(new ExceptionConverter());
79+
80+
// Add a custom method base converter
81+
jsonOptions.Converters.Add(new MethodBaseConverter());
82+
83+
// Add a custom type converter
84+
jsonOptions.Converters.Add(new TypeConverter());
85+
86+
// Add a custom DateTime converter for ISO 8601 format (yyyy-MM-ddTHH:mm:ss.ffffffK)
87+
jsonOptions.Converters.Add(new DateTimeIso8601Converter());
88+
89+
// Return the JSON options with custom settings and converters added
90+
return jsonOptions;
91+
}
92+
93+
// Retrieves a value from an environment variable and converts it to the specified type <typeparamref name="T"/>.
94+
// If the environment variable is not found, empty, or cannot be converted, returns the provided default value.
95+
private static T GetOrDefault<T>(string environmentParameter, T defaultValue)
96+
{
97+
// Attempt to read the environment variable value
98+
var envValue = Environment.GetEnvironmentVariable(environmentParameter);
99+
100+
// If the environment variable is missing or blank, use the default value
101+
if (string.IsNullOrWhiteSpace(envValue))
102+
{
103+
return defaultValue;
104+
}
105+
106+
try
107+
{
108+
// Check if T is a nullable type and get the underlying type
109+
var underlyingType = Nullable.GetUnderlyingType(typeof(T));
110+
var targetType = underlyingType ?? typeof(T);
111+
112+
// Special handling for booleans to support "true", "false", "1", and "0"
113+
if (targetType == typeof(bool))
114+
{
115+
if (bool.TryParse(envValue, out bool boolResult))
116+
{
117+
return (T)(object)boolResult;
118+
}
119+
120+
// Support numeric boolean representation
121+
if (envValue.Trim() == "1") return (T)(object)true;
122+
if (envValue.Trim() == "0") return (T)(object)false;
123+
}
124+
125+
// Attempt to convert the string value to the target type using system conversion
126+
return (T)Convert.ChangeType(envValue.Trim(), targetType);
127+
}
128+
catch
129+
{
130+
// If conversion fails (e.g., invalid format), fall back to the default value
131+
return defaultValue;
132+
}
133+
}
134+
#endregion
135+
}
136+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<!-- Assembly -->
5+
<TargetFramework>net10.0</TargetFramework>
6+
<AssemblyVersion>10.0.0.0</AssemblyVersion>
7+
<FileVersion>10.0.0.0</FileVersion>
8+
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
9+
<SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>
10+
<LangVersion>latest</LangVersion>
11+
<IsPackable>false</IsPackable>
12+
</PropertyGroup>
13+
14+
<ItemGroup>
15+
<!-- Please refrain from upgrading LiteDB until the locking bug is addressed.
16+
The latest known version without this issue is version 5.0.17.
17+
https://github.com/mbdavid/LiteDB/issues/1976#issuecomment-1968006775 -->
18+
<PackageReference Include="G4.Converters" Version="2026.4.29.65" />
19+
<PackageReference Include="LiteDB" Version="5.0.17" />
20+
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.7" />
21+
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.7" />
22+
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.7" />
23+
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.7" />
24+
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="10.0.7" />
25+
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.7" />
26+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.7" />
27+
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.7" />
28+
<PackageReference Include="Microsoft.Extensions.Configuration.Xml" Version="10.0.7" />
29+
<PackageReference Include="Microsoft.Extensions.Primitives" Version="10.0.7" />
30+
</ItemGroup>
31+
32+
</Project>

src/ChromiumPeek/ChromiumPeek.csproj

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,13 @@
1717
</PropertyGroup>
1818

1919
<ItemGroup>
20-
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
21-
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.0.1" />
22-
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="10.0.1" />
20+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.7" />
21+
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.7" />
22+
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="10.1.7" />
2323
</ItemGroup>
2424

2525
<ItemGroup>
2626
<ProjectReference Include="..\ChromiumPeek.Domain\ChromiumPeek.Domain.csproj" />
2727
</ItemGroup>
2828

29-
<ItemGroup>
30-
<Folder Include="Controllers\" />
31-
</ItemGroup>
32-
3329
</Project>

src/ChromiumPeek/Program.cs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,6 @@
242242
app.MapHub<ChromiumPeekHub>($"/hub/v4/g4/peek").RequireCors("CorsPolicy");
243243
#endregion
244244

245-
246245
StartChromiumWithExtension();
247246

248247
// Start the application and wait for it to finish.
@@ -268,11 +267,7 @@ static void StartChromiumWithExtension()
268267

269268
var browserCandidates = new[]
270269
{
271-
@"C:\Program Files\Google\Chrome\Application\chrome.exe",
272-
@"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe",
273-
Path.Combine(
274-
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
275-
@"Microsoft\Edge\Application\msedge.exe")
270+
@"E:\G4\g4-sandbox-v2026.02.12.64\browsers\chrome\chrome.exe"
276271
};
277272

278273
var browserPath = browserCandidates.FirstOrDefault(File.Exists);
@@ -294,7 +289,7 @@ static void StartChromiumWithExtension()
294289

295290
// No manual quotes needed anywhere here
296291
psi.ArgumentList.Add($"--remote-debugging-port={remoteDebuggingPort}");
297-
psi.ArgumentList.Add($"--user-data-dir={userDataDir}");
292+
// psi.ArgumentList.Add($"--user-data-dir={userDataDir}");
298293
psi.ArgumentList.Add($"--load-extension={extensionDir}");
299294
// optional, once it's stable:
300295
// psi.ArgumentList.Add($"--disable-extensions-except={extensionDir}");
@@ -317,6 +312,4 @@ static void StartChromiumWithExtension()
317312
{
318313
Console.WriteLine("[ChromiumPeek] Failed to start browser: " + ex);
319314
}
320-
}
321-
322-
315+
}

src/Common.Domain/Common.Domain.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
<ItemGroup>
2020
<PackageReference Include="CommandBridge" Version="2025.2.26.62" />
21-
<PackageReference Include="G4.Extensions" Version="2025.8.11.43" />
21+
<PackageReference Include="G4.Extensions" Version="2026.4.29.65" />
2222
</ItemGroup>
2323

2424
</Project>

src/Common.Domain/Models/RecorderNodeModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class RecorderNodeModel<T>
3636
public string ControlType { get; set; }
3737

3838
/// <summary>
39-
/// Gets or sets the underlying IUIAutomationElement instance.
39+
/// Gets or sets the underlying Element instance.
4040
/// </summary>
4141
[JsonIgnore]
4242
public T Element { get; set; }

src/G4.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.Domain", "Common.Dom
3131
EndProject
3232
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChromiumPeek.Domain", "ChromiumPeek.Domain\ChromiumPeek.Domain.csproj", "{B234C607-2A88-42E0-A2C4-060B345690F5}"
3333
EndProject
34+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChromiumPeek.Settings", "ChromiumPeek.Settings\ChromiumPeek.Settings.csproj", "{81647D0A-AADF-4864-8238-1F39AA0F2800}"
35+
EndProject
3436
Global
3537
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3638
Debug|Any CPU = Debug|Any CPU
@@ -61,6 +63,10 @@ Global
6163
{B234C607-2A88-42E0-A2C4-060B345690F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
6264
{B234C607-2A88-42E0-A2C4-060B345690F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
6365
{B234C607-2A88-42E0-A2C4-060B345690F5}.Release|Any CPU.Build.0 = Release|Any CPU
66+
{81647D0A-AADF-4864-8238-1F39AA0F2800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
67+
{81647D0A-AADF-4864-8238-1F39AA0F2800}.Debug|Any CPU.Build.0 = Debug|Any CPU
68+
{81647D0A-AADF-4864-8238-1F39AA0F2800}.Release|Any CPU.ActiveCfg = Release|Any CPU
69+
{81647D0A-AADF-4864-8238-1F39AA0F2800}.Release|Any CPU.Build.0 = Release|Any CPU
6470
EndGlobalSection
6571
GlobalSection(SolutionProperties) = preSolution
6672
HideSolutionNode = FALSE

0 commit comments

Comments
 (0)