Line data Source code
1 : //* This file is part of the MOOSE framework 2 : //* https://mooseframework.inl.gov 3 : //* 4 : //* All rights reserved, see COPYRIGHT for full restrictions 5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT 6 : //* 7 : //* Licensed under LGPL 2.1, please see LICENSE for details 8 : //* https://www.gnu.org/licenses/lgpl-2.1.html 9 : 10 : #pragma once 11 : 12 : #include <functional> 13 : #include <string> 14 : #include <map> 15 : #include <type_traits> 16 : #include <typeindex> 17 : 18 : #include "nlohmann/json.h" 19 : 20 : #include "MooseError.h" 21 : #include "MooseUtils.h" 22 : 23 : class WebServerControl; 24 : 25 : namespace Moose 26 : { 27 : /** 28 : * A static registry used to register and build values of different types for the WebServerControl 29 : * 30 : * Needed due to the complexities of parsing parameter types from generic JSON received 31 : * by the web server. 32 : */ 33 : class WebServerControlTypeRegistry 34 : { 35 : public: 36 : /** 37 : * @return The WebServerControlTypeRegistry singleton 38 : */ 39 : static WebServerControlTypeRegistry & getRegistry(); 40 : 41 : /** 42 : * The base class for a value that is produced by this registry. 43 : */ 44 : class ControlledValueBase 45 : { 46 : public: 47 : /** 48 : * Constructor. 49 : * @param name The name that the value is for (typically a controllable path) 50 : * @param type The string representationg of the type 51 : */ 52 : ControlledValueBase(const std::string & name, const std::string & type); 53 : 54 190 : virtual ~ControlledValueBase() {} 55 : 56 : /** 57 : * @return The name that the value is for 58 : */ 59 318 : const std::string & name() const { return _name; } 60 : /** 61 : * @return The string representation of the type 62 : */ 63 128 : const std::string & type() const { return _type; } 64 : 65 : /** 66 : * Sets the controllable value given the name and type via the controllable 67 : * interface in \p control. 68 : * 69 : * Will broadcast the value and set it in the derived, type-aware class. 70 : */ 71 : virtual void setControllableValue(WebServerControl & control) = 0; 72 : 73 : private: 74 : /// The name that the value is for 75 : const std::string _name; 76 : /// The string representation of the type 77 : const std::string _type; 78 : }; 79 : 80 : /** 81 : * Base registry class for a type that is used to build values. 82 : */ 83 : class RegisteredTypeBase 84 : { 85 : public: 86 : RegisteredTypeBase(const std::string & type); 87 : 88 0 : virtual ~RegisteredTypeBase() {} 89 : 90 : /** 91 : * @return The string representation of the type 92 : */ 93 190 : const std::string & type() const { return _type; } 94 : /** 95 : * Builds a value with the given type, name \p name, and JSON value \p json_value. 96 : * 97 : * This will be called on receipt of a controllable value on rank 0 in the 98 : * WebServerControl. It will at that point parse the value from JSON and store it. 99 : * Later on during sync, it will be used to broadcast the value and then locally 100 : * set it. 101 : */ 102 : virtual std::unique_ptr<ControlledValueBase> build(const std::string & name, 103 : const nlohmann::json & json_value) const = 0; 104 : /** 105 : * Builds a value with the given type, name \p name, and a default value. 106 : * 107 : * This will be called by the WebServerControl on ranks that are not rank 0. 108 : * It will be used during the sync step, where the value is broadcasted to the 109 : * rest of the ranks and then set locally. 110 : */ 111 : virtual std::unique_ptr<ControlledValueBase> build(const std::string & name) const = 0; 112 : 113 : private: 114 : /// The string representation of the underlying type 115 : const std::string _type; 116 : }; 117 : 118 : /** 119 : * Derived registry item. 120 : * 121 : * Stores how to build the value and how to parse the value from JSON. 122 : * 123 : * @tparam ControlledValue The derived ControlledValueBase class that contains 124 : * the implementation for setting the controllable value 125 : * @tparam ValueType The underlying type of the value to be controlled 126 : */ 127 : template <class ControlledValue, class ValueType> 128 : struct RegisteredType : public RegisteredTypeBase 129 : { 130 458768 : RegisteredType(const std::string & type, 131 : std::function<ValueType(const nlohmann::json &)> && parse_function) 132 458768 : : RegisteredTypeBase(type), _parse_function(parse_function) 133 : { 134 458768 : } 135 : 136 : virtual std::unique_ptr<ControlledValueBase> 137 62 : build(const std::string & name) const override final 138 : { 139 62 : return std::make_unique<ControlledValue>(name, type()); 140 : } 141 : virtual std::unique_ptr<ControlledValueBase> 142 148 : build(const std::string & name, const nlohmann::json & json_value) const override final 143 : { 144 148 : return std::make_unique<ControlledValue>(name, type(), _parse_function(json_value)); 145 : } 146 : 147 : private: 148 : /// Function that converts from json -> the value for the ValueType 149 : const std::function<ValueType(const nlohmann::json &)> _parse_function; 150 : }; 151 : 152 : /** 153 : * Register a type in the registry 154 : * 155 : * @tparam ControlledValue The derived ControlledValueBase class that contains 156 : * the implementation for setting the controllable value 157 : * @tparam ValueType The underlying type of the value to be controlled 158 : * @param type_name Human readable name for the type of the value to be controlled 159 : * @param parse_function Function used to parse the value from JSON 160 : */ 161 : template <class ControlledValue, class ValueType> 162 : static char add(const std::string & type_name, 163 : std::function<ValueType(const nlohmann::json &)> && parse_function); 164 : 165 : /** 166 : * Query the registration for the given type. 167 : */ 168 : static const RegisteredTypeBase * query(const std::string & type); 169 : 170 : /** 171 : * Get the registration for the given type, erroring if it isn't registered. 172 : */ 173 : static const RegisteredTypeBase & get(const std::string & type); 174 : 175 : private: 176 : /// The registration data 177 : std::map<std::string, std::unique_ptr<RegisteredTypeBase>> _name_map; 178 : /// The registered value types, to avoid registering the same underlying 179 : /// value type multiple times 180 : std::set<std::type_index> _value_types; 181 : }; 182 : 183 : template <class ControlledValue, class ValueType> 184 : char 185 458768 : WebServerControlTypeRegistry::add( 186 : const std::string & type_name, 187 : std::function<ValueType(const nlohmann::json &)> && parse_function) 188 : { 189 : static_assert(std::is_base_of_v<ControlledValueBase, ControlledValue>, 190 : "Is not derived from ControlledValueBase"); 191 : static_assert(std::is_same_v<typename ControlledValue::value_type, ValueType>, "Is not the same"); 192 : 193 458768 : auto entry = std::make_unique<RegisteredType<ControlledValue, ValueType>>( 194 458768 : type_name, std::move(parse_function)); 195 458768 : if (!getRegistry()._name_map.emplace(type_name, std::move(entry)).second) 196 0 : ::mooseError( 197 : "WebServerControlTypeRegistry: The string type \"", type_name, "\" is already registered."); 198 : 199 458768 : static const std::type_index index = typeid(ValueType); 200 458768 : if (!getRegistry()._value_types.insert(index).second) 201 0 : ::mooseError("WebServerControlRegistry: The type \"", 202 : MooseUtils::prettyCppType<ValueType>(), 203 : "\" is already registered"); 204 458768 : return 0; 205 458768 : } 206 : }