tgstation-server 6.8.0
The /tg/station 13 server suite
Loading...
Searching...
No Matches
Classes | Namespaces | Functions
SetupWizard.cs File Reference

Go to the source code of this file.

Classes

class  Tgstation.Server.Host.Setup.SetupWizard
 

Namespaces

namespace  Tgstation
 
namespace  Tgstation.Server
 
namespace  Tgstation.Server.Host
 
namespace  Tgstation.Server.Host.Setup
 

Functions

 Tgstation.Server.Host.Setup.while (true)
 
async ValueTask< GeneralConfigurationConfigureGeneral (CancellationToken cancellationToken)
 Prompts the user to create a GeneralConfiguration. More...
 
async ValueTask< FileLoggingConfigurationConfigureLogging (CancellationToken cancellationToken)
 Prompts the user to create a FileLoggingConfiguration. More...
 
async ValueTask< ElasticsearchConfigurationConfigureElasticsearch (CancellationToken cancellationToken)
 Prompts the user to create a ElasticsearchConfiguration. More...
 
async ValueTask< ControlPanelConfigurationConfigureControlPanel (CancellationToken cancellationToken)
 Prompts the user to create a ControlPanelConfiguration. More...
 
async ValueTask< SwarmConfiguration?> ConfigureSwarm (CancellationToken cancellationToken)
 Prompts the user to create a SwarmConfiguration. More...
 
async ValueTask SaveConfiguration (string userConfigFileName, ushort? hostingPort, DatabaseConfiguration databaseConfiguration, GeneralConfiguration newGeneralConfiguration, FileLoggingConfiguration? fileLoggingConfiguration, ElasticsearchConfiguration? elasticsearchConfiguration, ControlPanelConfiguration controlPanelConfiguration, SwarmConfiguration? swarmConfiguration, CancellationToken cancellationToken)
 Saves a given Configuration set to userConfigFileName . More...
 
async ValueTask RunWizard (string userConfigFileName, CancellationToken cancellationToken)
 Runs the SetupWizard. More...
 
async ValueTask CheckRunWizard (CancellationToken cancellationToken)
 Check if it should and run the SetupWizard if necessary. More...
 

Function Documentation

◆ CheckRunWizard()

async ValueTask CheckRunWizard ( CancellationToken  cancellationToken)

Check if it should and run the SetupWizard if necessary.

Parameters
cancellationTokenThe CancellationToken for the operation.
Returns
A ValueTask representing the running operation.

Definition at line 1078 of file SetupWizard.cs.

