Skip to content

Commit

Permalink
Merge pull request #329 from microsoft/serverapattrs
Browse files Browse the repository at this point in the history
Allow specifying JSON configuration to netremote-server on command-line
  • Loading branch information
abeltrano authored Jul 30, 2024
2 parents ebc50e5 + 6544025 commit bf81dee
Show file tree
Hide file tree
Showing 24 changed files with 464 additions and 119 deletions.
20 changes: 18 additions & 2 deletions src/common/net/wifi/apmanager/AccessPointManager.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@

using namespace Microsoft::Net::Wifi;

AccessPointManager::AccessPointManager(std::unordered_map<std::string, AccessPointAttributes> accessPointAttributes) :
m_accessPointAttributes{ std::move(accessPointAttributes) }
{}

/* static */
std::shared_ptr<AccessPointManager>
AccessPointManager::Create()
AccessPointManager::Create(std::unordered_map<std::string, AccessPointAttributes> accessPointAttributes)
{
return std::make_shared<notstd::enable_make_protected<AccessPointManager>>();
return std::make_shared<notstd::enable_make_protected<AccessPointManager>>(std::move(accessPointAttributes));
}

std::shared_ptr<AccessPointManager>
Expand Down Expand Up @@ -119,6 +123,18 @@ AccessPointManager::GetAllAccessPoints() const
return accessPoints;
}

std::optional<AccessPointAttributes>
AccessPointManager::GetAccessPointAttributes(const std::string& interfaceName) const
{
auto accessPointAttributesIterator = m_accessPointAttributes.find(interfaceName);
if (accessPointAttributesIterator == std::cend(m_accessPointAttributes)) {
return std::nullopt;
}

auto [_, accessPointAttributes] = *accessPointAttributesIterator;
return accessPointAttributes;
}

void
AccessPointManager::AddDiscoveryAgent(std::shared_ptr<AccessPointDiscoveryAgent> discoveryAgent)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ struct AccessPointDiscoveryAgent :
RegisterDiscoveryEventCallback(AccessPointPresenceEventCallback onDevicePresenceChanged);

/**
* @brief indicates the started/running state.
* @brief Indicates the started/running state.
*
* @return true
* @return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
#include <mutex>
#include <optional>
#include <shared_mutex>
#include <string>
#include <unordered_map>
#include <vector>

#include <microsoft/net/wifi/AccessPointAttributes.hxx>

namespace Microsoft::Net::Wifi
{
struct IAccessPoint;
Expand All @@ -30,11 +34,11 @@ public:
/**
* @brief Safely create an instance of the access point manager.
*
* @param accessPointFactory
* @param accessPointAttributes The static attributes of the access points to manage.
* @return std::shared_ptr<AccessPointManager>
*/
[[nodiscard]] static std::shared_ptr<AccessPointManager>
Create();
Create(std::unordered_map<std::string, AccessPointAttributes> accessPointAttributes = {});

/**
* @brief Get an instance of this access point manager.
Expand Down Expand Up @@ -75,6 +79,15 @@ public:
std::vector<std::weak_ptr<IAccessPoint>>
GetAllAccessPoints() const;

/**
* @brief Get the attributes of the access point with the specified interface name.
*
* @param interfaceName The interface name of the access point to get attributes for.
* @return std::optional<AccessPointAttributes>
*/
std::optional<AccessPointAttributes>
GetAccessPointAttributes(const std::string& interfaceName) const;

virtual ~AccessPointManager() = default;
AccessPointManager(const AccessPointManager&) = delete;
AccessPointManager(AccessPointManager&&) = delete;
Expand All @@ -86,8 +99,10 @@ public:
protected:
/**
* @brief Construct a new AccessPointManager object.
*
* @param accessPointAttributes The static attributes of the access points to manage.
*/
AccessPointManager() = default;
AccessPointManager(std::unordered_map<std::string, AccessPointAttributes> accessPointAttributes = {});

