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
28using namespace fawkes;
29
30/** @class ClipsRestApi "clips-rest-api.h"
31 * REST API backend for CLIPS.
32 * @author Tim Niemueller
33 */
34
35/** Constructor. */
36ClipsRestApi::ClipsRestApi() : Thread("ClipsRestApi", Thread::OPMODE_WAITFORWAKEUP)
37{
38}
39
40/** Destructor. */
42{
43}
44
45void
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
59void
61{
63 delete rest_api_;
64}
65
66void
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
126Fact
127ClipsRestApi::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
175ClipsRestApi::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
203ClipsRestApi::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.