LCOV - code coverage report
Current view: top level - include/controls - WebServerControl.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 8601ad Lines: 40 43 93.0 %
Date: 2025-07-18 13:27:08 Functions: 57 57 100.0 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.14