1079 {
1080 var setupWizardMode = generalConfiguration.SetupWizardMode;
1081 if (setupWizardMode == SetupWizardMode.Never)
1082 return;
1083
1084 var forceRun = setupWizardMode == SetupWizardMode.Force || setupWizardMode == SetupWizardMode.Only;
1085 if (!console.Available)
1086 {
1087 if (forceRun)
1088 throw new InvalidOperationException("Asked to run setup wizard with no console avaliable!");
1089 return;
1090 }
1091
1092 var userConfigFileName = ioManager.ConcatPath(
1093 internalConfiguration.AppSettingsBasePath,
1094 $"{ServerFactory.AppSettings}.{hostingEnvironment.EnvironmentName}.yml");
1095
1096 async Task HandleSetupCancel()
1097 {
1098 // DCTx2: Operation should always run
1099 await console.WriteAsync(String.Empty, true, default);
1100 await console.WriteAsync("Aborting setup!", true, default);
1101 }
1102
1103 Task finalTask = Task.CompletedTask;
1104 string? originalConsoleTitle = null;
1105 void SetConsoleTitle()
1106 {
1107 if (originalConsoleTitle != null)
1108 return;
1109
1110 originalConsoleTitle = console.Title;
1111 console.SetTitle($"{assemblyInformationProvider.VersionString} Setup Wizard");
1112 }
1113
1114 // Link passed cancellationToken with cancel key press
1115 using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, console.CancelKeyPress))
1116 using ((cancellationToken = cts.Token).Register(() => finalTask = HandleSetupCancel()))
1117 try
1118 {
1119 var exists = await ioManager.FileExists(userConfigFileName, cancellationToken);
1120 if (!exists)
1121 {
1122 var legacyJsonFileName = $"appsettings.{hostingEnvironment.EnvironmentName}.json";
1123 exists = await ioManager.FileExists(legacyJsonFileName, cancellationToken);
1124 if (exists)
1125 userConfigFileName = legacyJsonFileName;
1126 }
1127
1128 bool shouldRunBasedOnAutodetect;
1129 if (exists)
1130 {
1131 var bytes = await ioManager.ReadAllBytes(userConfigFileName, cancellationToken);
1132 var contents = Encoding.UTF8.GetString(bytes);
1133 var lines = contents.Split('\n', StringSplitOptions.RemoveEmptyEntries);
1134 var existingConfigIsEmpty = lines
1135 .Select(line => line.Trim())
1136 .All(line => line[0] == '#' || line == "{}" || line.Length == 0);
1137 shouldRunBasedOnAutodetect = existingConfigIsEmpty;
1138 }
1139 else
1140 shouldRunBasedOnAutodetect = true;
1141
1142 if (!shouldRunBasedOnAutodetect)
1143 {
1144 if (forceRun)
1145 {
1146 SetConsoleTitle();
1147 await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "The configuration settings are requesting the setup wizard be run, but you already appear to have a configuration file ({0})!", userConfigFileName), true, cancellationToken);
1148
1149 forceRun = await PromptYesNo("Continue running setup wizard?", false, cancellationToken);
1150 }
1151
1152 if (!forceRun)
1153 return;
1154 }
1155
1156 SetConsoleTitle();
1157
1158 if (!String.IsNullOrEmpty(internalConfiguration.MariaDBDefaultRootPassword))
1159 {
1160 // we can generate the whole thing.
1161 var csb = new MySqlConnectionStringBuilder
1162 {
1163 Server = "127.0.0.1",
1164 UserID = "root",
1165 Password = internalConfiguration.MariaDBDefaultRootPassword,
1166 Database = "tgs",
1167 };
1168
1169 await SaveConfiguration(
1170 userConfigFileName,
1171 null,
1173 {
1174 ConnectionString = csb.ConnectionString,
1175 DatabaseType = DatabaseType.MariaDB,
1177 },
1179 null,
1180 null,
1182 {
1183 Enable = true,
1184 AllowAnyOrigin = true,
1185 },
1186 null,
1187 cancellationToken);
1188 }
1189 else
1190 {
1191 // flush the logs to prevent console conflicts
1192 await asyncDelayer.Delay(TimeSpan.FromSeconds(1), cancellationToken);
1193
1194 await RunWizard(userConfigFileName, cancellationToken);
1195 }
1196 }
1197 finally
1198 {
1199 await finalTask;
1200 if (originalConsoleTitle != null)
1201 console.SetTitle(originalConsoleTitle);
1202 }
1203 }
async ValueTask SaveConfiguration(string userConfigFileName, ushort? hostingPort, DatabaseConfiguration databaseConfiguration, GeneralConfiguration newGeneralConfiguration, FileLoggingConfiguration? fileLoggingConfiguration, ElasticsearchConfiguration? elasticsearchConfiguration, ControlPanelConfiguration controlPanelConfiguration, SwarmConfiguration? swarmConfiguration, CancellationToken cancellationToken)
Saves a given Configuration set to userConfigFileName .
Definition: SetupWizard.cs:966
async ValueTask RunWizard(string userConfigFileName, CancellationToken cancellationToken)
Runs the SetupWizard.
Configuration options for the Database.DatabaseContext.
string? ConnectionString
The connection string for the database.
Attribute for bringing in the master versions list from MSBuild that aren't embedded into assemblies ...
string RawMariaDBRedistVersion
The Version string of the MariaDB server bundled with TGS installs.
static MasterVersionsAttribute Instance
Return the Assembly's instance of the MasterVersionsAttribute.
DatabaseType
Type of database to user.
Definition: DatabaseType.cs:7
SetupWizardMode
Determines if the SetupWizard will run.

References Tgstation.Server.Host.Configuration.DatabaseConfiguration.ConnectionString, Tgstation.Server.Host.Properties.MasterVersionsAttribute.Instance, Tgstation.Server.Host.Properties.MasterVersionsAttribute.RawMariaDBRedistVersion, RunWizard(), and SaveConfiguration().

Referenced by Tgstation.Server.Host.Setup.SetupWizard.ExecuteAsync().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ConfigureControlPanel()

async ValueTask< ControlPanelConfiguration > ConfigureControlPanel ( CancellationToken  cancellationToken)

