master
h 202 lines 7 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 WSLCUserSettings.h
8
9 Abstract:
10
11 Declaration of UserSettings — the singleton that loads, validates, and
12 provides access to the wslc user settings file.
13
14 --*/
15 #pragma once
16 #include "defs.h"
17 #include "EnumVariantMap.h"
18 #include "WSLCSessionDefaults.h"
19 #include "wslc.h"
20 #include <cstdint>
21 #include <filesystem>
22 #include <optional>
23 #include <string>
24 #include <string_view>
25 #include <vector>
26
27 // How to add a setting:
28 // 1 - Add an entry to the Setting enum.
29 // 2 - Add a DEFINE_SETTING_MAPPING specialization with yaml_t, value_t, default, and YAML path.
30 // 3 - Implement the Validate function in UserSettings.cpp if needed, otherwise use pass through.
31
32 namespace wsl::windows::wslc::settings {
33
34 // Enum of all user settings.
35 // Must start at 0 to enable direct variant indexing.
36 // Max must be last and unused.
37 enum class Setting : size_t
38 {
39 SessionCpuCount = 0,
40 SessionMemoryMb,
41 SessionStorageSizeMb,
42 SessionNetworkingMode,
43 SessionHostFileShareMode,
44 SessionDnsTunneling,
45 SessionHostLoopback,
46 CredentialStore,
47 SessionPortRelay,
48 SessionDefaultBindingAddress,
49 SessionStoragePath,
50 SessionIdleTimeout,
51
52 Max
53 };
54
55 enum class HostFileShareMode
56 {
57 Plan9,
58 VirtioFs
59 };
60
61 enum class CredentialStoreType
62 {
63 WinCred,
64 File
65 };
66
67 enum class PortRelayType
68 {
69 VirtioNet,
70 WslRelay
71 };
72
73 namespace details {
74
75 template <Setting S>
76 struct SettingMapping
77 {
78 // yaml_t - the C++ type read from the YAML node via node.as<yaml_t>()
79 // value_t - the native type stored in SettingsMap
80 // DefaultValue - used when the key is absent or fails validation
81 // YamlPath - dot-separated path into the YAML document (e.g. "session.cpuCount")
82 // Validate - semantic validation; returns nullopt to reject and fall back to default
83 };
84
85 // clang-format off
86 #define DEFINE_SETTING_MAPPING(_setting_, _yaml_t_, _value_t_, _default_, _path_) \
87 template <> \
88 struct SettingMapping<Setting::_setting_> \
89 { \
90 using yaml_t = _yaml_t_; \
91 using value_t = _value_t_; \
92 inline static const value_t DefaultValue = _default_; \
93 static constexpr std::string_view YamlPath = _path_; \
94 static std::optional<value_t> Validate(const yaml_t& value); \
95 };
96
97 DEFINE_SETTING_MAPPING(SessionCpuCount, uint32_t, uint32_t, 0, "session.cpuCount")
98 DEFINE_SETTING_MAPPING(SessionMemoryMb, std::string, uint32_t, 0, "session.memorySize")
99 DEFINE_SETTING_MAPPING(SessionStorageSizeMb, std::string, uint32_t, 1048576, "session.maxStorageSize")
100 DEFINE_SETTING_MAPPING(SessionNetworkingMode, std::string, WSLCNetworkingMode, WSLCNetworkingModeConsomme, "session.networkingMode")
101 DEFINE_SETTING_MAPPING(SessionHostFileShareMode, std::string, HostFileShareMode, HostFileShareMode::VirtioFs, "session.hostFileShareMode")
102 DEFINE_SETTING_MAPPING(SessionDnsTunneling, bool, bool, true, "session.dnsTunneling")
103 DEFINE_SETTING_MAPPING(SessionHostLoopback, std::string, std::string, DefaultHostLoopback, "session.hostLoopback")
104 DEFINE_SETTING_MAPPING(CredentialStore, std::string, CredentialStoreType, CredentialStoreType::WinCred, "credentialStore")
105 DEFINE_SETTING_MAPPING(SessionPortRelay, std::string, PortRelayType, PortRelayType::VirtioNet, "experimental.portRelay")
106 DEFINE_SETTING_MAPPING(SessionDefaultBindingAddress, std::string, std::string, std::string{}, "session.defaultBindingAddress")
107 DEFINE_SETTING_MAPPING(SessionStoragePath, std::string, std::string, std::string{}, "session.storagePath")
108 DEFINE_SETTING_MAPPING(SessionIdleTimeout, uint32_t, uint32_t, 30, "session.idleTimeout")
109
110 #undef DEFINE_SETTING_MAPPING
111 // clang-format on
112
113 } // namespace details
114
115 // Type-safe enum-indexed map of all settings values, backed by EnumBasedVariantMap.
116 struct SettingsMap : wsl::windows::wslc::EnumBasedVariantMap<Setting, details::SettingMapping>
117 {
118 // Returns the stored value if present, otherwise the compile-time default.
119 template <Setting S>
120 typename details::SettingMapping<S>::value_t GetOrDefault() const
121 {
122 if (Contains(S))
123 {
124 return Get<S>();
125 }
126 return details::SettingMapping<S>::DefaultValue;
127 }
128 };
129
130 // Indicates which source the settings were loaded from.
131 enum class UserSettingsType
132 {
133 Default, // Settings file did not exist or failed to parse; built-in defaults are used.
134 Standard, // Settings file (settings.yaml) loaded successfully.
135 };
136
137 struct Warning
138 {
139 std::wstring Message;
140 std::wstring SettingPath; // Empty for file-level warnings; key path for per-field warnings.
141 };
142
143 // Singleton that owns the parsed settings for the current process lifetime.
144 // Load order:
145 // 1. settings.yaml (Standard)
146 // 2. Built-in defaults (Default, if the file is absent or fails to parse)
147 class UserSettings
148 {
149 public:
150 // Returns the singleton instance. Loaded on first call; subsequent calls are no-ops.
151 static UserSettings const& Instance();
152
153 NON_COPYABLE(UserSettings);
154 NON_MOVABLE(UserSettings);
155
156 // Returns the value for setting S, or its built-in default if not present in the file.
157 template <Setting S>
158 typename details::SettingMapping<S>::value_t Get() const
159 {
160 return m_settings.GetOrDefault<S>();
161 }
162
163 std::vector<Warning> const& GetWarnings() const
164 {
165 return m_warnings;
166 }
167
168 UserSettingsType GetType() const
169 {
170 return m_type;
171 }
172
173 // Called before opening the settings file in an editor.
174 // If type is Default, creates the file from the commented-out defaults template.
175 void PrepareToShellExecuteFile() const;
176
177 std::filesystem::path SettingsFilePath() const;
178
179 // Overwrites the settings file with the commented-out defaults template.
180 void Reset() const;
181
182 // Loads settings from an explicit directory.
183 explicit UserSettings(const std::filesystem::path& settingsDir);
184 ~UserSettings() = default;
185
186 private:
187 UserSettings();
188
189 SettingsMap m_settings;
190 std::vector<Warning> m_warnings;
191 UserSettingsType m_type = UserSettingsType::Default;
192 std::filesystem::path m_settingsPath;
193 };
194
195 // Convenience free function — returns the singleton instance.
196 // Usage: settings::User().Get<Setting::Foo>()
197 inline UserSettings const& User()
198 {
199 return UserSettings::Instance();
200 }
201
202 } // namespace wsl::windows::wslc::settings