1+ using FluentValidation ;
2+ using Microsoft . Extensions . Configuration ;
3+ using Nox . Core . Exceptions ;
4+ using Nox . Core . Extensions ;
5+ using Nox . Core . Helpers ;
6+ using Nox . Core . Interfaces ;
7+ using Nox . Core . Interfaces . Configuration ;
8+ using Nox . Core . Interfaces . Database ;
9+ using Nox . Core . Validation . Configuration ;
10+
11+ namespace Nox . Core . Builders ;
12+
13+ public class ProjectConfigurationBuilder
14+ {
15+ private string ? _designRoot ;
16+
17+ public ProjectConfigurationBuilder ( string ? designRoot )
18+ {
19+ _designRoot = designRoot ;
20+ }
21+
22+ public IProjectConfiguration ? Build ( )
23+ {
24+ var configuration = ConfigurationHelper . GetNoxAppSettings ( ) ;
25+
26+ if ( string . IsNullOrEmpty ( _designRoot ) )
27+ {
28+ if ( configuration != null )
29+ {
30+ _designRoot = configuration [ "Nox:DesignFolder" ] ?? configuration [ "Nox:DefinitionRootPath" ] ;
31+ }
32+
33+ if ( ! Directory . Exists ( _designRoot ) ) _designRoot = "./" ;
34+
35+ if ( _designRoot == null )
36+ {
37+ throw new ConfigurationException ( "Could not load Nox configuration." ) ;
38+ }
39+ }
40+ var configurator = new ProjectConfigurator ( _designRoot ) ;
41+
42+ var yamlConfig = configurator . LoadConfiguration ( ) ;
43+
44+ if ( yamlConfig != null )
45+ {
46+ var validator = new YamlConfigValidator ( ) ;
47+ validator . ValidateAndThrow ( yamlConfig ) ;
48+
49+ return new Configurator ( yamlConfig )
50+ . WithAppConfiguration ( configuration ! )
51+ . Configure ( ) ;
52+ }
53+ return null ;
54+ }
55+
56+ private class Configurator
57+ {
58+ private IProjectConfiguration ? _projectConfig ;
59+ private IConfiguration ? _appConfig ;
60+ private readonly IYamlConfiguration ? _yamlConfig ;
61+
62+ public Configurator ( IYamlConfiguration projectConfig )
63+ {
64+ _yamlConfig = projectConfig ;
65+ _projectConfig = _yamlConfig . ToMetaService ( ) ;
66+ }
67+
68+ public ProjectConfigurationBuilder . Configurator WithAppConfiguration ( IConfiguration appConfig )
69+ {
70+ _appConfig = appConfig ;
71+ return this ;
72+ }
73+
74+ public IProjectConfiguration Configure ( )
75+ {
76+ _projectConfig = _yamlConfig ! . ToMetaService ( ) ;
77+
78+ var serviceDatabases = GetServiceDatabasesFromNoxConfig ( ) ;
79+
80+ ResolveConfigurationVariables ( serviceDatabases ) ;
81+
82+ _projectConfig . Validate ( ) ;
83+
84+ _projectConfig . Configure ( ) ;
85+
86+ return _projectConfig ;
87+ }
88+
89+
90+ private void ResolveConfigurationVariables ( IList < IServiceDataSource > serviceDatabases )
91+ {
92+ // populate variables from application config
93+ var databases = serviceDatabases
94+ . Where ( d => string . IsNullOrEmpty ( d . ConnectionString ) )
95+ . Where ( d => ! string . IsNullOrEmpty ( d . ConnectionVariable ) ) ;
96+
97+ var variables = databases
98+ . Select ( d => d . ConnectionVariable ! )
99+ . ToHashSet ( )
100+ . ToDictionary ( v => v , v => _appConfig ? [ v ] , StringComparer . OrdinalIgnoreCase ) ;
101+
102+ if ( _projectConfig ! . MessagingProviders is { Count : > 0 } )
103+ {
104+ foreach ( var item in _projectConfig . MessagingProviders )
105+ {
106+ if ( string . IsNullOrEmpty ( item . ConnectionString ) && ! string . IsNullOrEmpty ( item . ConnectionVariable ) )
107+ {
108+ variables . Add ( item . ConnectionVariable , _appConfig ? [ item . ConnectionVariable ] ) ;
109+ }
110+ }
111+ }
112+
113+ // try key vault where app configuration is missing
114+ if ( variables . Any ( v => v . Value == null ) )
115+ {
116+ // TryAddMissingConfigsFromKeyVault(_metaService.KeyVaultUri, variables!);
117+ }
118+
119+ if ( variables . Any ( v => v . Value == null ) )
120+ {
121+ var variableNames = string . Join ( ',' , variables
122+ . Where ( v => v . Value == null )
123+ . Select ( v => v . Key )
124+ . ToArray ( )
125+ ) ;
126+ throw new ConfigurationNotFoundException ( variableNames ) ;
127+ }
128+
129+ databases . ToList ( ) . ForEach ( db =>
130+ db . ConnectionString = variables [ db . ConnectionVariable ! ]
131+ ) ;
132+
133+ if ( _projectConfig . MessagingProviders is { Count : > 0 } )
134+ {
135+ foreach ( var item in _projectConfig . MessagingProviders )
136+ {
137+ if ( string . IsNullOrEmpty ( item . ConnectionString ) && ! string . IsNullOrEmpty ( item . ConnectionVariable ) )
138+ {
139+ item . ConnectionString = variables [ item . ConnectionVariable ! ] ;
140+ }
141+ }
142+ }
143+ }
144+
145+ /*
146+ private void TryAddMissingConfigsFromKeyVault(string vaultUri, Dictionary<string, string> variables)
147+ {
148+ var azureServiceTokenProvider = new AzureServiceTokenProvider();
149+
150+ var keyVault = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
151+
152+ try
153+ {
154+ var test = keyVault.GetSecretAsync(vaultUri, "Test").GetAwaiter().GetResult().Value;
155+ }
156+ catch (Exception ex)
157+ {
158+ return;
159+ }
160+
161+ foreach (var key in variables.Keys)
162+ {
163+
164+ if (string.IsNullOrEmpty(variables[key]))
165+ {
166+ variables[key] = keyVault.GetSecretAsync(vaultUri, key.Replace(":", "--")).GetAwaiter().GetResult().Value;
167+ }
168+
169+ }
170+ }
171+
172+ */
173+
174+ private IList < IServiceDataSource > GetServiceDatabasesFromNoxConfig ( )
175+ {
176+ var serviceDatabases = new List < IServiceDataSource >
177+ {
178+ _projectConfig ! . Database !
179+ } ;
180+
181+ foreach ( var dataSource in _projectConfig . DataSources ! )
182+ {
183+ serviceDatabases . Add ( dataSource ) ;
184+ }
185+
186+ return serviceDatabases ;
187+ }
188+
189+ }
190+ }
0 commit comments