Prompts the user to create a ControlPanelConfiguration.

Parameters
cancellationTokenThe CancellationToken for the operation.
Returns
A ValueTask<TResult> resulting in the new ControlPanelConfiguration.

Definition at line 861 of file SetupWizard.cs.

862 {
863 var config = new ControlPanelConfiguration
864 {
865 Enable = await PromptYesNo("Enable the web control panel?", true, cancellationToken),
866 AllowAnyOrigin = await PromptYesNo(
867 "Allow web control panels hosted elsewhere to access the server? (Access-Control-Allow-Origin: *)",
868 true,
869 cancellationToken),
870 };
871
872 if (!config.AllowAnyOrigin)
873 {
874 await console.WriteAsync("Enter a comma seperated list of CORS allowed origins (optional): ", false, cancellationToken);
875 var commaSeperatedOrigins = await console.ReadLineAsync(false, cancellationToken);
876 if (!String.IsNullOrWhiteSpace(commaSeperatedOrigins))
877 {
878 var splits = commaSeperatedOrigins.Split(',');
879 config.AllowedOrigins = new List<string>(splits.Select(x => x.Trim()));
880 }
881 }
882
883 return config;
884 }

Referenced by RunWizard().

Here is the caller graph for this function:

◆ ConfigureElasticsearch()

async ValueTask< ElasticsearchConfiguration > ConfigureElasticsearch ( CancellationToken  cancellationToken)

Prompts the user to create a ElasticsearchConfiguration.

Parameters
cancellationTokenThe CancellationToken for the operation.
Returns
A ValueTask<TResult> resulting in the new ElasticsearchConfiguration.

Definition at line 809 of file SetupWizard.cs.

810 {
811 var elasticsearchConfiguration = new ElasticsearchConfiguration();
812 await console.WriteAsync(null, true, cancellationToken);
813 elasticsearchConfiguration.Enable = await PromptYesNo("Enable logging to an external ElasticSearch server?", false, cancellationToken);
814
815 if (elasticsearchConfiguration.Enable)
816 {
817 do
818 {
819 await console.WriteAsync("ElasticSearch server endpoint (Include protocol and port, leave blank for http://127.0.0.1:9200): ", false, cancellationToken);
820 var hostString = await console.ReadLineAsync(false, cancellationToken);
821 if (String.IsNullOrWhiteSpace(hostString))
822 hostString = "http://127.0.0.1:9200";
823
824 if (Uri.TryCreate(hostString, UriKind.Absolute, out var host))
825 {
826 elasticsearchConfiguration.Host = host;
827 break;
828 }
829
830 await console.WriteAsync("Invalid URI!", true, cancellationToken);
831 }
832 while (true);
833
834 do
835 {
836 await console.WriteAsync("Enter Elasticsearch username: ", false, cancellationToken);
837 elasticsearchConfiguration.Username = await console.ReadLineAsync(false, cancellationToken);
838 if (!String.IsNullOrWhiteSpace(elasticsearchConfiguration.Username))
839 break;
840 }
841 while (true);
842
843 do
844 {
845 await console.WriteAsync("Enter password: ", false, cancellationToken);
846 elasticsearchConfiguration.Password = await console.ReadLineAsync(true, cancellationToken);
847 if (!String.IsNullOrWhiteSpace(elasticsearchConfiguration.Username))
848 break;
849 }
850 while (true);
851 }
852
853 return elasticsearchConfiguration;
854 }
Configuration options pertaining to elasticsearch log storage.

Referenced by RunWizard().

Here is the caller graph for this function:

◆ ConfigureGeneral()

async ValueTask< GeneralConfiguration > ConfigureGeneral ( CancellationToken  cancellationToken)

Prompts the user to create a GeneralConfiguration.

Parameters
cancellationTokenThe CancellationToken for the operation.
Returns
A ValueTask<TResult> resulting in the new GeneralConfiguration.

Definition at line 666 of file SetupWizard.cs.

