https://mooseframework.inl.gov
Loading...
Searching...
No Matches
WebServerControl.h
Go to the documentation of this file.
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 <atomic>
15#include <memory>
16#include <thread>
17
19
21class HttpServer;
22
28{
29public:
31
34
41
42 virtual void execute() override final;
43
45
56 template <class T>
58 {
59 public:
60 ControlledValue(const std::string & name, const std::string & type)
62 {
63 }
64 ControlledValue(const std::string & name, const std::string & type, const T & value)
66 {
67 }
68
70 using value_type = T;
71
72 virtual void setControllableValue(WebServerControl & control) override final
73 {
74 control.comm().broadcast(_value);
75 control.setControllableValueByName<T>(name(), _value);
76 }
77
78 private:
81 };
82
83protected:
87 enum class RequestMethod
88 {
89 GET,
90 POST
91 };
92
96 struct Request
97 {
98 Request() = default;
99
103 bool hasJSON() const { return _json.has_value(); }
104
108 const nlohmann::json & getJSON() const;
109
113 void setJSON(const nlohmann::json & json, const Moose::PassKey<WebServerControl>)
114 {
115 _json = json;
116 }
117
118 private:
120 std::optional<nlohmann::json> _json;
121 };
122
126 struct Response
127 {
128 Response() = default;
129
133 Response(const unsigned int status_code);
137 Response(const unsigned int status_code, const nlohmann::json & json);
138
142 unsigned int getStatusCode() const { return _status_code; }
143
147 bool hasJSON() const { return _json.has_value(); }
151 const nlohmann::json & getJSON() const;
152
156 bool hasError() const { return _error.has_value(); }
160 const std::string & getError() const;
161
162 protected:
166 void setError(const std::string & error) { _error = error; }
167
168 private:
170 unsigned int _status_code = 0;
172 std::optional<nlohmann::json> _json;
174 std::optional<std::string> _error;
175 };
176
180 struct ErrorResponse : public Response
181 {
182 ErrorResponse(const std::string & error, const unsigned int status_code = 400);
183 };
184
189 {
191
195 bool getRequireWaiting() const { return _require_waiting; }
200 {
201 _require_waiting = value;
202 }
203
212 {
213 _require_initialized = value;
214 }
215
219 const std::set<std::string> getRequiredJSONKeys() const { return _required_json_keys; }
223 void requireJSONKey(const std::string & key) { _required_json_keys.insert(key); }
227 void requireJSONKeys(std::initializer_list<std::string> && keys)
228 {
229 _required_json_keys.insert(keys);
230 }
231
232 private:
238 std::set<std::string> _required_json_keys;
239 };
240
248 template <RequestMethod method>
249 void addServerAction(const std::string & path,
250 std::function<Response(const Request &, WebServerControl &)> && action,
251 const ServerActionOptions & options = {});
252
256 virtual void addServerActions() {}
257
263 template <class value_T, class key_T>
264 static value_T convertJSON(const nlohmann::json & json_value, const key_T & key);
265
269 bool isCurrentlyWaiting() const { return _currently_waiting.load(); }
270
275 {
277 std::string name;
279 std::string host;
281 std::string user;
283 nlohmann::json data;
284 };
285
290
294 void outputMessage(const std::string & message) const;
295
296private:
304
308 void setClientInfo(const ClientInfo & info);
309
313 void clientPoke();
314
318 bool isClientInitialized() const { return _client_initialized.load(); }
323
327 void setCurrentlyWaiting(const bool value = true) { _currently_waiting.store(value); }
328
332 bool isTerminateRequested() const { return _terminate_requested.load(); }
336 void setTerminateRequested(const bool value = true) { _terminate_requested.store(value); }
337
341 bool isKillRequested() const { return _kill_requested.load(); }
345 void setKillRequested() { _kill_requested.store(true); }
346
350 void outputClientTiming(const std::string & message,
351 const std::chrono::time_point<std::chrono::steady_clock> & start) const;
352
358 std::string clientTimeoutErrorMessage(const Real timeout,
359 const std::string & timeout_param_name,
360 const std::optional<std::string> & suffix = {}) const;
361
365 void stopServer();
366
368 const unsigned int * const _port;
370 const FileName * const _file_socket;
374 const Real _client_timeout;
375
377 std::atomic<bool> _client_initialized = false;
379 std::atomic<bool> _currently_waiting = false;
381 std::atomic<bool> _terminate_requested = false;
383 std::atomic<bool> _kill_requested = false;
385 std::atomic<int64_t> _last_client_poke = 0;
386
388 std::optional<ClientInfo> _client_info;
390 mutable std::mutex _client_info_lock;
391
393 std::weak_ptr<HttpServer> _server_weak_ptr;
395 std::unique_ptr<std::thread> _server_thread_ptr;
396
398 std::vector<std::unique_ptr<ControlledValueBase>> _controlled_values;
401};
402
403template <class value_T, class key_T>
404value_T
405WebServerControl::convertJSON(const nlohmann::json & json_value, const key_T & key)
406{
407 try
408 {
409 return json_value[key].template get<value_T>();
410 }
411 catch (const std::exception & e)
412 {
413 std::ostringstream message;
414 message << "While parsing '" << key << "' " << e.what();
415 throw std::runtime_error(message.str());
416 }
417}
Base class for Control objects.
Definition Control.h:44
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
const InputParameters & parameters() const
Get the parameters of the object.
Definition MooseBase.h:131
The base class for a value that is produced by this registry.
Starts the web server(s) for the WebServerControl objects.
Class containing a value to be controlled.
T value_type
The underlying type of the value.
ControlledValue(const std::string &name, const std::string &type)
virtual void setControllableValue(WebServerControl &control) override final
Sets the controllable value given the name and type via the controllable interface in control.
ControlledValue(const std::string &name, const std::string &type, const T &value)
Starts a webserver that an external process can connect to in order to send JSON messages to control ...
std::atomic< bool > _terminate_requested
Whether or not the solve should be terminated in the next execute() call.
const Real _client_timeout
Time in seconds to allow the client to communicate after init before timing out.
void addServerAction(const std::string &path, std::function< Response(const Request &, WebServerControl &)> &&action, const ServerActionOptions &options={})
Adds an action for the server to perform at the given path.
virtual void addServerActions()
Entrypoint for controls derived from this one to add additional actions.
void setClientInitialized()
Set that the client has called /initialized; used by the server.
void setKillRequested()
Set for the control to kill the solve; used by /kill in the server.
void addServerActionsInternal()
Adds the internal actions to the server.
virtual void execute() override final
Execute the control.
bool isKillRequested() const
Get whether or not the client sent the kill command.
static InputParameters validParams()
std::atomic< bool > _currently_waiting
Whether or not the Control is currently waiting.
std::weak_ptr< HttpServer > _server_weak_ptr
Weak pointer to the server; the server itself is owned by the server thread.
std::atomic< int64_t > _last_client_poke
The most recent time we've heard from the client.
bool isTerminateRequested() const
Whether or not the client has called /terminate.
std::string clientTimeoutErrorMessage(const Real timeout, const std::string &timeout_param_name, const std::optional< std::string > &suffix={}) const
Helper for producing an error message about a client timeout.
bool isCurrentlyWaiting() const
Get whether or not the control is currently waiting.
void clientPoke()
Store a client's poke, which is a timing used to determine the client timeout.
std::atomic< bool > _kill_requested
Whether or not the client has called /kill.
std::mutex _client_info_lock
Lock for _client_info as it is written by the server thread.
ClientInfo getClientInfo() const
Get the information sent by the client on initialize.
static value_T convertJSON(const nlohmann::json &json_value, const key_T &key)
Helper for converting a value to JSON for the given key.
RequestMethod
Define the valid methods for a client request.
const unsigned int *const _port
Port to listen on, if any.
const FileName *const _file_socket
File socket to listen on, if any.
std::unique_ptr< std::thread > _server_thread_ptr
The server thread.
std::vector< std::unique_ptr< ControlledValueBase > > _controlled_values
The values received to control; filled on rank 0 from the server and then broadcast.
std::atomic< bool > _client_initialized
Whether or not the client has called /initialize.
void setCurrentlyWaiting(const bool value=true)
Set that the control is currently waiting; used by the server.
void stopServer()
Stop the server if it exists and is running.
void setClientInfo(const ClientInfo &info)
Set the ClientInfo object received from the client during /initialize.
void startServer(const Moose::PassKey< StartWebServerControlAction >)
Start the server.
void outputMessage(const std::string &message) const
Output a message with the prefix of this control type and name.
bool isClientInitialized() const
Whether or not the client has called /initialize.
std::optional< ClientInfo > _client_info
Client information received on /initialize by the server.
const Real _initial_client_timeout
Time in seconds to allow the client to initially communicate before timing out.
std::mutex _controlled_values_mutex
Mutex to prevent threaded writes to _controlled_values.
void setTerminateRequested(const bool value=true)
Set for the control to terminate the solve; used by /terminate in the server.
void outputClientTiming(const std::string &message, const std::chrono::time_point< std::chrono::steady_clock > &start) const
Output a timing message with the prefix of this control.
Stores the information sent by the client on initialize.
std::string host
Client host.
nlohmann::json data
Raw data.
std::string user
Client user.
std::string name
Client name.
Represents an error response to the client from the server.
Represents a request from the client.
std::optional< nlohmann::json > _json
The underlying JSON data, if any.
void setJSON(const nlohmann::json &json, const Moose::PassKey< WebServerControl >)
Set the JSON data in the request.
const nlohmann::json & getJSON() const
Represents a response to the client from the server.
const std::string & getError() const
std::optional< std::string > _error
The error message, if any.
const nlohmann::json & getJSON() const
void setError(const std::string &error)
Set the error message.
unsigned int _status_code
The status code.
unsigned int getStatusCode() const
std::optional< nlohmann::json > _json
The JSON data, if any.
Options to be passed to addServerAction.
bool _require_waiting
Whether or not to require waiting.
void requireJSONKey(const std::string &key)
Append a key to be required in JSON in the request data.
void requireJSONKeys(std::initializer_list< std::string > &&keys)
Append keys to be required in JSON in the request data.
void setRequireInitialized(const bool value, const Moose::PassKey< WebServerControl >)
Set the require initialized flag; only accessible by the WebServerControl.
const std::set< std::string > getRequiredJSONKeys() const
std::set< std::string > _required_json_keys
JSON keys that are required in the data.
bool _require_initialized
Whether or not to require initialization.
void setRequireWaiting(const bool value, const Moose::PassKey< WebServerControl >)
Set the require waiting flag; only accessible by the WebServerControl.