Fawkes API Fawkes Development Version
skiller-rest-api.cpp
1
2/***************************************************************************
3 * skiller-rest-api.cpp - CLIPS Executive REST API
4 *
5 * Created: Sun Mar 25 01:29:29 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 "skiller-rest-api.h"
23
24#include <core/threading/mutex_locker.h>
25#include <interfaces/SkillerDebugInterface.h>
26#include <interfaces/SkillerInterface.h>
27#include <utils/time/wait.h>
28#include <webview/rest_api_manager.h>
29
30using namespace fawkes;
31
32/** @class SkillerRestApi "skiller-rest-api.h"
33 * REST API backend for the CLIPS executive.
34 * @author Tim Niemueller
35 */
36
37/** Constructor. */
38SkillerRestApi::SkillerRestApi() : Thread("ClipsWebviewThread", Thread::OPMODE_WAITFORWAKEUP)
39{
40}
41
42/** Destructor. */
44{
45}
46
47void
49{
51 skiller_if_ = blackboard->open_for_reading<SkillerInterface>("Skiller");
52
53 rest_api_ = new WebviewRestApi("skiller", logger);
54 rest_api_->add_handler<WebviewRestArray<SkillInfo>>(
55 WebRequest::METHOD_GET, "/skills", std::bind(&SkillerRestApi::cb_list_skills, this));
56 rest_api_->add_handler<Skill>(WebRequest::METHOD_GET,
57 "/skills/{id}",
58 std::bind(&SkillerRestApi::cb_get_skill,
59 this,
60 std::placeholders::_1));
61 rest_api_->add_handler(WebRequest::METHOD_DELETE,
62 "/skills/{id}",
63 std::bind(&SkillerRestApi::cb_stop_skill, this, std::placeholders::_1));
64 rest_api_->add_handler<Skill, SkillCall>(WebRequest::METHOD_POST,
65 "/call",
66 std::bind(&SkillerRestApi::cb_exec_skill,
67 this,
68 std::placeholders::_1));
70}
71
72void
74{
76 delete rest_api_;
77}
78
79void
81{
82}
83
84void
85SkillerRestApi::set_and_wait_graph(const char *graph)
86{
87 if (strcmp(skdb_if_->graph_fsm(), graph) != 0) {
88 // It's not currently the desired graph
90 skdb_if_->msgq_enqueue(m);
93 do {
95 skdb_if_->read();
96 now.stamp();
97 } while (strcmp(skdb_if_->graph_fsm(), graph) != 0 && (now - &start) <= 5.0);
98 }
99
100 if (strcmp(skdb_if_->graph_fsm(), graph) != 0) {
101 throw WebviewRestException(WebReply::HTTP_REQUEST_TIMEOUT,
102 "Did not receive '%s' in time from skiller",
103 graph);
104 }
105}
106
108SkillerRestApi::cb_list_skills()
109{
111
112 skdb_if_->read();
113 if (!skdb_if_->has_writer() || !skiller_if_->has_writer()) {
114 throw WebviewRestException(WebReply::HTTP_SERVICE_UNAVAILABLE,
115 "Behavior Engine plugin is not loaded");
116 }
117
118 std::string prev_fsm = skdb_if_->graph_fsm();
119
120 set_and_wait_graph("LIST");
121
122 std::stringstream ss(skdb_if_->graph());
123 std::string skill_name;
124 while (std::getline(ss, skill_name, '\n')) {
125 SkillInfo s;
126 s.set_kind("SkillInfo");
128 s.set_name(skill_name);
129 rv.push_back(std::move(s));
130 }
131
133 new SkillerDebugInterface::SetGraphMessage(prev_fsm.c_str());
134 skdb_if_->msgq_enqueue(m);
135
136 return rv;
137}
138
139Skill
140SkillerRestApi::cb_get_skill(WebviewRestParams &params)
141{
142 std::string skill_name{params.path_arg("id")};
143
144 if (skill_name == "active") {
145 skill_name = "ACTIVE";
146 }
147
148 skdb_if_->read();
149 skiller_if_->read();
150 if (!skdb_if_->has_writer() || !skiller_if_->has_writer()) {
151 throw WebviewRestException(WebReply::HTTP_SERVICE_UNAVAILABLE,
152 "Behavior Engine plugin is not loaded");
153 }
154
155 set_and_wait_graph(skill_name.c_str());
156
157 Skill s;
158 s.set_kind("Skill");
160 s.set_name(skdb_if_->graph_fsm());
161 s.set_graph(skdb_if_->graph());
162
163 if (skill_name == "ACTIVE") {
164 skiller_if_->read();
165 s.set_skill_string(skiller_if_->skill_string());
166 s.set_error(skiller_if_->error());
167 s.set_msg_id(skiller_if_->msgid());
169 switch (skiller_if_->status()) {
170 case SkillerInterface::S_RUNNING: s.set_status("RUNNING"); break;
171 case SkillerInterface::S_FINAL: s.set_status("FINAL"); break;
172 case SkillerInterface::S_FAILED: s.set_status("FAILED"); break;
173 default: s.set_status("INACTIVE"); break;
174 }
175 }
176
177 return s;
178}
179
180Skill
181SkillerRestApi::cb_exec_skill(const SkillCall &call)
182{
183 if (!call.skill_string()) {
184 throw WebviewRestException(WebReply::HTTP_BAD_REQUEST, "Request lacks skill string");
185 }
186
187 skiller_if_->read();
188 if (!skiller_if_->has_writer()) {
189 throw WebviewRestException(WebReply::HTTP_SERVICE_UNAVAILABLE,
190 "Behavior Engine plugin is not loaded");
191 }
192
193 if (skiller_if_->exclusive_controller() != 0) {
194 throw WebviewRestException(WebReply::HTTP_CONFLICT, "Another thread is exclusive controller");
195 }
196
199 m->ref();
200
201 try {
202 skiller_if_->msgq_enqueue(m);
203 } catch (Exception &e) {
204 logger->log_error(name(), "Failed to execute skill: %s", e.what_no_backtrace());
205 throw WebviewRestException(WebReply::HTTP_INTERNAL_SERVER_ERROR,
206 "Failed to execute skill: %s",
208 }
209
210 Skill sk;
211 sk.set_kind("Skill");
213 sk.set_name("active");
214 sk.set_msg_id(m->id());
215 m->unref();
216 return sk;
217}
218
219std::unique_ptr<fawkes::WebviewRestReply>
220SkillerRestApi::cb_stop_skill(WebviewRestParams &params)
221{
222 std::string skill_name{params.path_arg("id")};
223
224 if (skill_name != "active") {
225 throw WebviewRestException(WebReply::HTTP_BAD_REQUEST,
226 "Only the 'active' skill can be stopped");
227 }
228
229 skiller_if_->read();
230 if (!skiller_if_->has_writer()) {
231 throw WebviewRestException(WebReply::HTTP_SERVICE_UNAVAILABLE,
232 "Behavior Engine plugin is not loaded");
233 }
234
235 if (skiller_if_->exclusive_controller() != 0) {
236 throw WebviewRestException(WebReply::HTTP_CONFLICT, "Another thread is exclusive controller");
237 }
238
239 try {
241 } catch (Exception &e) {
242 logger->log_error(name(), "Failed to stop skill: %s", e.what_no_backtrace());
243 throw WebviewRestException(WebReply::HTTP_INTERNAL_SERVER_ERROR,
244 "Failed to execute skill: %s",
246 }
247
248 return std::make_unique<WebviewRestReply>(WebReply::HTTP_OK, "OK", "text/plain");
249}
SkillCall representation for JSON transfer.
Definition: SkillCall.h:29
std::optional< std::string > skill_string() const
Get skill_string value.
Definition: SkillCall.h:127
SkillInfo representation for JSON transfer.
Definition: SkillInfo.h:29
void set_name(const std::string &name)
Set name value.
Definition: SkillInfo.h:136
static std::string api_version()
Get version of implemented API.
Definition: SkillInfo.h:49
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Definition: SkillInfo.h:119
void set_kind(const std::string &kind)
Set kind value.
Definition: SkillInfo.h:102
Skill representation for JSON transfer.
Definition: Skill.h:29
void set_graph(const std::string &graph)
Set graph value.
Definition: Skill.h:153
void set_error(const std::string &error)
Set error value.
Definition: Skill.h:189
void set_status(const std::string &status)
Set status value.
Definition: Skill.h:240
void set_exclusive_controller(const std::string &exclusive_controller)
Set exclusive_controller value.
Definition: Skill.h:223
void set_kind(const std::string &kind)
Set kind value.
Definition: Skill.h:102
void set_skill_string(const std::string &skill_string)
Set skill-string value.
Definition: Skill.h:171
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Definition: Skill.h:119
static std::string api_version()
Get version of implemented API.
Definition: Skill.h:49
void set_msg_id(const int64_t &msg_id)
Set msg_id value.
Definition: Skill.h:206
void set_name(const std::string &name)
Set name value.
Definition: Skill.h:136
virtual void init()
Initialize the thread.
virtual void finalize()
Finalize the thread.
~SkillerRestApi()
Destructor.
SkillerRestApi()
Constructor.
virtual void loop()
Code to execute in the thread.
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
BlackBoard * blackboard
This is the BlackBoard instance you can use to interact with the BlackBoard.
Definition: blackboard.h:44
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
Clock * clock
By means of this member access to the clock is given.
Definition: clock.h:42
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual const char * what_no_backtrace() const noexcept
Get primary string (does not implicitly print the back trace).
Definition: exception.cpp:663
unsigned int msgq_enqueue(Message *message, bool proxy=false)
Enqueue message at end of queue.
Definition: interface.cpp:915
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:479
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:848
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:41
unsigned int id() const
Get message ID.
Definition: message.cpp:181
void unref()
Decrement reference count and conditionally delete this instance.
Definition: refcount.cpp:95
void ref()
Increment reference count.
Definition: refcount.cpp:67
SetGraphMessage Fawkes BlackBoard Interface Message.
SkillerDebugInterface Fawkes BlackBoard Interface.
char * graph_fsm() const
Get graph_fsm value.
char * graph() const
Get graph value.
ExecSkillMessage Fawkes BlackBoard Interface Message.
StopExecMessage Fawkes BlackBoard Interface Message.
SkillerInterface Fawkes BlackBoard Interface.
char * error() const
Get error value.
SkillStatusEnum status() const
Get status value.
uint32_t msgid() const
Get msgid value.
char * skill_string() const
Get skill_string value.
char * exclusive_controller() const
Get exclusive_controller value.
Thread class encapsulation of pthreads.
Definition: thread.h:46
const char * name() const
Get name of thread.
Definition: thread.h:100
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:499
void wait_systime()
Wait until minimum loop time has been reached in real time.
Definition: wait.cpp:96
A class for handling time.
Definition: time.h:93
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
REST processing exception.
Definition: rest_api.h:71
REST parameters to pass to handlers.
Definition: rest_api.h:125
std::string path_arg(const std::string &what)
Get a path argument.
Definition: rest_api.h:142
Fawkes library namespace.