667 {
668 var newGeneralConfiguration = new GeneralConfiguration
669 {
671 };
672
673 do
674 {
675 await console.WriteAsync(null, true, cancellationToken);
676 await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "Minimum database user password length (leave blank for default of {0}): ", newGeneralConfiguration.MinimumPasswordLength), false, cancellationToken);
677 var passwordLengthString = await console.ReadLineAsync(false, cancellationToken);
678 if (String.IsNullOrWhiteSpace(passwordLengthString))
679 break;
680 if (UInt32.TryParse(passwordLengthString, out var passwordLength) && passwordLength >= 0)
681 {
682 newGeneralConfiguration.MinimumPasswordLength = passwordLength;
683 break;
684 }
685
686 await console.WriteAsync("Please enter a positive integer!", true, cancellationToken);
687 }
688 while (true);
689
690 do
691 {
692 await console.WriteAsync(null, true, cancellationToken);
693 await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "Default timeout for sending and receiving BYOND topics (ms, 0 for infinite, leave blank for default of {0}): ", newGeneralConfiguration.ByondTopicTimeout), false, cancellationToken);
694 var topicTimeoutString = await console.ReadLineAsync(false, cancellationToken);
695 if (String.IsNullOrWhiteSpace(topicTimeoutString))
696 break;
697 if (UInt32.TryParse(topicTimeoutString, out var topicTimeout) && topicTimeout >= 0)
698 {
699 newGeneralConfiguration.ByondTopicTimeout = topicTimeout;
700 break;
701 }
702
703 await console.WriteAsync("Please enter a positive integer!", true, cancellationToken);
704 }
705 while (true);
706
707 await console.WriteAsync(null, true, cancellationToken);
708 await console.WriteAsync("Enter a GitHub personal access token to bypass some rate limits (this is optional and does not require any scopes)", true, cancellationToken);
709 await console.WriteAsync("GitHub personal access token: ", false, cancellationToken);
710 newGeneralConfiguration.GitHubAccessToken = await console.ReadLineAsync(true, cancellationToken);
711 if (String.IsNullOrWhiteSpace(newGeneralConfiguration.GitHubAccessToken))
712 newGeneralConfiguration.GitHubAccessToken = null;
713
714 newGeneralConfiguration.HostApiDocumentation = await PromptYesNo("Host API Documentation?", false, cancellationToken);
715
716 return newGeneralConfiguration;
717 }

Referenced by RunWizard().

Here is the caller graph for this function:

◆ ConfigureLogging()

async ValueTask< FileLoggingConfiguration > ConfigureLogging ( CancellationToken  cancellationToken)

Prompts the user to create a FileLoggingConfiguration.

Parameters
cancellationTokenThe CancellationToken for the operation.
Returns
A ValueTask<TResult> resulting in the new FileLoggingConfiguration.

Definition at line 724 of file SetupWizard.cs.

