Fawkes API  Fawkes Development Version
clips-rest-api.cpp
1 
2 /***************************************************************************
3  * clips-rest-api.cpp - CLIPS REST API
4  *
5  * Created: Sat Mar 31 01:36:11 2018
6  * Copyright 2006-2018 Tim Niemueller [www.niemueller.de]
7  ****************************************************************************/
8 
9 /* This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Library General Public License for more details.
18  *
19  * Read the full text in the LICENSE.GPL file in the doc directory.
20  */
21 
22 #include "clips-rest-api.h"
23 
24 #include <clips/clips.h>
25 #include <core/threading/mutex_locker.h>
26 #include <webview/rest_api_manager.h>
27 
28 using namespace fawkes;
29 
30 /** @class ClipsRestApi "clips-rest-api.h"
31  * REST API backend for CLIPS.
32  * @author Tim Niemueller
33  */
34 
35 /** Constructor. */
36 ClipsRestApi::ClipsRestApi() : Thread("ClipsRestApi", Thread::OPMODE_WAITFORWAKEUP)
37 {
38 }
39 
40 /** Destructor. */
42 {
43 }
44 
45 void
47 {
48  rest_api_ = new WebviewRestApi("clips", logger);
49  rest_api_->add_handler<WebviewRestArray<Fact>>(WebRequest::METHOD_GET,
50  "/{env}/facts",
51  std::bind(&ClipsRestApi::cb_get_facts,
52  this,
53  std::placeholders::_1));
55  WebRequest::METHOD_GET, "/", std::bind(&ClipsRestApi::cb_list_environments, this));
57 }
58 
59 void
61 {
63  delete rest_api_;
64 }
65 
66 void
68 {
69 }
70 
71 /** Get a value from a fact.
72  * @param fact pointer to CLIPS fact
73  * @param slot_name name of field to retrieve
74  * @return template-specific return value
75  */
76 // template <typename T>
77 // T get_value(const CLIPS::Fact::pointer &fact, const std::string &slot_name)
78 // {
79 // CLIPS::Values v = fact->slot_value(slot_name);
80 // if (v.empty()) {
81 // throw Exception("No value for slot '%s'", slot_name.c_str());
82 // }
83 // if (v[0].type() == CLIPS::TYPE_SYMBOL && v[0].as_string() == "nil") {
84 // return T();
85 // }
86 // return v[0];
87 // }
88 
89 /** Specialization for bool.
90  * @param fact pointer to CLIPS fact
91  * @param slot_name name of field to retrieve
92  * @return boolean value
93  */
94 // template <>
95 // bool get_value(const CLIPS::Fact::pointer &fact, const std::string &slot_name)
96 // {
97 // CLIPS::Values v = fact->slot_value(slot_name);
98 // if (v.empty()) {
99 // throw Exception("No value for slot '%s'", slot_name.c_str());
100 // }
101 // if (v[0].type() != CLIPS::TYPE_SYMBOL) {
102 // throw Exception("Value for slot '%s' is not a boolean", slot_name.c_str());
103 // }
104 // return (v[0].as_string() == "TRUE");
105 // }
106 
107 /** Get value array.
108  * This is not a template because the overly verbose operator API
109  * of CLIPS::Value can lead to ambiguous overloads, e.g., resolving
110  * std::string to std::string or const char * operators.
111  * @param fact pointer to CLIPS fact
112  * @param slot_name name of field to retrieve
113  * @return vector of strings from multislot
114  */
115 // static std::vector<std::string>
116 // get_values(const CLIPS::Fact::pointer &fact, const std::string &slot_name)
117 // {
118 // CLIPS::Values v = fact->slot_value(slot_name);
119 // std::vector<std::string> rv(v.size());
120 // for (size_t i = 0; i < v.size(); ++i) {
121 // rv[i] = static_cast<std::string&>(v[i]);
122 // }
123 // return rv;
124 // }
125 
126 Fact
127 ClipsRestApi::gen_fact(LockPtr<CLIPS::Environment> &clips,
128  CLIPS::Fact::pointer & fact,
129  bool formatted)
130 {
131  Fact retf;
132  retf.set_kind("Fact");
134  retf.set_index(fact->index());
135  CLIPS::Template::pointer fact_template = fact->get_template();
136  if (fact_template) {
137  retf.set_template_name(fact_template->name());
138  } else {
139  retf.set_template_name("implied");
140  }
141 
142  if (formatted) {
143  char tmp[16384];
144  tmp[16383] = 0;
145  OpenStringDestination(clips->cobj(), (char *)"ProcPPForm", tmp, 16383);
146  PrintFact(clips->cobj(), (char *)"ProcPPForm", (struct fact *)fact->cobj(), FALSE, FALSE);
147  CloseStringDestination(clips->cobj(), (char *)"ProcPPForm");
148  retf.set_formatted(tmp);
149  } else {
150  std::vector<std::string> slots = fact->slot_names();
151  for (const auto &s : slots) {
152  CLIPS::Values fval = fact->slot_value(s);
153  SlotValue sval;
154  sval.set_name(s);
155  sval.set_is_multifield(fact_template ? fact_template->is_multifield_slot(s)
156  : (fval.size() > 1));
157  for (const auto &v : fval) {
158  switch (v.type()) {
159  case CLIPS::TYPE_FLOAT: sval.addto_values(std::to_string(v.as_float())); break;
160  case CLIPS::TYPE_INTEGER: sval.addto_values(std::to_string(v.as_integer())); break;
161  case CLIPS::TYPE_SYMBOL:
162  case CLIPS::TYPE_STRING:
163  case CLIPS::TYPE_INSTANCE_NAME: sval.addto_values(v.as_string()); break;
164  default: sval.addto_values("ADDR"); break;
165  }
166  }
167  retf.addto_slots(std::move(sval));
168  }
169  }
170 
171  return retf;
172 }
173 
175 ClipsRestApi::cb_get_facts(WebviewRestParams &params)
176 {
177  bool formatted = (params.query_arg("formatted") == "true");
178 
180 
181  MutexLocker lock(clips_env_mgr.objmutex_ptr());
182  std::map<std::string, LockPtr<CLIPS::Environment>> envs = clips_env_mgr->environments();
183  if (envs.find(params.path_arg("env")) == envs.end()) {
184  throw WebviewRestException(WebReply::HTTP_NOT_FOUND,
185  "Environment '%s' is unknown",
186  params.path_arg("env").c_str());
187  }
188 
189  auto clips = envs[params.path_arg("env")];
190  MutexLocker clips_lock(clips.objmutex_ptr());
191 
192  CLIPS::Fact::pointer fact = clips->get_facts();
193  while (fact) {
194  CLIPS::Template::pointer tmpl = fact->get_template();
195  rv.push_back(std::move(gen_fact(clips, fact, formatted)));
196  fact = fact->next();
197  }
198 
199  return rv;
200 }
201 
203 ClipsRestApi::cb_list_environments()
204 {
206 
207  MutexLocker lock(clips_env_mgr.objmutex_ptr());
208  std::map<std::string, LockPtr<CLIPS::Environment>> envs = clips_env_mgr->environments();
209 
210  for (const auto &e : envs) {
211  Environment env;
212  env.set_kind("Environment");
214  env.set_name(e.first);
215  rv.push_back(std::move(env));
216  }
217 
218  return rv;
219 }
~ClipsRestApi()
Destructor.
virtual void finalize()
Finalize the thread.
virtual void loop()
Code to execute in the thread.
ClipsRestApi()
Constructor.
virtual void init()
Initialize the thread.
Environment representation for JSON transfer.
Definition: Environment.h:28
void set_name(const std::string &name)
Set name value.
Definition: Environment.h:135
static std::string api_version()
Get version of implemented API.
Definition: Environment.h:48
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Definition: Environment.h:118
void set_kind(const std::string &kind)
Set kind value.
Definition: Environment.h:101
Fact representation for JSON transfer.
Definition: Fact.h:30
static std::string api_version()
Get version of implemented API.
Definition: Fact.h:50
void set_template_name(const std::string &template_name)
Set template_name value.
Definition: Fact.h:154
void set_index(const int64_t &index)
Set index value.
Definition: Fact.h:137
void set_formatted(const std::string &formatted)
Set formatted value.
Definition: Fact.h:171
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Definition: Fact.h:120
void set_kind(const std::string &kind)
Set kind value.
Definition: Fact.h:103
void addto_slots(const std::shared_ptr< SlotValue > &&slots)
Add element to slots array.
Definition: Fact.h:196
SlotValue representation for JSON transfer.
Definition: SlotValue.h:28
void set_name(const std::string &name)
Set name value.
Definition: SlotValue.h:101
void addto_values(const std::string &&values)
Add element to values array.
Definition: SlotValue.h:160
void set_is_multifield(const bool &is_multifield)
Set is-multifield value.
Definition: SlotValue.h:135
Container to return array via REST.
Definition: rest_array.h:36
void push_back(M &m)
Add item at the back of the container.
Definition: rest_array.h:123
LockPtr< CLIPSEnvManager > clips_env_mgr
CLIPS environment manager.
Definition: clips_manager.h:44
Mutex * objmutex_ptr() const
Get object mutex.
Definition: lockptr.h:284
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:41
Mutex locking helper.
Definition: mutex_locker.h:34
Thread class encapsulation of pthreads.
Definition: thread.h:46
WebviewRestApiManager * webview_rest_api_manager
Webview REST API manager.
Definition: webview.h:55
void unregister_api(WebviewRestApi *api)
Remove a request processor.
void register_api(WebviewRestApi *api)
Add a REST API.
Webview REST API component.
Definition: rest_api.h:221
void add_handler(WebRequest::Method method, std::string path, Handler handler)
Add handler function.
Definition: rest_api.cpp:85
REST processing exception.
Definition: rest_api.h:71
REST parameters to pass to handlers.
Definition: rest_api.h:125
std::string query_arg(const std::string &what)
Get a query argument.
Definition: rest_api.h:158
std::string path_arg(const std::string &what)
Get a path argument.
Definition: rest_api.h:142
Fawkes library namespace.