/**
* @brief Callback function for all access point agent presence change events.
Expand Down Expand Up @@ -123,6 +138,7 @@ private:

mutable std::shared_mutex m_discoveryAgentsGate;
std::vector<std::shared_ptr<AccessPointDiscoveryAgent>> m_discoveryAgents;
std::unordered_map<std::string, AccessPointAttributes> m_accessPointAttributes{};
};

} // namespace Microsoft::Net::Wifi
Expand Down
12 changes: 4 additions & 8 deletions src/common/net/wifi/core/AccessPoint.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,9 @@ AccessPointFactory::GetControllerFactory() const noexcept
}

std::shared_ptr<IAccessPoint>
AccessPointFactory::Create(std::string_view interfaceName)
AccessPointFactory::Create(std::string_view interfaceName, std::unique_ptr<IAccessPointCreateArgs> accessPointCreateArgs)
{
return Create(interfaceName, nullptr);
}

std::shared_ptr<IAccessPoint>
AccessPointFactory::Create(std::string_view interfaceName, [[maybe_unused]] std::unique_ptr<IAccessPointCreateArgs> accessPointCreateArgs)
{
return std::make_shared<AccessPoint>(interfaceName, GetControllerFactory());
return (accessPointCreateArgs == nullptr)
? std::make_shared<AccessPoint>(interfaceName, GetControllerFactory())
: std::make_shared<AccessPoint>(interfaceName, GetControllerFactory(), std::move(accessPointCreateArgs->Attributes));
}
3 changes: 1 addition & 2 deletions src/common/net/wifi/core/AccessPointAttributes.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
#include <unordered_map>

#include <microsoft/net/wifi/AccessPointAttributes.hxx>

#include "AccessPointAttributesJsonSerialization.hxx"
#include <microsoft/net/wifi/AccessPointAttributesJsonSerialization.hxx>

using namespace Microsoft::Net::Wifi;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@

#include <microsoft/net/wifi/AccessPointAttributes.hxx>
#include <microsoft/net/wifi/AccessPointAttributesJsonSerialization.hxx>
#include <nlohmann/json.hpp>

#include "AccessPointAttributesJsonSerialization.hxx"

namespace Microsoft::Net::Wifi
{
void
Expand Down
4 changes: 2 additions & 2 deletions src/common/net/wifi/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ target_sources(wifi-core
AccessPoint.cxx
AccessPointAttributes.cxx
AccessPointAttributesJsonSerialization.cxx
AccessPointAttributesJsonSerialization.hxx
AccessPointController.cxx
AccessPointOperationStatus.cxx
AccessPointOperationStatusLogOnExit.cxx
Expand All @@ -23,6 +22,7 @@ target_sources(wifi-core
FILES
${WIFI_CORE_PUBLIC_INCLUDE_PREFIX}/AccessPoint.hxx
${WIFI_CORE_PUBLIC_INCLUDE_PREFIX}/AccessPointAttributes.hxx
${WIFI_CORE_PUBLIC_INCLUDE_PREFIX}/AccessPointAttributesJsonSerialization.hxx
${WIFI_CORE_PUBLIC_INCLUDE_PREFIX}/AccessPointController.hxx
${WIFI_CORE_PUBLIC_INCLUDE_PREFIX}/AccessPointOperationStatus.hxx
${WIFI_CORE_PUBLIC_INCLUDE_PREFIX}/AccessPointOperationStatusLogOnExit.hxx
Expand All @@ -37,11 +37,11 @@ target_sources(wifi-core
target_link_libraries(wifi-core
PRIVATE
magic_enum::magic_enum
nlohmann_json::nlohmann_json
notstd
strings
PUBLIC
${PROJECT_NAME}-net
nlohmann_json::nlohmann_json
plog::plog
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,6 @@ struct AccessPointFactory :
*/
AccessPointFactory(std::shared_ptr<IAccessPointControllerFactory> accessPointControllerFactory);