725 {
726 var fileLoggingConfiguration = new FileLoggingConfiguration();
727 await console.WriteAsync(null, true, cancellationToken);
728 fileLoggingConfiguration.Disable = !await PromptYesNo("Enable file logging?", true, cancellationToken);
729
730 if (!fileLoggingConfiguration.Disable)
731 {
732 do
733 {
734 await console.WriteAsync("Log file directory path (leave blank for default): ", false, cancellationToken);
735 fileLoggingConfiguration.Directory = await console.ReadLineAsync(false, cancellationToken);
736 if (String.IsNullOrWhiteSpace(fileLoggingConfiguration.Directory))
737 {
738 fileLoggingConfiguration.Directory = null;
739 break;
740 }
741
742 // test a write of it
743 await console.WriteAsync(null, true, cancellationToken);
744 await console.WriteAsync("Testing directory access...", true, cancellationToken);
745 try
746 {
747 await ioManager.CreateDirectory(fileLoggingConfiguration.Directory, cancellationToken);
748 var testFile = ioManager.ConcatPath(fileLoggingConfiguration.Directory, String.Format(CultureInfo.InvariantCulture, "WizardAccesTest.{0}.deleteme", Guid.NewGuid()));
749 await ioManager.WriteAllBytes(testFile, Array.Empty<byte>(), cancellationToken);
750 try
751 {
752 await ioManager.DeleteFile(testFile, cancellationToken);
753 }
754 catch (OperationCanceledException)
755 {
756 throw;
757 }
758 catch (Exception e)
759 {
760 await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "Error deleting test log file: {0}", testFile), true, cancellationToken);
761 await console.WriteAsync(e.Message, true, cancellationToken);
762 await console.WriteAsync(null, true, cancellationToken);
763 }
764
765 break;
766 }
767 catch (OperationCanceledException)
768 {
769 throw;
770 }
771 catch (Exception e)
772 {
773 await console.WriteAsync(e.Message, true, cancellationToken);
774 await console.WriteAsync(null, true, cancellationToken);
775 await console.WriteAsync("Please verify the path is valid and you have access to it!", true, cancellationToken);
776 }
777 }
778 while (true);
779
780 async ValueTask<LogLevel?> PromptLogLevel(string question)
781 {
782 do
783 {
784 await console.WriteAsync(null, true, cancellationToken);
785 await console.WriteAsync(question, true, cancellationToken);
786 await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "Enter one of {0}/{1}/{2}/{3}/{4}/{5} (leave blank for default): ", nameof(LogLevel.Trace), nameof(LogLevel.Debug), nameof(LogLevel.Information), nameof(LogLevel.Warning), nameof(LogLevel.Error), nameof(LogLevel.Critical)), false, cancellationToken);
787 var responseString = await console.ReadLineAsync(false, cancellationToken);
788 if (String.IsNullOrWhiteSpace(responseString))
789 return null;
790 if (Enum.TryParse<LogLevel>(responseString, out var logLevel) && logLevel != LogLevel.None)
791 return logLevel;
792 await console.WriteAsync("Invalid log level!", true, cancellationToken);
793 }
794 while (true);
795 }
796
797 fileLoggingConfiguration.LogLevel = await PromptLogLevel(String.Format(CultureInfo.InvariantCulture, "Enter the level limit for normal logs (default {0}).", fileLoggingConfiguration.LogLevel)) ?? fileLoggingConfiguration.LogLevel;
798 fileLoggingConfiguration.MicrosoftLogLevel = await PromptLogLevel(String.Format(CultureInfo.InvariantCulture, "Enter the level limit for Microsoft logs (VERY verbose, default {0}).", fileLoggingConfiguration.MicrosoftLogLevel)) ?? fileLoggingConfiguration.MicrosoftLogLevel;
799 }
800
801 return fileLoggingConfiguration;
802 }

Referenced by RunWizard().

Here is the caller graph for this function:

◆ ConfigureSwarm()

async ValueTask< SwarmConfiguration?> ConfigureSwarm ( CancellationToken  cancellationToken)

Prompts the user to create a SwarmConfiguration.

Parameters
cancellationTokenThe CancellationToken for the operation.
Returns
A ValueTask<TResult> resulting in the new SwarmConfiguration.

Definition at line 891 of file SetupWizard.cs.

892 {
893 var enable = await PromptYesNo("Enable swarm mode?", false, cancellationToken);
894 if (!enable)
895 return null;
896
897 string identifer;
898 do
899 {
900 await console.WriteAsync("Enter this server's identifer: ", false, cancellationToken);
901 identifer = await console.ReadLineAsync(false, cancellationToken);
902 }
903 while (String.IsNullOrWhiteSpace(identifer));
904
905 async ValueTask<Uri> ParseAddress(string question)
906 {
907 var first = true;
908 Uri? address;
909 do
910 {
911 if (first)
912 first = false;
913 else
914 await console.WriteAsync("Invalid address!", true, cancellationToken);
915
916 await console.WriteAsync(question, false, cancellationToken);
917 var addressString = await console.ReadLineAsync(false, cancellationToken);
918 if (Uri.TryCreate(addressString, UriKind.Absolute, out address)
919 && address.Scheme != Uri.UriSchemeHttp
920 && address.Scheme != Uri.UriSchemeHttps)
921 address = null;
922 }
923 while (address == null);
924
925 return address;
926 }
927
928 var address = await ParseAddress("Enter this server's INTERNAL http(s) address: ");
929 var publicAddress = await ParseAddress("Enter this server's PUBLIC https(s) address: ");
930 string privateKey;
931 do
932 {
933 await console.WriteAsync("Enter the swarm private key: ", false, cancellationToken);
934 privateKey = await console.ReadLineAsync(false, cancellationToken);
935 }
936 while (String.IsNullOrWhiteSpace(privateKey));
937
938 var controller = await PromptYesNo("Is this server the swarm's controller? (y/n): ", null, cancellationToken);
939 Uri? controllerAddress = null;
940 if (!controller)
941 controllerAddress = await ParseAddress("Enter the swarm controller's HTTP(S) address: ");
942
943 return new SwarmConfiguration
944 {
945 Address = address,
946 PublicAddress = publicAddress,
947 ControllerAddress = controllerAddress,
948 Identifier = identifer,
949 PrivateKey = privateKey,
950 };
951 }
Configuration for the server swarm system.

