22 #include "clips-executive-rest-api.h"
24 #include <core/threading/mutex_locker.h>
25 #include <webview/rest_api_manager.h>
36 :
Thread(
"ClipsWebviewThread",
Thread::OPMODE_WAITFORWAKEUP)
49 std::map<std::string, LockPtr<CLIPS::Environment>> envs =
clips_env_mgr->environments();
50 if (envs.find(
"executive") == envs.end()) {
51 throw Exception(
"No CLIPS environment named 'executive' found");
53 clips_ = envs[
"executive"];
58 WebRequest::METHOD_GET,
"/goals", std::bind(&ClipsExecutiveRestApi::cb_list_goals,
this));
61 std::bind(&ClipsExecutiveRestApi::cb_get_goal,
63 std::placeholders::_1));
65 WebRequest::METHOD_GET,
67 std::bind(&ClipsExecutiveRestApi::cb_list_domain_operators,
this));
69 WebRequest::METHOD_GET,
71 std::bind(&ClipsExecutiveRestApi::cb_list_domain_objects,
this));
73 WebRequest::METHOD_GET,
75 std::bind(&ClipsExecutiveRestApi::cb_list_domain_predicates,
this));
77 WebRequest::METHOD_GET,
79 std::bind(&ClipsExecutiveRestApi::cb_list_domain_facts,
this));
81 WebRequest::METHOD_GET,
"/plans", std::bind(&ClipsExecutiveRestApi::cb_list_plans,
this));
83 "/plans/{goal-id}/{id}",
84 std::bind(&ClipsExecutiveRestApi::cb_get_plan,
86 std::placeholders::_1));
107 template <
typename T>
109 get_value(
const CLIPS::Fact::pointer &fact,
const std::string &slot_name)
111 CLIPS::Values v = fact->slot_value(slot_name);
113 throw Exception(
"No value for slot '%s'", slot_name.c_str());
115 if (v[0].type() == CLIPS::TYPE_SYMBOL && v[0].as_string() ==
"nil") {
128 get_value(
const CLIPS::Fact::pointer &fact,
const std::string &slot_name)
130 CLIPS::Values v = fact->slot_value(slot_name);
132 throw Exception(
"No value for slot '%s'", slot_name.c_str());
134 if (v[0].type() != CLIPS::TYPE_SYMBOL) {
135 throw Exception(
"Value for slot '%s' is not a boolean", slot_name.c_str());
137 return (v[0].as_string() ==
"TRUE");
148 static std::vector<std::string>
149 get_values(
const CLIPS::Fact::pointer &fact,
const std::string &slot_name)
151 CLIPS::Values v = fact->slot_value(slot_name);
152 std::vector<std::string> rv(v.size());
153 for (
size_t i = 0; i < v.size(); ++i) {
154 switch (v[i].type()) {
155 case CLIPS::TYPE_FLOAT: rv[i] = std::to_string(
static_cast<double>(v[i]));
break;
156 case CLIPS::TYPE_INTEGER: rv[i] = std::to_string(
static_cast<long long int>(v[i]));
break;
157 case CLIPS::TYPE_SYMBOL:
158 case CLIPS::TYPE_STRING:
159 case CLIPS::TYPE_INSTANCE_NAME: rv[i] =
static_cast<std::string &
>(v[i]);
break;
160 default: rv[i] =
"CANNOT-REPRESENT";
break;
167 ClipsExecutiveRestApi::generate_goal(CLIPS::Fact::pointer fact)
172 g.
set_id(get_value<std::string>(fact,
"id"));
173 g.
set__class(get_value<std::string>(fact,
"class"));
174 g.
set_type(get_value<std::string>(fact,
"type"));
175 g.
set_sub_type(get_value<std::string>(fact,
"sub-type"));
176 g.
set_mode(get_value<std::string>(fact,
"mode"));
177 g.
set_parent(get_value<std::string>(fact,
"parent"));
178 g.
set_outcome(get_value<std::string>(fact,
"outcome"));
180 g.
set_message(get_value<std::string>(fact,
"message"));
183 g.
set_meta(get_values(fact,
"meta"));
187 CLIPS::Fact::pointer pfact = clips_->get_facts();
189 CLIPS::Template::pointer tmpl = pfact->get_template();
190 if (tmpl->name() ==
"plan") {
192 if (get_value<std::string>(pfact,
"goal-id") == *g.
id()) {
193 g.
addto_plans(std::move(get_value<std::string>(pfact,
"id")));
198 pfact = pfact->next();
205 ClipsExecutiveRestApi::cb_list_goals()
210 CLIPS::Fact::pointer fact = clips_->get_facts();
212 CLIPS::Template::pointer tmpl = fact->get_template();
213 if (tmpl->name() ==
"goal") {
215 rv.
push_back(std::move(generate_goal(fact)));
230 const std::string
id = params.
path_arg(
"id");
233 CLIPS::Fact::pointer fact = clips_->get_facts();
235 CLIPS::Template::pointer tmpl = fact->get_template();
236 if (tmpl->name() ==
"goal") {
238 if (get_value<std::string>(fact,
"id") ==
id) {
239 return generate_goal(fact);
253 ClipsExecutiveRestApi::cb_list_domain_operators()
258 std::map<std::string, std::list<std::pair<std::string, std::string>>> op_params;
260 CLIPS::Fact::pointer fact = clips_->get_facts();
262 CLIPS::Template::pointer tmpl = fact->get_template();
263 if (tmpl->name() ==
"domain-operator-parameter") {
264 std::string operator_name = get_value<std::string>(fact,
"operator");
265 if (op_params.find(operator_name) == op_params.end()) {
266 op_params[operator_name] = {};
268 op_params[operator_name].push_back(
269 std::make_pair(get_value<std::string>(fact,
"name"), get_value<std::string>(fact,
"type")));
274 fact = clips_->get_facts();
276 CLIPS::Template::pointer tmpl = fact->get_template();
277 if (tmpl->name() ==
"domain-operator") {
282 o.
set_name(get_value<std::string>(fact,
"name"));
284 if (op_params.find(*o.
name()) != op_params.end()) {
285 for (
const auto &p : op_params[*o.
name()]) {
306 ClipsExecutiveRestApi::cb_list_domain_objects()
311 CLIPS::Fact::pointer fact = clips_->get_facts();
313 CLIPS::Template::pointer tmpl = fact->get_template();
314 if (tmpl->name() ==
"domain-object") {
318 o.
set_name(get_value<std::string>(fact,
"name"));
319 o.
set_type(get_value<std::string>(fact,
"type"));
329 ClipsExecutiveRestApi::cb_list_domain_predicates()
334 CLIPS::Fact::pointer fact = clips_->get_facts();
336 CLIPS::Template::pointer tmpl = fact->get_template();
337 if (tmpl->name() ==
"domain-predicate") {
341 p.
set_name(get_value<std::string>(fact,
"name"));
342 p.
set_sensed(get_value<bool>(fact,
"sensed"));
354 ClipsExecutiveRestApi::cb_list_domain_facts()
359 CLIPS::Fact::pointer fact = clips_->get_facts();
361 CLIPS::Template::pointer tmpl = fact->get_template();
362 if (tmpl->name() ==
"domain-fact") {
366 f.
set_name(get_value<std::string>(fact,
"name"));
376 std::shared_ptr<DomainPreconditionAtom>
377 ClipsExecutiveRestApi::gen_domain_precondition_atom(
const CLIPS::Fact::pointer fact)
379 auto pre_atom = std::make_shared<DomainPreconditionAtom>();
380 pre_atom->set_kind(
"DomainPreconditionAtom");
382 pre_atom->set_name(get_value<std::string>(fact,
"name"));
383 pre_atom->set_type(
"atom");
384 pre_atom->set_grounded(get_value<bool>(fact,
"grounded"));
385 pre_atom->set_is_satisfied(get_value<bool>(fact,
"is-satisfied"));
386 pre_atom->set_predicate(get_value<std::string>(fact,
"predicate"));
387 for (
const auto &s : get_values(fact,
"param-names")) {
388 pre_atom->addto_param_names(std::move(s));
390 for (
const auto &s : get_values(fact,
"param-values")) {
391 pre_atom->addto_param_values(std::move(s));
393 for (
const auto &s : get_values(fact,
"param-constants")) {
394 pre_atom->addto_param_constants(std::move(s));
399 std::shared_ptr<DomainPreconditionCompound>
400 ClipsExecutiveRestApi::gen_domain_precondition_compound(
const CLIPS::Fact::pointer fact,
401 const PlanActionKey & plan_action_key,
402 PreCompoundMap & prec,
405 std::string prec_name = get_value<std::string>(fact,
"name");
407 auto pre_comp = std::make_shared<DomainPreconditionCompound>();
408 pre_comp->set_kind(
"DomainPreconditionCompound");
410 pre_comp->set_name(prec_name);
411 pre_comp->set_type(get_value<std::string>(fact,
"type"));
412 pre_comp->set_grounded(get_value<bool>(fact,
"grounded"));
413 pre_comp->set_is_satisfied(get_value<bool>(fact,
"is-satisfied"));
416 for (
const auto &prea_fact : prea[plan_action_key]) {
417 std::string part_of = get_value<std::string>(prea_fact,
"part-of");
418 if (part_of == prec_name) {
419 pre_comp->addto_elements(gen_domain_precondition_atom(prea_fact));
422 for (
const auto &prec_fact : prec[plan_action_key]) {
423 std::string part_of = get_value<std::string>(prec_fact,
"part-of");
424 if (part_of == prec_name) {
425 pre_comp->addto_elements(
426 gen_domain_precondition_compound(prec_fact, plan_action_key, prec, prea));
434 ClipsExecutiveRestApi::gen_plan_precompute(PlanMap & plans,
435 PlanActionMap & plan_actions,
436 PreCompoundMap &prec,
439 CLIPS::Fact::pointer fact = clips_->get_facts();
441 CLIPS::Template::pointer tmpl = fact->get_template();
442 if (tmpl->name() ==
"plan") {
443 plans[std::make_pair(get_value<std::string>(fact,
"goal-id"),
444 get_value<std::string>(fact,
"id"))] = fact;
445 }
else if (tmpl->name() ==
"plan-action") {
446 plan_actions[std::make_pair(get_value<std::string>(fact,
"goal-id"),
447 get_value<std::string>(fact,
"plan-id"))]
449 }
else if (tmpl->name() ==
"domain-precondition"
450 || tmpl->name() ==
"domain-atomic-precondition") {
451 std::string goal_id = get_value<std::string>(fact,
"goal-id");
452 std::string plan_id = get_value<std::string>(fact,
"plan-id");
453 int64_t action_id = get_value<int64_t>(fact,
"grounded-with");
454 if (action_id != 0) {
455 if (tmpl->name() ==
"domain-precondition") {
456 prec[std::make_tuple(goal_id, plan_id, action_id)].push_back(fact);
458 prea[std::make_tuple(goal_id, plan_id, action_id)].push_back(fact);
467 ClipsExecutiveRestApi::gen_plan(
const PlanKey & plan_key,
468 const CLIPS::Fact::pointer fact,
469 PlanActionMap & plan_actions,
470 PreCompoundMap & prec,
473 const std::string &goal_id = get_value<std::string>(fact,
"goal-id");
474 const std::string &plan_id = get_value<std::string>(fact,
"id");
481 p.
set_cost(get_value<double>(fact,
"cost"));
482 if (plan_actions.find(plan_key) != plan_actions.end()) {
483 std::vector<std::shared_ptr<PlanAction>> actions;
485 for (
auto &pai : plan_actions[plan_key]) {
486 auto pa = std::make_shared<PlanAction>();
488 int64_t action_id = get_value<int64_t>(pai,
"id");
489 std::string operator_name = get_value<std::string>(pai,
"action-name");
492 pa->set_kind(
"PlanAction");
494 pa->set_id(action_id);
495 pa->set_operator_name(operator_name);
496 for (
const auto &pv : get_values(pai,
"param-values")) {
497 pa->addto_param_values(std::move(pv));
499 pa->set_state(get_value<std::string>(pai,
"state"));
500 pa->set_executable(get_value<bool>(pai,
"executable"));
501 pa->set_duration(get_value<double>(pai,
"duration"));
502 pa->set_dispatch_time(get_value<double>(pai,
"dispatch-time"));
505 const PlanActionKey plan_action_key{std::make_tuple(goal_id, plan_id, action_id)};
506 if (prec.find(plan_action_key) != prec.end()) {
507 for (
auto &prec_fact : prec[plan_action_key]) {
508 std::string part_of = get_value<std::string>(prec_fact,
"part-of");
509 int64_t grounded_with = get_value<int64_t>(prec_fact,
"grounded-with");
510 if (part_of == operator_name && grounded_with == action_id) {
511 pa->addto_preconditions(
512 gen_domain_precondition_compound(prec_fact, plan_action_key, prec, prea));
516 actions.push_back(std::move(pa));
519 std::sort(actions.begin(),
521 [](std::shared_ptr<PlanAction> &a, std::shared_ptr<PlanAction> &b) {
522 return *a->id() < *b->id();
531 ClipsExecutiveRestApi::cb_list_plans()
536 std::map<PlanKey, CLIPS::Fact::pointer> plans;
537 std::map<PlanKey, ClipsFactList> plan_actions;
540 gen_plan_precompute(plans, plan_actions, prec, prea);
542 for (
auto &pi : plans) {
543 rv.
push_back(std::move(gen_plan(pi.first, pi.second, plan_actions, prec, prea)));
552 std::string goal_id = params.
path_arg(
"goal-id");
553 std::string
id = params.
path_arg(
"id");
558 std::map<PlanKey, CLIPS::Fact::pointer> plans;
559 std::map<PlanKey, ClipsFactList> plan_actions;
563 gen_plan_precompute(plans, plan_actions, prec, prea);
565 const PlanKey plan_key{goal_id,
id};
566 if (plans.find(plan_key) == plans.end()) {
568 "No plan for goal '%s' with ID '%s' found",
573 return gen_plan(plan_key, plans[plan_key], plan_actions, prec, prea);
~ClipsExecutiveRestApi()
Destructor.
virtual void finalize()
Finalize the thread.
virtual void init()
Initialize the thread.
virtual void loop()
Code to execute in the thread.
ClipsExecutiveRestApi()
Constructor.
DomainFact representation for JSON transfer.
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
void set_kind(const std::string &kind)
Set kind value.
static std::string api_version()
Get version of implemented API.
void set_name(const std::string &name)
Set name value.
void set_param_values(const std::vector< std::string > ¶m_values)
Set param-values value.
DomainObject representation for JSON transfer.
void set_name(const std::string &name)
Set name value.
void set_type(const std::string &type)
Set type value.
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
void set_kind(const std::string &kind)
Set kind value.
static std::string api_version()
Get version of implemented API.
DomainOperatorParameter representation for JSON transfer.
void set_type(const std::string &type)
Set type value.
void set_name(const std::string &name)
Set name value.
DomainOperator representation for JSON transfer.
void addto_parameters(const std::shared_ptr< DomainOperatorParameter > &¶meters)
Add element to parameters array.
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
void set_kind(const std::string &kind)
Set kind value.
static std::string api_version()
Get version of implemented API.
void set_name(const std::string &name)
Set name value.
void set_wait_sensed(const bool &wait_sensed)
Set wait-sensed value.
std::optional< std::string > name() const
Get name value.
static std::string api_version()
Get version of implemented API.
static std::string api_version()
Get version of implemented API.
DomainPredicate representation for JSON transfer.
static std::string api_version()
Get version of implemented API.
void set_sensed(const bool &sensed)
Set sensed value.
void set_param_types(const std::vector< std::string > ¶m_types)
Set param-types value.
void set_name(const std::string &name)
Set name value.
void set_param_names(const std::vector< std::string > ¶m_names)
Set param-names value.
void set_kind(const std::string &kind)
Set kind value.
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Goal representation for JSON transfer.
void set_message(const std::string &message)
Set message value.
void set_acquired_resources(const std::vector< std::string > &acquired_resources)
Set acquired-resources value.
std::optional< std::string > id() const
Get id value.
void set_parameters(const std::vector< std::string > ¶meters)
Set parameters value.
void set_id(const std::string &id)
Set id value.
void set_mode(const std::string &mode)
Set mode value.
void set_sub_type(const std::string &sub_type)
Set sub-type value.
void set_meta(const std::vector< std::string > &meta)
Set meta value.
void set_parent(const std::string &parent)
Set parent value.
void set_required_resources(const std::vector< std::string > &required_resources)
Set required-resources value.
void set_outcome(const std::string &outcome)
Set outcome value.
void set__class(const std::string &_class)
Set class value.
void set_kind(const std::string &kind)
Set kind value.
static std::string api_version()
Get version of implemented API.
void addto_plans(const std::string &&plans)
Add element to plans array.
void set_priority(const int64_t &priority)
Set priority value.
void set_error(const std::vector< std::string > &error)
Set error value.
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
void set_type(const std::string &type)
Set type value.
static std::string api_version()
Get version of implemented API.
Plan representation for JSON transfer.
void set_id(const std::string &id)
Set id value.
void set_goal_id(const std::string &goal_id)
Set goal-id value.
static std::string api_version()
Get version of implemented API.
void set_kind(const std::string &kind)
Set kind value.
void set_actions(const std::vector< std::shared_ptr< PlanAction >> &actions)
Set actions value.
void set_cost(const float &cost)
Set cost value.
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Container to return array via REST.
void push_back(M &m)
Add item at the back of the container.
LockPtr< CLIPSEnvManager > clips_env_mgr
CLIPS environment manager.
Base class for exceptions in Fawkes.
virtual const char * what_no_backtrace() const
Get primary string (does not implicitly print the back trace).
Mutex * objmutex_ptr() const
Get object mutex.
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
Logger * logger
This is the Logger member used to access the logger.
Thread class encapsulation of pthreads.
const char * name() const
Get name of thread.
WebviewRestApiManager * webview_rest_api_manager
Webview REST API manager.
void unregister_api(WebviewRestApi *api)
Remove a request processor.
void register_api(WebviewRestApi *api)
Add a REST API.
Webview REST API component.
void add_handler(WebRequest::Method method, std::string path, Handler handler)
Add handler function.
REST processing exception.
REST parameters to pass to handlers.
std::string path_arg(const std::string &what)
Get a path argument.
Fawkes library namespace.