/**
* @brief Create a new access point object for the given network interface.
*
* @param interfaceName
* @return std::shared_ptr<IAccessPoint>
*/
virtual std::shared_ptr<IAccessPoint>
Create(std::string_view interfaceName) override;

/**
* @brief Create a new access point object for the given network interface with the specified creation arguments.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ namespace Microsoft::Net::Wifi
*/
struct AccessPointAttributes
{
std::unordered_map<std::string, std::string> Properties{};

bool
operator==(const AccessPointAttributes&) const = default;

/**
* @brief Attempt to deserialize a JSON string into a map of access point attributes.
*
Expand All @@ -31,8 +36,6 @@ struct AccessPointAttributes
*/
static std::optional<std::unordered_map<std::string, AccessPointAttributes>>
TryParseJson(std::istream& json);

std::unordered_map<std::string, std::string> Properties{};
};
} // namespace Microsoft::Net::Wifi

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,6 @@ struct IAccessPointFactory
IAccessPointFactory&
operator=(IAccessPointFactory&&) = delete;

/**
* @brief Create a new access point object for the given network interface.
*
* @param interfaceName The name of the interface.
* @return std::shared_ptr<IAccessPoint>
*/
virtual std::shared_ptr<IAccessPoint>
Create(std::string_view interfaceName) = 0;

/**
* @brief Create a new access point object for the given network interface with the specified creation arguments.
*
Expand All @@ -137,7 +128,7 @@ struct IAccessPointFactory
* @return std::shared_ptr<IAccessPoint>
*/
virtual std::shared_ptr<IAccessPoint>
Create(std::string_view interfaceName, std::unique_ptr<IAccessPointCreateArgs> createArgs) = 0;
Create(std::string_view interfaceName, std::unique_ptr<IAccessPointCreateArgs> createArgs = nullptr) = 0;
};
} // namespace Microsoft::Net::Wifi

Expand Down
3 changes: 3 additions & 0 deletions src/common/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ target_sources(${PROJECT_NAME}-server
PRIVATE
NetRemoteServer.cxx
NetRemoteServerConfiguration.cxx
NetRemoteServerJsonConfiguration.cxx
PUBLIC
FILE_SET HEADERS
BASE_DIRS ${NET_REMOTE_SERVER_PUBLIC_INCLUDE}
FILES
${NET_REMOTE_SERVER_PUBLIC_INCLUDE_PREFIX}/NetRemoteServer.hxx
${NET_REMOTE_SERVER_PUBLIC_INCLUDE_PREFIX}/NetRemoteServerConfiguration.hxx
${NET_REMOTE_SERVER_PUBLIC_INCLUDE_PREFIX}/NetRemoteServerJsonConfiguration.hxx
)

target_link_libraries(${PROJECT_NAME}-server
Expand All @@ -23,6 +25,7 @@ target_link_libraries(${PROJECT_NAME}-server
${PROJECT_NAME}-service
PRIVATE
CLI11::CLI11
nlohmann_json::nlohmann_json
plog::plog
)

Expand Down
37 changes: 32 additions & 5 deletions src/common/server/NetRemoteServerConfiguration.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include <CLI/Error.hpp>
#include <CLI/Formatter.hpp>
#include <microsoft/net/remote/service/NetRemoteServerConfiguration.hxx>
#include <microsoft/net/remote/service/NetRemoteServerJsonConfiguration.hxx>
#include <plog/Log.h>

using namespace Microsoft::Net::Remote::Service;

Expand All @@ -26,17 +28,22 @@ ConfigureCliAppOptions(CLI::App& app, NetRemoteServerConfiguration& config)
config.ServerAddress,
"The address to listen on for incoming connections");

app.add_flag(
"--enable-file-logging",
config.EnableFileLogging,
"Enable logging to file (disabled by default)");

app.add_option(
"-c,--config,--configuration,--configurationFile,--json,--jsonConfig,--jsonConfiguration--jsonConfigurationFile",
config.JsonConfigurationFilePath,
"The path to the JSON configuration file");

app.add_flag(
"-v,--verbosity",
config.LogVerbosity,
"The log verbosity level. Supply multiple times to increase verbosity (0=fatal, 1=errors, 2=warnings, 3=info, 4=debug, 5+=verbose)")
->default_val(NetRemoteServerConfiguration::LogVerbosityDefault);

app.add_flag(
"--enable-file-logging",
config.EnableFileLogging,
"Enable logging to file (disabled by default)");

return app;
}

Expand All @@ -56,6 +63,26 @@ ParseCliAppOptions(bool throwOnParseError, Args&&... args)
}
}

// If optional JSON configuration was specified, parse it. While optional, if specified, it must be valid.
if (!std::empty(configuration.JsonConfigurationFilePath)) {
const auto configurationJsonObject = NetRemoteServerJsonConfiguration::ParseFromFile(configuration.JsonConfigurationFilePath);
if (!configurationJsonObject.has_value()) {
LOGF << "Failed to parse JSON configuration file";
return {};
}

const auto configurationJson = NetRemoteServerJsonConfiguration::TryParseFromJson(configurationJsonObject.value());
if (!configurationJsonObject.has_value()) {
LOGF << "Failed to parse JSON configuration";
return {};
}

// If optional fields are specified in the JSON configuration, populate the configuration object with them.
if (configurationJson->AccessPointAttributes.has_value()) {
configuration.AccessPointAttributes = std::move(configurationJson->AccessPointAttributes.value());
}
}

return configuration;
}

Expand Down
60 changes: 60 additions & 0 deletions src/common/server/NetRemoteServerJsonConfiguration.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@

#include <filesystem>
#include <format>
#include <fstream>
#include <optional>

#include <microsoft/net/remote/service/NetRemoteServerJsonConfiguration.hxx>
#include <microsoft/net/wifi/AccessPointAttributesJsonSerialization.hxx>
#include <nlohmann/json.hpp>
#include <plog/Log.h>

using namespace Microsoft::Net::Remote::Service;

/* static */
std::optional<nlohmann::json>
NetRemoteServerJsonConfiguration::ParseFromFile(const std::filesystem::path& configurationFilePath) noexcept
{
std::ifstream configurationFileStream{ configurationFilePath };
nlohmann::json configurationJson;

try {
configurationJson = nlohmann::json::parse(configurationFileStream);
} catch (const nlohmann::json::parse_error& parseError) {
LOGE << std::format("Failed to parse JSON configuration file '{}' ({})", configurationFilePath.string(), parseError.what());
return std::nullopt;
}

LOGD << std::format("Successfully parsed JSON configuration file '{}'\n{}", configurationFilePath.string(), configurationJson.dump(2));

return configurationJson;
}

/* static */
std::optional<NetRemoteServerJsonConfiguration>
NetRemoteServerJsonConfiguration::TryParseFromJson(const nlohmann::json& configurationJson) noexcept
{
using Microsoft::Net::Wifi::AccessPointAttributes;

NetRemoteServerJsonConfiguration configuration{};

// Parse access point attributes, if specified.
if (configurationJson.contains(AccessPointAttributesKey)) {
try {
auto accessPointAttributesJson = configurationJson.at(AccessPointAttributesKey);
if (!accessPointAttributesJson.is_object()) {
LOGE << std::format("JSON configuration '{}' is not an object", AccessPointAttributesKey);
return std::nullopt;
}

std::unordered_map<std::string, AccessPointAttributes> accessPointAttributes{};
accessPointAttributesJson.get_to(accessPointAttributes);
configuration.AccessPointAttributes = std::move(accessPointAttributes);
} catch (const nlohmann::json::exception& jsonException) {
LOGE << std::format("Failed to parse JSON configuration for '{}' field: {}", AccessPointAttributesKey, jsonException.what());
return std::nullopt;
}
}

return configuration;
}
Loading

0 comments on commit bf81dee

Please sign in to comment.