Referenced by RunWizard().

Here is the caller graph for this function:

◆ RunWizard()

async ValueTask RunWizard ( string  userConfigFileName,
CancellationToken  cancellationToken 
)

Runs the SetupWizard.

Parameters
userConfigFileNameThe path to the settings json to build.
cancellationTokenThe CancellationToken for the operation.
Returns
A ValueTask representing the running operation.

Definition at line 1038 of file SetupWizard.cs.

1039 {
1040 // welcome message
1041 await console.WriteAsync($"Welcome to {Constants.CanonicalPackageName}!", true, cancellationToken);
1042 await console.WriteAsync("This wizard will help you configure your server.", true, cancellationToken);
1043
1044 var hostingPort = await PromptForHostingPort(cancellationToken);
1045
1046 var databaseConfiguration = await ConfigureDatabase(cancellationToken);
1047
1048 var newGeneralConfiguration = await ConfigureGeneral(cancellationToken);
1049
1050 var fileLoggingConfiguration = await ConfigureLogging(cancellationToken);
1051
1052 var elasticSearchConfiguration = await ConfigureElasticsearch(cancellationToken);
1053
1054 var controlPanelConfiguration = await ConfigureControlPanel(cancellationToken);
1055
1056 var swarmConfiguration = await ConfigureSwarm(cancellationToken);
1057
1058 await console.WriteAsync(null, true, cancellationToken);
1059 await console.WriteAsync(String.Format(CultureInfo.InvariantCulture, "Configuration complete! Saving to {0}", userConfigFileName), true, cancellationToken);
1060
1061 await SaveConfiguration(
1062 userConfigFileName,
1063 hostingPort,
1064 databaseConfiguration,
1065 newGeneralConfiguration,
1066 fileLoggingConfiguration,
1067 elasticSearchConfiguration,
1068 controlPanelConfiguration,
1069 swarmConfiguration,
1070 cancellationToken);
1071 }
async ValueTask< ControlPanelConfiguration > ConfigureControlPanel(CancellationToken cancellationToken)
Prompts the user to create a ControlPanelConfiguration.
Definition: SetupWizard.cs:861
async ValueTask< GeneralConfiguration > ConfigureGeneral(CancellationToken cancellationToken)
Prompts the user to create a GeneralConfiguration.
Definition: SetupWizard.cs:666
async ValueTask< FileLoggingConfiguration > ConfigureLogging(CancellationToken cancellationToken)
Prompts the user to create a FileLoggingConfiguration.
Definition: SetupWizard.cs:724
async ValueTask< SwarmConfiguration?> ConfigureSwarm(CancellationToken cancellationToken)
Prompts the user to create a SwarmConfiguration.
Definition: SetupWizard.cs:891
async ValueTask< ElasticsearchConfiguration > ConfigureElasticsearch(CancellationToken cancellationToken)
Prompts the user to create a ElasticsearchConfiguration.
Definition: SetupWizard.cs:809

References ConfigureControlPanel(), ConfigureElasticsearch(), ConfigureGeneral(), ConfigureLogging(), ConfigureSwarm(), and SaveConfiguration().

Referenced by CheckRunWizard().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SaveConfiguration()

async ValueTask SaveConfiguration ( string  userConfigFileName,
ushort?  hostingPort,
DatabaseConfiguration  databaseConfiguration,
GeneralConfiguration  newGeneralConfiguration,
FileLoggingConfiguration fileLoggingConfiguration,
ElasticsearchConfiguration elasticsearchConfiguration,
ControlPanelConfiguration  controlPanelConfiguration,
SwarmConfiguration swarmConfiguration,
CancellationToken  cancellationToken 
)

Saves a given Configuration set to userConfigFileName .

Parameters
userConfigFileNameThe file to save the Configuration to.
hostingPortThe hosting port to save.
databaseConfigurationThe DatabaseConfiguration to save.
newGeneralConfigurationThe GeneralConfiguration to save.
fileLoggingConfigurationThe FileLoggingConfiguration to save.
elasticsearchConfigurationThe ElasticsearchConfiguration to save.
controlPanelConfigurationThe ControlPanelConfiguration to save.
swarmConfigurationThe SwarmConfiguration to save.
cancellationTokenThe CancellationToken for the operation.
Returns
A ValueTask representing the running operation.

