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 "Control.h" 13 : 14 : #include "WebServerControlTypeRegistry.h" 15 : 16 : #include "tinyhttp/http.h" 17 : 18 : #include <atomic> 19 : #include <memory> 20 : #include <thread> 21 : 22 : /** 23 : * Starts a webserver that an external process can connect to 24 : * in order to send JSON messages to control the solve 25 : */ 26 : class WebServerControl : public Control 27 : { 28 : public: 29 : static InputParameters validParams(); 30 : 31 : WebServerControl(const InputParameters & parameters); 32 : ~WebServerControl(); 33 : 34 : virtual void execute() override; 35 : 36 : /** 37 : * @return A string representation of \p json_type 38 : */ 39 : static std::string stringifyJSONType(const miniJson::JsonType & json_type); 40 : 41 : /** 42 : * @return A c++ representation of the scalar value of \p json_value with 43 : * the given expected json type 44 : */ 45 : template <typename T, miniJson::JsonType json_type> 46 : static T getScalarJSONValue(const miniJson::Json & json_value); 47 : 48 : using ValueBase = Moose::WebServerControlTypeRegistry::ValueBase; 49 : 50 : /** 51 : * Base class for a controllable value with a given type and name 52 : */ 53 : template <typename T> 54 : class TypedValueBase : public ValueBase 55 : { 56 : public: 57 56 : TypedValueBase(const std::string & name, const std::string & type) : ValueBase(name, type) {} 58 112 : TypedValueBase(const std::string & name, const std::string & type, const T & value) 59 112 : : ValueBase(name, type), _value(value) 60 : { 61 112 : } 62 : 63 : /** 64 : * @return The underlying value 65 : */ 66 168 : const T & value() const { return _value; } 67 : 68 168 : virtual void setControllableValue(WebServerControl & control) override final 69 : { 70 168 : control.comm().broadcast(_value); 71 168 : control.setControllableValueByName<T>(name(), value()); 72 168 : } 73 : 74 : private: 75 : /// The underlying value 76 : T _value; 77 : }; 78 : 79 : /** 80 : * Class that stores a scalar controllable value to be set 81 : */ 82 : template <typename T, miniJson::JsonType json_type> 83 : class ScalarValue : public TypedValueBase<T> 84 : { 85 : public: 86 38 : ScalarValue(const std::string & name, const std::string & type) : TypedValueBase<T>(name, type) 87 : { 88 38 : } 89 70 : ScalarValue(const std::string & name, 90 : const std::string & type, 91 : const miniJson::Json & json_value) 92 70 : : TypedValueBase<T>(name, type, getScalarJSONValue<T, json_type>(json_value)) 93 : { 94 70 : } 95 : }; 96 : 97 : /** 98 : * Class that stores a vector controllable value to be set 99 : */ 100 : template <typename T, miniJson::JsonType json_type> 101 : class VectorValue : public TypedValueBase<std::vector<T>> 102 : { 103 : public: 104 18 : VectorValue(const std::string & name, const std::string & type) 105 18 : : TypedValueBase<std::vector<T>>(name, type) 106 : { 107 18 : } 108 42 : VectorValue(const std::string & name, 109 : const std::string & type, 110 : const miniJson::Json & json_value) 111 42 : : TypedValueBase<std::vector<T>>(name, type, getVectorJSONValue(json_value)) 112 : { 113 42 : } 114 : 115 42 : static std::vector<T> getVectorJSONValue(const miniJson::Json & json_value) 116 : { 117 42 : const auto from_json_type = json_value.getType(); 118 42 : if (from_json_type != miniJson::JsonType::kArray) 119 0 : throw ValueBase::Exception("The value '" + json_value.serialize() + "' of type " + 120 : stringifyJSONType(from_json_type) + " is not an array"); 121 : 122 42 : const auto & array_value = json_value.toArray(); 123 42 : std::vector<T> value(array_value.size()); 124 175 : for (const auto i : index_range(array_value)) 125 133 : value[i] = getScalarJSONValue<T, json_type>(array_value[i]); 126 84 : return value; 127 0 : } 128 : }; 129 : 130 : /** 131 : * Registers a scalar parameter type to be controlled 132 : */ 133 : template <typename T, miniJson::JsonType json_type> 134 205504 : static char registerScalarType(const std::string type_name) 135 : { 136 205504 : return Moose::WebServerControlTypeRegistry().add<ScalarValue<T, json_type>>(type_name); 137 : } 138 : /** 139 : * Registers a vector parameter type to be controlled 140 : */ 141 : template <typename T, miniJson::JsonType json_type> 142 154128 : static char registerVectorType(const std::string type_name) 143 : { 144 308256 : return Moose::WebServerControlTypeRegistry().add<VectorValue<T, json_type>>("std::vector<" + 145 308256 : type_name + ">"); 146 : } 147 : 148 : private: 149 : /** 150 : * Internal method for starting the server 151 : */ 152 : void startServer(); 153 : 154 : /** 155 : * @return Whether or not the server is currently waiting 156 : */ 157 140 : bool currentlyWaiting() const { return _currently_waiting.load(); } 158 : 159 : /// Whether or not the Control is currently waiting 160 : std::atomic<bool> _currently_waiting; 161 : 162 : /// The server 163 : std::unique_ptr<HttpServer> _server; 164 : /// The server thread 165 : std::unique_ptr<std::thread> _server_thread; 166 : 167 : /// The values received to control; filled on rank 0 from the server and then broadcast 168 : std::vector<std::unique_ptr<ValueBase>> _controlled_values; 169 : /// Mutex to prevent threaded writes to _controlled_values 170 : std::mutex _controlled_values_mutex; 171 : }; 172 : 173 : template <typename T, miniJson::JsonType json_type> 174 : T 175 203 : WebServerControl::getScalarJSONValue(const miniJson::Json & json_value) 176 : { 177 203 : const auto from_json_type = json_value.getType(); 178 203 : if (from_json_type != json_type) 179 0 : throw ValueBase::Exception("The value " + json_value.serialize() + " of JSON type " + 180 : stringifyJSONType(from_json_type) + 181 : " is not of the expected JSON type " + stringifyJSONType(json_type)); 182 : 183 : if constexpr (json_type == miniJson::JsonType::kBool) 184 56 : return json_value.toBool(); 185 : else if constexpr (json_type == miniJson::JsonType::kNumber) 186 189 : return json_value.toDouble(); 187 : else if constexpr (json_type == miniJson::JsonType::kString) 188 98 : return json_value.toString(); 189 : ::mooseError("WebServerControl::getScalarJSONValue(): Not configured for parsing type ", 190 : stringifyJSONType(from_json_type)); 191 : }