Definition at line 966 of file SetupWizard.cs.

976 {
977 newGeneralConfiguration.ApiPort = hostingPort ?? GeneralConfiguration.DefaultApiPort;
978 newGeneralConfiguration.ConfigVersion = GeneralConfiguration.CurrentConfigVersion;
979 var map = new Dictionary<string, object?>()
980 {
981 { DatabaseConfiguration.Section, databaseConfiguration },
982 { GeneralConfiguration.Section, newGeneralConfiguration },
983 { FileLoggingConfiguration.Section, fileLoggingConfiguration },
984 { ElasticsearchConfiguration.Section, elasticsearchConfiguration },
985 { ControlPanelConfiguration.Section, controlPanelConfiguration },
986 { SwarmConfiguration.Section, swarmConfiguration },
987 };
988
989 var versionConverter = new VersionConverter();
990 var builder = new SerializerBuilder()
991 .WithTypeConverter(versionConverter);
992
993 if (userConfigFileName.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
994 builder.JsonCompatible();
995
996 var serializer = new SerializerBuilder()
997 .WithTypeConverter(versionConverter)
998 .Build();
999
1000 var serializedYaml = serializer.Serialize(map);
1001
1002 // big hack, but, prevent the default control panel channel from being overridden
1003 serializedYaml = serializedYaml.Replace(
1004 $"\n {nameof(ControlPanelConfiguration.Channel)}: ",
1005 String.Empty,
1006 StringComparison.Ordinal)
1007 .Replace("\r", String.Empty, StringComparison.Ordinal);
1008
1009 var configBytes = Encoding.UTF8.GetBytes(serializedYaml);
1010
1011 try
1012 {
1013 await ioManager.WriteAllBytes(
1014 userConfigFileName,
1015 configBytes,
1016 cancellationToken);
1017 }
1018 catch (Exception e) when (e is not OperationCanceledException)
1019 {
1020 await console.WriteAsync(e.Message, true, cancellationToken);
1021 await console.WriteAsync(null, true, cancellationToken);
1022 await console.WriteAsync("For your convienence, here's the yaml we tried to write out:", true, cancellationToken);
1023 await console.WriteAsync(null, true, cancellationToken);
1024 await console.WriteAsync(serializedYaml, true, cancellationToken);
1025 await console.WriteAsync(null, true, cancellationToken);
1026 await console.WriteAsync("Press any key to exit...", true, cancellationToken);
1027 await console.PressAnyKeyAsync(cancellationToken);
1028 throw new OperationCanceledException();
1029 }
1030 }
const string Section
The key for the Microsoft.Extensions.Configuration.IConfigurationSection the ControlPanelConfiguratio...
const string Section
The key for the Microsoft.Extensions.Configuration.IConfigurationSection the DatabaseConfiguration re...
const string Section
The key for the Microsoft.Extensions.Configuration.IConfigurationSection the ElasticsearchConfigurati...
const string Section
The key for the Microsoft.Extensions.Configuration.IConfigurationSection the FileLoggingConfiguration...
const string Section
The key for the Microsoft.Extensions.Configuration.IConfigurationSection the GeneralConfiguration res...
static readonly Version CurrentConfigVersion
The current ConfigVersion.
const ushort DefaultApiPort
The default value of ApiPort.
const string Section
The key for the Microsoft.Extensions.Configuration.IConfigurationSection the SwarmConfiguration resid...
JsonConverter and IYamlTypeConverter for serializing global::System.Versions in semver format.

References Tgstation.Server.Host.Configuration.GeneralConfiguration.CurrentConfigVersion, Tgstation.Server.Host.Configuration.GeneralConfiguration.DefaultApiPort, Tgstation.Server.Host.Configuration.ControlPanelConfiguration.Section, Tgstation.Server.Host.Configuration.DatabaseConfiguration.Section, Tgstation.Server.Host.Configuration.ElasticsearchConfiguration.Section, Tgstation.Server.Host.Configuration.FileLoggingConfiguration.Section, Tgstation.Server.Host.Configuration.GeneralConfiguration.Section, and Tgstation.Server.Host.Configuration.SwarmConfiguration.Section.

Referenced by CheckRunWizard(), and RunWizard().

Here is the caller graph for this function: