Fawkes API Fawkes Development Version
clips_robot_memory_thread.cpp
1
2/***************************************************************************
3 * clips_robot_memory_thread.cpp - CLIPS feature to access the robot memory
4 *
5 * Created: Mon Aug 29 15:41:47 2016
6 * Copyright 2016 Frederik Zwilling
7 * 2013-2018 Tim Niemueller [www.niemueller.de]
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * Read the full text in the LICENSE.GPL file in the doc directory.
21 */
22
23#include "clips_robot_memory_thread.h"
24
25#include <core/threading/mutex_locker.h>
26#include <plugins/mongodb/utils.h>
27
28#include <bsoncxx/document/element.hpp>
29#include <bsoncxx/exception/exception.hpp>
30#include <bsoncxx/types.hpp>
31#include <mongocxx/exception/exception.hpp>
32
33using namespace fawkes;
34
35/** @class ClipsRobotMemoryThread 'clips_robot_memory_thread.h'
36 * CLIPS feature to access the robot memory.
37 * MongoDB access through CLIPS first appeared in the RCLL referee box.
38 * @author Tim Niemueller
39 * @author Frederik Zwilling
40 */
41
42ClipsRobotMemoryThread::ClipsRobotMemoryThread()
43: Thread("ClipsRobotMemoryThread", Thread::OPMODE_WAITFORWAKEUP),
44 CLIPSFeature("robot_memory"),
46{
47}
48
49void
51{
52}
53
54void
56{
57}
58
59void
61{
62 envs_.clear();
63 for (ClipsRmTrigger *trigger : clips_triggers_) {
64 delete trigger;
65 }
66}
67
68void
69ClipsRobotMemoryThread::clips_context_init(const std::string & env_name,
71{
72 envs_[env_name] = clips;
73 logger->log_debug(name(), "Called to initialize environment %s", env_name.c_str());
74
75 clips.lock();
76
77 clips->add_function("bson-create",
78 sigc::slot<CLIPS::Value>(
79 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_create)));
80 clips->add_function("bson-parse",
81 sigc::slot<CLIPS::Value, std::string>(
82 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_parse)));
83 clips->add_function("bson-destroy",
84 sigc::slot<void, void *>(
85 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_destroy)));
86 clips->add_function("bson-append",
87 sigc::slot<void, void *, std::string, CLIPS::Value>(
88 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_append)));
89 clips->add_function("bson-append-regex",
90 sigc::slot<void, void *, std::string, CLIPS::Value>(
91 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_append_regex)));
92 clips->add_function("bson-append-array",
93 sigc::slot<void, void *, std::string, CLIPS::Values>(
94 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_append_array)));
95 clips->add_function("bson-array-start",
96 sigc::slot<CLIPS::Value>(
97 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_array_start)));
98 clips->add_function("bson-array-finish",
99 sigc::slot<void, void *, std::string, void *>(
100 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_array_finish)));
101 clips->add_function("bson-array-append",
102 sigc::slot<void, void *, CLIPS::Value>(
103 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_array_append)));
104
105 clips->add_function("bson-append-time",
106 sigc::slot<void, void *, std::string, CLIPS::Values>(
107 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_append_time)));
108 clips->add_function("bson-tostring",
109 sigc::slot<std::string, void *>(
110 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_tostring)));
111 clips->add_function("robmem-insert",
112 sigc::slot<void, std::string, void *>(
113 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_insert)));
114 clips->add_function("robmem-upsert",
115 sigc::slot<void, std::string, void *, CLIPS::Value>(
116 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_upsert)));
117 clips->add_function("robmem-update",
118 sigc::slot<void, std::string, void *, CLIPS::Value>(
119 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_update)));
120 clips->add_function("robmem-replace",
121 sigc::slot<void, std::string, void *, CLIPS::Value>(
122 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_replace)));
123 clips->add_function("robmem-query",
124 sigc::slot<CLIPS::Value, std::string, void *>(
125 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_query)));
126 clips->add_function("robmem-remove",
127 sigc::slot<void, std::string, void *>(
128 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_remove)));
129 clips->add_function("robmem-query-sort",
130 sigc::slot<CLIPS::Value, std::string, void *, void *>(
131 sigc::mem_fun(*this,
132 &ClipsRobotMemoryThread::clips_robotmemory_query_sort)));
133 clips->add_function("robmem-dump-collection",
134 sigc::slot<CLIPS::Value, std::string, std::string>(
135 sigc::mem_fun(*this,
136 &ClipsRobotMemoryThread::clips_robotmemory_dump_collection)));
137 clips->add_function("robmem-restore-collection",
138 sigc::slot<CLIPS::Value, std::string, std::string, std::string>(sigc::mem_fun(
139 *this, &ClipsRobotMemoryThread::clips_robotmemory_restore_collection)));
140 clips->add_function("robmem-cursor-destroy",
141 sigc::slot<void, void *>(
142 sigc::mem_fun(*this,
143 &ClipsRobotMemoryThread::clips_robotmemory_cursor_destroy)));
144 clips->add_function("robmem-cursor-more",
145 sigc::slot<CLIPS::Value, void *>(
146 sigc::mem_fun(*this,
147 &ClipsRobotMemoryThread::clips_robotmemory_cursor_more)));
148 clips->add_function("robmem-cursor-next",
149 sigc::slot<CLIPS::Value, void *>(
150 sigc::mem_fun(*this,
151 &ClipsRobotMemoryThread::clips_robotmemory_cursor_next)));
152 clips->add_function("robmem-trigger-register",
153 sigc::slot<CLIPS::Value, std::string, void *, std::string>(sigc::bind<0>(
154 sigc::mem_fun(*this,
155 &ClipsRobotMemoryThread::clips_robotmemory_register_trigger),
156 env_name)));
157 clips->add_function("robmem-trigger-destroy",
158 sigc::slot<void, void *>(
159 sigc::mem_fun(*this,
160 &ClipsRobotMemoryThread::clips_robotmemory_destroy_trigger)));
161 clips->add_function("bson-field-names",
162 sigc::slot<CLIPS::Values, void *>(
163 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_field_names)));
164 clips->add_function("bson-has-field",
165 sigc::slot<CLIPS::Value, void *, std::string>(
166 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_has_field)));
167 clips->add_function("bson-get",
168 sigc::slot<CLIPS::Value, void *, std::string>(
169 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_get)));
170 clips->add_function("bson-get-array",
171 sigc::slot<CLIPS::Values, void *, std::string>(
172 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_get_array)));
173 clips->add_function("bson-get-time",
174 sigc::slot<CLIPS::Values, void *, std::string>(
175 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_get_time)));
176 clips->add_function("robmem-create-index",
177 sigc::slot<void, std::string, void *>(
178 sigc::mem_fun(*this,
179 &ClipsRobotMemoryThread::clips_robotmemory_create_index)));
180 clips->add_function("robmem-create-unique-index",
181 sigc::slot<void, std::string, void *>(sigc::mem_fun(
182 *this, &ClipsRobotMemoryThread::clips_robotmemory_create_unique_index)));
183
184 clips->add_function("robmem-mutex-create",
185 sigc::slot<CLIPS::Value, std::string>(
186 sigc::mem_fun(*this,
187 &ClipsRobotMemoryThread::clips_robotmemory_mutex_create)));
188 clips->add_function("robmem-mutex-destroy",
189 sigc::slot<CLIPS::Value, std::string>(
190 sigc::mem_fun(*this,
191 &ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy)));
192 clips->add_function("robmem-mutex-try-lock",
193 sigc::slot<CLIPS::Value, std::string, std::string>(
194 sigc::mem_fun(*this,
195 &ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock)));
196 clips->add_function("robmem-mutex-renew-lock",
197 sigc::slot<CLIPS::Value, std::string, std::string>(sigc::mem_fun(
198 *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock)));
199 clips->add_function("robmem-mutex-force-lock",
200 sigc::slot<CLIPS::Value, std::string, std::string>(sigc::mem_fun(
201 *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock)));
202 clips->add_function("robmem-mutex-unlock",
203 sigc::slot<CLIPS::Value, std::string, std::string>(
204 sigc::mem_fun(*this,
205 &ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock)));
206 clips->add_function("robmem-mutex-setup-ttl",
207 sigc::slot<CLIPS::Value, float>(
208 sigc::mem_fun(*this,
209 &ClipsRobotMemoryThread::clips_robotmemory_mutex_setup_ttl)));
210 clips->add_function("robmem-mutex-expire-locks",
211 sigc::slot<CLIPS::Value, float>(sigc::mem_fun(
212 *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks)));
213
214 clips->add_function("robmem-mutex-create-async",
215 sigc::slot<CLIPS::Values, std::string>(sigc::mem_fun(
216 *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_create_async)));
217 clips->add_function("robmem-mutex-destroy-async",
218 sigc::slot<CLIPS::Values, std::string>(sigc::mem_fun(
219 *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy_async)));
220 clips->add_function(
221 "robmem-mutex-try-lock-async",
222 sigc::slot<CLIPS::Values, std::string, std::string>(sigc::bind<0>(
223 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock_async),
224 env_name)));
225 clips->add_function(
226 "robmem-mutex-renew-lock-async",
227 sigc::slot<CLIPS::Values, std::string, std::string>(sigc::bind<0>(
228 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock_async),
229 env_name)));
230 clips->add_function("robmem-mutex-force-lock-async",
231 sigc::slot<CLIPS::Values, std::string, std::string>(sigc::mem_fun(
232 *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock_async)));
233 clips->add_function("robmem-mutex-unlock-async",
234 sigc::slot<CLIPS::Values, std::string, std::string>(sigc::mem_fun(
235 *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock_async)));
236 clips->add_function(
237 "robmem-mutex-expire-locks-async",
238 sigc::slot<CLIPS::Value, float>(sigc::bind<0>(
239 sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks_async),
240 env_name)));
241
242 clips->build("(deffacts have-feature-mongodb (have-feature MongoDB))");
243
244 //load helper functions written in CLIPS
245 clips->batch_evaluate(SRCDIR "/robot-memory.clp");
246
247 clips.unlock();
248}
249
250void
252{
253 envs_.erase(env_name);
254 logger->log_debug(name(), "Removing environment %s", env_name.c_str());
255}
256
257CLIPS::Value
258ClipsRobotMemoryThread::clips_bson_create()
259{
260 return CLIPS::Value(new bsoncxx::builder::basic::document());
261}
262
263CLIPS::Value
264ClipsRobotMemoryThread::clips_bson_parse(std::string document)
265{
266 auto b = new bsoncxx::builder::basic::document();
267 try {
268 b->append(bsoncxx::builder::concatenate(bsoncxx::from_json(document)));
269 } catch (bsoncxx::exception &e) {
270 logger->log_error("MongoDB", "Parsing JSON doc failed: %s\n%s", e.what(), document.c_str());
271 }
272 return CLIPS::Value(b);
273}
274
275void
276ClipsRobotMemoryThread::clips_bson_destroy(void *bson)
277{
278 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
279 delete b;
280}
281
282std::string
283ClipsRobotMemoryThread::clips_bson_tostring(void *bson)
284{
285 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
286 return bsoncxx::to_json(b->view());
287}
288
289void
290ClipsRobotMemoryThread::clips_bson_append(void *bson, std::string field_name, CLIPS::Value value)
291{
292 using namespace bsoncxx::builder;
293 try {
294 auto b = static_cast<basic::document *>(bson);
295 switch (value.type()) {
296 case CLIPS::TYPE_FLOAT: b->append(basic::kvp(field_name, value.as_float())); break;
297
298 case CLIPS::TYPE_INTEGER:
299 b->append(basic::kvp(field_name, static_cast<int64_t>(value.as_integer())));
300 break;
301
302 case CLIPS::TYPE_SYMBOL:
303 case CLIPS::TYPE_INSTANCE_NAME:
304 case CLIPS::TYPE_STRING: b->append(basic::kvp(field_name, value.as_string())); break;
305 case CLIPS::TYPE_EXTERNAL_ADDRESS: {
306 auto subb = static_cast<basic::document *>(value.as_address());
307 b->append(basic::kvp(field_name, subb->view()));
308 } break;
309
310 default:
311 logger->log_warn("RefBox", "Tried to add unknown type to BSON field %s", field_name.c_str());
312 break;
313 }
314 } catch (bsoncxx::exception &e) {
315 logger->log_error("MongoDB",
316 "Failed to append array value to field %s: %s",
317 field_name.c_str(),
318 e.what());
319 }
320}
321
322void
323ClipsRobotMemoryThread::clips_bson_append_regex(void * bson,
324 std::string field_name,
325 CLIPS::Value regex_string)
326{
327 using namespace bsoncxx::builder;
328 if (regex_string.type() != CLIPS::TYPE_STRING) {
329 logger->log_error("MongoDB", "Regex string has to be of type string");
330 return;
331 }
332 try {
333 auto b = static_cast<basic::document *>(bson);
334 b->append(basic::kvp(field_name, bsoncxx::types::b_regex{regex_string.as_string()}));
335 } catch (bsoncxx::exception &e) {
336 logger->log_error("MongoDB",
337 "Failed to append regex to field %s: %s",
338 field_name.c_str(),
339 e.what());
340 }
341}
342
343void
344ClipsRobotMemoryThread::clips_bson_append_array(void * bson,
345 std::string field_name,
346 CLIPS::Values values)
347{
348 using namespace bsoncxx::builder;
349 try {
350 auto b = static_cast<basic::document *>(bson);
351
352 b->append(basic::kvp(field_name, [&](basic::sub_array array) {
353 for (auto value : values) {
354 switch (value.type()) {
355 case CLIPS::TYPE_FLOAT: array.append(value.as_float()); break;
356
357 case CLIPS::TYPE_INTEGER: array.append(static_cast<int64_t>(value.as_integer())); break;
358
359 case CLIPS::TYPE_SYMBOL:
360 case CLIPS::TYPE_STRING:
361 case CLIPS::TYPE_INSTANCE_NAME: array.append(value.as_string()); break;
362
363 case CLIPS::TYPE_EXTERNAL_ADDRESS: {
364 auto subb = static_cast<bsoncxx::builder::basic::document *>(value.as_address());
365 array.append(subb->view());
366 } break;
367
368 default:
369 logger->log_warn("MongoDB",
370 "Tried to add unknown type to BSON array field %s",
371 field_name.c_str());
372 break;
373 }
374 }
375 }));
376 } catch (bsoncxx::exception &e) {
377 logger->log_error("MongoDB",
378 "Failed to append array value to field %s: %s",
379 field_name.c_str(),
380 e.what());
381 }
382}
383
384CLIPS::Value
385ClipsRobotMemoryThread::clips_bson_array_start()
386{
387 return CLIPS::Value(new bsoncxx::builder::basic::array{});
388}
389
390void
391ClipsRobotMemoryThread::clips_bson_array_finish(void *bson, std::string field_name, void *array)
392{
393 using namespace bsoncxx::builder;
394 auto doc = static_cast<basic::document *>(bson);
395 auto array_doc = static_cast<bsoncxx::builder::basic::array *>(array);
396 doc->append(basic::kvp(field_name, array_doc->view()));
397 delete array_doc;
398}
399
400void
401ClipsRobotMemoryThread::clips_bson_array_append(void *array, CLIPS::Value value)
402{
403 using namespace bsoncxx::builder;
404 auto array_doc = static_cast<bsoncxx::builder::basic::array *>(array);
405 switch (value.type()) {
406 case CLIPS::TYPE_FLOAT: array_doc->append(value.as_float()); break;
407
408 case CLIPS::TYPE_INTEGER: array_doc->append(static_cast<int64_t>(value.as_integer())); break;
409
410 case CLIPS::TYPE_SYMBOL:
411 case CLIPS::TYPE_STRING:
412 case CLIPS::TYPE_INSTANCE_NAME: array_doc->append(value.as_string()); break;
413
414 case CLIPS::TYPE_EXTERNAL_ADDRESS: {
415 auto subb = static_cast<basic::document *>(value.as_address());
416 array_doc->append(subb->view());
417 } break;
418 default:
419 logger->log_warn("MongoDB", "bson-array-append: tried to add unknown type to BSON array field");
420 break;
421 }
422}
423
424void
425ClipsRobotMemoryThread::clips_bson_append_time(void * bson,
426 std::string field_name,
427 CLIPS::Values time)
428{
429 if (time.size() != 2) {
430 logger->log_warn("MongoDB", "Invalid time, %zu instead of 2 entries", time.size());
431 return;
432 }
433 if (time[0].type() != CLIPS::TYPE_INTEGER || time[1].type() != CLIPS::TYPE_INTEGER) {
434 logger->log_warn("MongoDB", "Invalid time, type mismatch");
435 return;
436 }
437
438 try {
439 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
440 struct timeval now = {time[0].as_integer(), time[1].as_integer()};
441 bsoncxx::types::b_date nowd{
442 std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>{
443 std::chrono::milliseconds{now.tv_sec * 1000 + now.tv_usec / 1000}}};
444 b->append(bsoncxx::builder::basic::kvp(field_name, nowd));
445 } catch (bsoncxx::exception &e) {
446 logger->log_error("MongoDB",
447 "Failed to append time value to field %s: %s",
448 field_name.c_str(),
449 e.what());
450 }
451}
452
453void
454ClipsRobotMemoryThread::clips_robotmemory_insert(std::string collection, void *bson)
455{
456 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
457
458 try {
459 robot_memory->insert(b->view(), collection);
460 } catch (mongocxx::exception &e) {
461 logger->log_warn("MongoDB", "Insert failed: %s", e.what());
462 }
463}
464
465void
466ClipsRobotMemoryThread::clips_robotmemory_create_index(std::string collection, void *bson)
467{
468 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
469
470 try {
471 robot_memory->create_index(b->view(), collection, /* unique */ false);
472 } catch (mongocxx::exception &e) {
473 logger->log_warn("MongoDB", "Creating index failed: %s", e.what());
474 }
475}
476
477void
478ClipsRobotMemoryThread::clips_robotmemory_create_unique_index(std::string collection, void *bson)
479{
480 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
481
482 try {
483 robot_memory->create_index(b->view(), collection, /* unique */ true);
484 } catch (mongocxx::exception &e) {
485 logger->log_warn("MongoDB", "Creating unique index failed: %s", e.what());
486 }
487}
488
489void
490ClipsRobotMemoryThread::robotmemory_update(std::string & collection,
491 const bsoncxx::document::view &update,
492 CLIPS::Value & query,
493 bool upsert)
494{
495 try {
496 if (query.type() == CLIPS::TYPE_STRING) {
497 robot_memory->update(bsoncxx::from_json(query.as_string()), update, collection, upsert);
498 } else if (query.type() == CLIPS::TYPE_EXTERNAL_ADDRESS) {
499 bsoncxx::builder::basic::document *qb =
500 static_cast<bsoncxx::builder::basic::document *>(query.as_address());
501 robot_memory->update(qb->view(), update, collection, upsert);
502 } else {
503 logger->log_warn("MongoDB", "Invalid query, must be string or BSON document");
504 return;
505 }
506
507 } catch (bsoncxx::exception &e) {
508 logger->log_warn("MongoDB", "Compiling query failed: %s", e.what());
509 } catch (mongocxx::exception &e) {
510 logger->log_warn("MongoDB", "Insert failed: %s", e.what());
511 }
512}
513
514void
515ClipsRobotMemoryThread::clips_robotmemory_upsert(std::string collection,
516 void * bson,
517 CLIPS::Value query)
518{
519 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
520 if (!b) {
521 logger->log_warn("MongoDB", "Invalid BSON Builder passed");
522 return;
523 }
524 robotmemory_update(collection, b->view(), query, true);
525}
526
527void
528ClipsRobotMemoryThread::clips_robotmemory_update(std::string collection,
529 void * bson,
530 CLIPS::Value query)
531{
532 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
533 if (!b) {
534 logger->log_warn("MongoDB", "Invalid BSON Builder passed");
535 return;
536 }
537 robotmemory_update(collection, b->view(), query, false);
538}
539
540void
541ClipsRobotMemoryThread::clips_robotmemory_replace(std::string collection,
542 void * bson,
543 CLIPS::Value query)
544{
545 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
546 if (!b)
547 logger->log_warn("MongoDB", "Invalid BSON Builder passed");
548 robotmemory_update(collection, b->view(), query, false);
549}
550
551CLIPS::Value
552ClipsRobotMemoryThread::clips_robotmemory_query_sort(std::string collection,
553 void * bson,
554 void * bson_sort)
555{
556 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
557
558 try {
559 mongocxx::options::find find_opts{};
560 if (bson_sort) {
561 auto *bs = static_cast<bsoncxx::builder::basic::document *>(bson_sort);
562 find_opts.sort(bs->view());
563 }
564
565 auto cursor = robot_memory->query(b->view(), collection, find_opts);
566 //std::unique_ptr<mongocxx::cursor> c = new mongocxx::cursor(std::move(cursor));
567 return CLIPS::Value(new std::unique_ptr<mongocxx::cursor>(
568 new mongocxx::cursor(std::move(cursor))),
569 CLIPS::TYPE_EXTERNAL_ADDRESS);
570 } catch (std::system_error &e) {
571 logger->log_warn("MongoDB", "Query failed: %s", e.what());
572 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
573 }
574}
575
576CLIPS::Value
577ClipsRobotMemoryThread::clips_robotmemory_dump_collection(std::string collection,
578 std::string directory)
579{
580 try {
581 int succ = robot_memory->dump_collection(collection, directory);
582 if (succ == 1) {
583 return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
584 } else {
585 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
586 }
587 } catch (mongocxx::exception &e) {
588 logger->log_error("MongoDB",
589 "Dumping collection %s to %s failed: \n %s",
590 collection.c_str(),
591 directory.c_str(),
592 e.what());
593 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
594 }
595}
596
597CLIPS::Value
598ClipsRobotMemoryThread::clips_robotmemory_restore_collection(std::string collection,
599 std::string directory,
600 std::string target_collection)
601{
602 try {
603 int succ = robot_memory->restore_collection(collection, directory, target_collection);
604 if (succ == 1) {
605 return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
606 } else {
607 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
608 }
609 } catch (mongocxx::exception &e) {
610 logger->log_error("MongoDB",
611 "Restoring collection %s to %s failed: \n %s",
612 collection.c_str(),
613 directory.c_str(),
614 e.what());
615 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
616 }
617}
618
619void
620ClipsRobotMemoryThread::clips_robotmemory_remove(std::string collection, void *bson)
621{
622 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
623 try {
624 robot_memory->remove(b->view(), collection);
625 } catch (std::system_error &e) {
626 logger->log_warn("MongoDB", "Remove failed: %s", e.what());
627 }
628}
629
630CLIPS::Value
631ClipsRobotMemoryThread::clips_robotmemory_query(const std::string &collection, void *bson)
632{
633 return clips_robotmemory_query_sort(collection, bson, NULL);
634}
635
636void
637ClipsRobotMemoryThread::clips_robotmemory_cursor_destroy(void *cursor)
638{
639 auto c = static_cast<std::unique_ptr<mongocxx::cursor> *>(cursor);
640 if (!c || !c->get()) {
641 logger->log_error("MongoDB", "mongodb-cursor-destroy: got invalid cursor");
642 return;
643 }
644
645 delete c;
646}
647
648CLIPS::Value
649ClipsRobotMemoryThread::clips_robotmemory_cursor_more(void *cursor)
650{
651 throw Exception("The function cursor-more is no longer supported. Call cursor-next and check the "
652 "return value for FALSE instead.");
653}
654
655CLIPS::Value
656ClipsRobotMemoryThread::clips_robotmemory_cursor_next(void *cursor)
657{
658 auto c = static_cast<std::unique_ptr<mongocxx::cursor> *>(cursor);
659
660 if (!c || !c->get()) {
661 logger->log_error("MongoDB", "mongodb-cursor-next: got invalid cursor");
662 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
663 }
664
665 try {
666 auto it = (*c)->begin();
667 if (it == (*c)->end()) {
668 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
669 } else {
670 auto b = new bsoncxx::builder::basic::document();
671 b->append(bsoncxx::builder::concatenate(*it));
672 it++;
673 return CLIPS::Value(b);
674 }
675 } catch (std::system_error &e) {
676 logger->log_error("MongoDB", "mongodb-cursor-next: got invalid query: %s", e.what());
677 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
678 }
679}
680
681CLIPS::Values
682ClipsRobotMemoryThread::clips_bson_field_names(void *bson)
683{
684 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
685
686 if (!b) {
687 logger->log_error("MongoDB", "mongodb-bson-field-names: invalid object");
688 CLIPS::Values rv;
689 rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
690 return rv;
691 }
692
693 CLIPS::Values rv;
694 for (auto element : b->view()) {
695 rv.push_back(CLIPS::Value(std::string(element.key())));
696 }
697 return rv;
698}
699
700CLIPS::Value
701ClipsRobotMemoryThread::clips_bson_get(void *bson, std::string field_name)
702{
703 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
704
705 if (!b) {
706 logger->log_error("MongoDB", "mongodb-bson-get: invalid object");
707 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
708 }
709
710 try {
711 auto el = get_dotted_field(b->view(), field_name);
712 if (!el) {
714 "mongodb-bson-get: failed to get '%s', no such element in doc: %s",
715 field_name.c_str(),
716 bsoncxx::to_json(b->view()).c_str());
717 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
718 }
719 switch (el.type()) {
720 case bsoncxx::type::k_double: return CLIPS::Value(el.get_double());
721 case bsoncxx::type::k_utf8: return CLIPS::Value(el.get_utf8().value.to_string());
722 case bsoncxx::type::k_bool:
723 return CLIPS::Value(el.get_bool() ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
724 case bsoncxx::type::k_int32: return CLIPS::Value(el.get_int32());
725 case bsoncxx::type::k_int64: return CLIPS::Value(el.get_int64());
726 case bsoncxx::type::k_document: {
727 auto b = new bsoncxx::builder::basic::document();
728 b->append(bsoncxx::builder::concatenate(el.get_document().view()));
729 return CLIPS::Value(b);
730 }
731 case bsoncxx::type::k_oid: //ObjectId
732 return CLIPS::Value(el.get_oid().value.to_string());
733
734 default: return CLIPS::Value("INVALID_VALUE_TYPE", CLIPS::TYPE_SYMBOL);
735 }
736 } catch (std::system_error &e) {
738 "mongodb-bson-get: failed to get '%s': %s",
739 field_name.c_str(),
740 e.what());
741 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
742 }
743}
744
745CLIPS::Value
746ClipsRobotMemoryThread::clips_bson_has_field(void *bson, std::string field_name)
747{
748 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
749
750 if (!b) {
751 logger->log_error("MongoDB", "mongodb-bson-get: invalid object");
752 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
753 }
754
755 try {
756 auto el = get_dotted_field(b->view(), field_name);
757 if (!el.key().empty()) {
758 return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
759 } else {
760 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
761 }
762 } catch (bsoncxx::exception &e) {
763 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
764 }
765}
766
767CLIPS::Values
768ClipsRobotMemoryThread::clips_bson_get_array(void *bson, std::string field_name)
769{
770 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
771
772 CLIPS::Values rv;
773
774 if (!b) {
775 logger->log_error("MongoDB", "mongodb-bson-get-array: invalid object");
776 rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
777 return rv;
778 }
779
780 try {
781 auto el = get_dotted_field(b->view(), field_name);
782
783 if (el.type() != bsoncxx::type::k_array) {
784 logger->log_error("MongoDB",
785 "mongodb-bson-get-array: field %s is not an array",
786 field_name.c_str());
787 rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
788 return rv;
789 }
790
791 bsoncxx::array::view array_view{el.get_array()};
792 for (const auto e : array_view) {
793 switch (e.type()) {
794 case bsoncxx::type::k_double: rv.push_back(CLIPS::Value(e.get_double())); break;
795 case bsoncxx::type::k_utf8: rv.push_back(CLIPS::Value(e.get_utf8().value.to_string())); break;
796 case bsoncxx::type::k_bool:
797 rv.push_back(CLIPS::Value(e.get_bool() ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL));
798 break;
799 case bsoncxx::type::k_int32: rv.push_back(CLIPS::Value(e.get_int32())); break;
800 case bsoncxx::type::k_int64: rv.push_back(CLIPS::Value(e.get_int64())); break;
801 case bsoncxx::type::k_document: {
802 auto b = new bsoncxx::builder::basic::document();
803 b->append(bsoncxx::builder::concatenate(e.get_document().view()));
804 rv.push_back(CLIPS::Value(b));
805 } break;
806 default:
807 rv.clear();
808 rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
809 return rv;
810 }
811 }
812 return rv;
813 } catch (bsoncxx::exception &e) {
815 "mongodb-bson-get: failed to get '%s': %s",
816 field_name.c_str(),
817 e.what());
818 rv.clear();
819 rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
820 return rv;
821 }
822}
823
824CLIPS::Values
825ClipsRobotMemoryThread::clips_bson_get_time(void *bson, std::string field_name)
826{
827 auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
828
829 CLIPS::Values rv;
830
831 if (!b) {
832 logger->log_error("MongoDB", "mongodb-bson-get-time: invalid object");
833 rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
834 return rv;
835 }
836
837 try {
838 auto el = get_dotted_field(b->view(), field_name);
839 int64_t ts = 0;
840 if (el.type() == bsoncxx::type::k_date) {
841 bsoncxx::types::b_date d = el.get_date();
842 ts = d.to_int64();
843 } else if (el.type() == bsoncxx::type::k_timestamp) {
844 bsoncxx::types::b_timestamp t = el.get_timestamp();
845 ts = (int64_t)t.timestamp * 1000;
846 } else {
847 logger->log_error("MongoDB",
848 "mongodb-bson-get-time: field %s is not a time",
849 field_name.c_str());
850 rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
851 return rv;
852 }
853
854 rv.resize(2);
855 rv[0] = CLIPS::Value((long long int)(ts / 1000));
856 rv[1] = CLIPS::Value((ts - (rv[0].as_integer() * 1000)) * 1000);
857 return rv;
858 } catch (bsoncxx::exception &e) {
859 rv.resize(2, CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
860 return rv;
861 }
862}
863
864CLIPS::Value
865ClipsRobotMemoryThread::clips_robotmemory_register_trigger(std::string env_name,
866 std::string collection,
867 void * query,
868 std::string assert_name)
869{
870 bsoncxx::document::value b{static_cast<bsoncxx::builder::basic::document *>(query)->view()};
871 std::string future_name = "register_trigger_" + assert_name;
872 if (!mutex_future_ready(future_name)) {
873 MutexLocker clips_lock(envs_[env_name].objmutex_ptr());
874 envs_[env_name]->assert_fact_f("(mutex-trigger-register-feedback FAIL \"%s\")",
875 assert_name.c_str());
876 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
877 }
878 auto fut = std::async(std::launch::async, [this, b, env_name, collection, assert_name] {
879 try {
880 ClipsRmTrigger *clips_trigger =
881 new ClipsRmTrigger(assert_name, robot_memory, envs_[env_name], logger);
883 b.view(), collection, &ClipsRmTrigger::callback, clips_trigger));
884 MutexLocker triggers_lock(&clips_triggers_mutex_);
885 clips_triggers_.push_back(clips_trigger);
886 MutexLocker clips_lock(envs_[env_name].objmutex_ptr());
887 envs_[env_name]->assert_fact_f("(mutex-trigger-register-feedback SUCCESS \"%s\" %p)",
888 assert_name.c_str(),
889 CLIPS::Value(clips_trigger).as_address());
890 return true;
891 } catch (std::system_error &e) {
892 logger->log_warn(name(), "Error while registering trigger: %s", e.what());
893 MutexLocker clips_lock(envs_[env_name].objmutex_ptr());
894 envs_[env_name]->assert_fact_f("(mutex-trigger-register-feedback FAIL \"%s\")",
895 assert_name.c_str());
896 return false;
897 }
898 });
899
900 mutex_futures_[future_name] = std::move(fut);
901 return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
902}
903
904void
905ClipsRobotMemoryThread::clips_robotmemory_destroy_trigger(void *trigger)
906{
907 ClipsRmTrigger *clips_trigger = static_cast<ClipsRmTrigger *>(trigger);
908 MutexLocker triggers_lock(&clips_triggers_mutex_);
909 clips_triggers_.remove(clips_trigger);
910 delete clips_trigger; //the triger unregisteres itself at the robot memory
911}
912
913CLIPS::Value
914ClipsRobotMemoryThread::clips_robotmemory_mutex_create(std::string name)
915{
916 bool rv = robot_memory->mutex_create(name);
917 return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
918}
919
920CLIPS::Value
921ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy(std::string name)
922{
923 bool rv = robot_memory->mutex_destroy(name);
924 return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
925}
926
927CLIPS::Value
928ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock(std::string name, std::string identity)
929{
930 bool rv = robot_memory->mutex_try_lock(name, identity);
931 return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
932}
933
934CLIPS::Value
935ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock(std::string name, std::string identity)
936{
937 bool rv = robot_memory->mutex_renew_lock(name, identity);
938 return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
939}
940
941CLIPS::Value
942ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock(std::string name, std::string identity)
943{
944 bool rv = robot_memory->mutex_try_lock(name, identity, /* force */ true);
945 return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
946}
947
948CLIPS::Value
949ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock(std::string name, std::string identity)
950{
951 bool rv = robot_memory->mutex_unlock(name, identity);
952 return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
953}
954
955CLIPS::Value
956ClipsRobotMemoryThread::clips_robotmemory_mutex_setup_ttl(float max_age_sec)
957{
958 bool rv = robot_memory->mutex_setup_ttl(max_age_sec);
959 return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
960}
961
962CLIPS::Value
963ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks(float max_age_sec)
964{
965 bool rv = robot_memory->mutex_expire_locks(max_age_sec);
966 return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
967}
968
969bool
970ClipsRobotMemoryThread::mutex_future_ready(const std::string &name)
971{
972 auto mf_it = mutex_futures_.find(name);
973 if (mf_it != mutex_futures_.end()) {
974 auto fut_status = mutex_futures_[name].wait_for(std::chrono::milliseconds(0));
975 if (fut_status != std::future_status::ready) {
976 return false;
977 } else {
978 mutex_futures_.erase(mf_it);
979 }
980 }
981 return true;
982}
983
984CLIPS::Values
985ClipsRobotMemoryThread::clips_robotmemory_mutex_create_async(std::string name)
986{
987 CLIPS::Values rv;
988 if (!mutex_future_ready(name)) {
989 rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
990 rv.push_back(CLIPS::Value("Task already running for " + name + " (create failed)"));
991 return rv;
992 }
993
994 auto fut =
995 std::async(std::launch::async, [this, name] { return robot_memory->mutex_create(name); });
996
997 mutex_futures_[name] = std::move(fut);
998
999 rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1000 return rv;
1001}
1002
1003CLIPS::Values
1004ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy_async(std::string name)
1005{
1006 CLIPS::Values rv;
1007 if (!mutex_future_ready(name)) {
1008 rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
1009 rv.push_back(CLIPS::Value("Task already running for " + name + " (destroy failed)"));
1010 return rv;
1011 }
1012
1013 auto fut =
1014 std::async(std::launch::async, [this, name] { return robot_memory->mutex_destroy(name); });
1015
1016 mutex_futures_[name] = std::move(fut);
1017
1018 rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1019 return rv;
1020}
1021
1022CLIPS::Values
1023ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock_async(std::string env_name,
1024 std::string name,
1025 std::string identity)
1026{
1027 CLIPS::Values rv;
1028 if (!mutex_future_ready(name)) {
1029 rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
1030 rv.push_back(CLIPS::Value("Task already running for " + name + " (try-lock failed)"));
1031 envs_[env_name]->assert_fact_f("(mutex-op-feedback try-lock-async FAIL %s)", name.c_str());
1032 return rv;
1033 }
1034
1035 auto fut = std::async(std::launch::async, [this, env_name, name, identity] {
1036 bool ok = robot_memory->mutex_try_lock(name, identity);
1037 if (!ok) {
1038 MutexLocker lock(envs_[env_name].objmutex_ptr());
1039 envs_[env_name]->assert_fact_f("(mutex-op-feedback try-lock-async FAIL %s)", name.c_str());
1040 }
1041 return ok;
1042 });
1043
1044 mutex_futures_[name] = std::move(fut);
1045
1046 rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1047 return rv;
1048}
1049
1050CLIPS::Values
1051ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock_async(std::string env_name,
1052 std::string name,
1053 std::string identity)
1054{
1055 CLIPS::Values rv;
1056 if (!mutex_future_ready(name)) {
1057 rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
1058 rv.push_back(CLIPS::Value("Task already running for " + name + " (try-lock failed)"));
1059 MutexLocker lock(envs_[env_name].objmutex_ptr());
1060 envs_[env_name]->assert_fact_f("(mutex-op-feedback renew-lock-async FAIL %s)", name.c_str());
1061 return rv;
1062 }
1063
1064 auto fut = std::async(std::launch::async, [this, env_name, name, identity] {
1065 bool ok = robot_memory->mutex_renew_lock(name, identity);
1066 MutexLocker lock(envs_[env_name].objmutex_ptr());
1067 envs_[env_name]->assert_fact_f("(mutex-op-feedback renew-lock-async %s %s)",
1068 ok ? "OK" : "FAIL",
1069 name.c_str());
1070 return ok;
1071 });
1072
1073 mutex_futures_[name] = std::move(fut);
1074
1075 rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1076 return rv;
1077}
1078
1079CLIPS::Values
1080ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock_async(std::string name,
1081 std::string identity)
1082{
1083 CLIPS::Values rv;
1084 if (!mutex_future_ready(name)) {
1085 rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
1086 rv.push_back(CLIPS::Value("Task already running for " + name + " (force-lock failed)"));
1087 return rv;
1088 }
1089
1090 auto fut = std::async(std::launch::async, [this, name, identity] {
1091 return robot_memory->mutex_try_lock(name, identity, /* force */ true);
1092 });
1093
1094 mutex_futures_[name] = std::move(fut);
1095
1096 rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1097 return rv;
1098}
1099
1100CLIPS::Values
1101ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock_async(std::string name, std::string identity)
1102{
1103 CLIPS::Values rv;
1104 if (!mutex_future_ready(name)) {
1105 rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
1106 rv.push_back(CLIPS::Value("Task already running for " + name + " (unlock failed)"));
1107 return rv;
1108 }
1109
1110 auto fut = std::async(std::launch::async, [this, name, identity] {
1111 return robot_memory->mutex_unlock(name, identity);
1112 });
1113
1114 mutex_futures_[name] = std::move(fut);
1115
1116 rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1117 return rv;
1118}
1119
1120CLIPS::Value
1121ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks_async(std::string env_name,
1122 float max_age_sec)
1123{
1124 CLIPS::Values rv;
1125 if (mutex_expire_future_.valid()) {
1126 // have shared state, expire was or is running
1127 auto fut_status = mutex_expire_future_.wait_for(std::chrono::milliseconds(0));
1128 if (fut_status != std::future_status::ready) {
1129 MutexLocker lock(envs_[env_name].objmutex_ptr());
1130 envs_[env_name]->assert_fact_f("(mutex-op-feedback expire-locks-async FAIL)");
1131 return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
1132 }
1133 }
1134
1135 auto fut = std::async(std::launch::async, [this, env_name, max_age_sec] {
1136 bool ok = robot_memory->mutex_expire_locks(max_age_sec);
1137 MutexLocker lock(envs_[env_name].objmutex_ptr());
1138 envs_[env_name]->assert_fact_f("(mutex-op-feedback expire-locks-async %s)", ok ? "OK" : "FAIL");
1139 return ok;
1140 });
1141
1142 mutex_expire_future_ = std::move(fut);
1143
1144 return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
1145}
void callback(const bsoncxx::document::view &update)
Callback function for the trigger.
void set_trigger(EventTrigger *trigger)
Set the trigger object given by the robot memory.
virtual void loop()
Code to execute in the thread.
virtual void finalize()
Finalize the thread.
virtual void clips_context_destroyed(const std::string &env_name)
Notification that a CLIPS environment has been destroyed.
virtual void init()
Initialize the thread.
virtual void clips_context_init(const std::string &env_name, fawkes::LockPtr< CLIPS::Environment > &clips)
Initialize a CLIPS context to use the provided feature.
bool mutex_create(const std::string &name)
Explicitly create a mutex.
int dump_collection(const std::string &dbcollection, const std::string &directory="@CONFDIR@/robot-memory")
Dump (= save) a collection to the filesystem to restore it later.
bool mutex_destroy(const std::string &name)
Destroy a mutex.
bool mutex_renew_lock(const std::string &name, const std::string &identity)
Renew a mutex.
bool mutex_unlock(const std::string &name, const std::string &identity)
Release lock on mutex.
EventTrigger * register_trigger(const bsoncxx::document::view &query, const std::string &collection, void(T::*callback)(const bsoncxx::document::view &), T *_obj)
Register a trigger to be notified when the robot memory is updated and the updated document matches t...
Definition: robot_memory.h:119
mongocxx::cursor query(bsoncxx::document::view query, const std::string &collection_name="", mongocxx::options::find query_options=mongocxx::options::find())
Query information from the robot memory.
bool mutex_setup_ttl(float max_age_sec)
Setup time-to-live index for mutexes.
int remove(const bsoncxx::document::view &query, const std::string &collection="")
Remove documents from the robot memory.
int insert(bsoncxx::document::view, const std::string &collection="")
Inserts a document into the robot memory.
int update(const bsoncxx::document::view &query, const bsoncxx::document::view &update, const std::string &collection="", bool upsert=false)
Updates documents in the robot memory.
bool mutex_try_lock(const std::string &name, bool force=false)
Try to acquire a lock for a mutex.
int create_index(bsoncxx::document::view keys, const std::string &collection="", bool unique=false)
Create an index on a collection.
int restore_collection(const std::string &dbcollection, const std::string &directory="@CONFDIR@/robot-memory", std::string target_dbcollection="")
Restore a previously dumped collection from a directory.
bool mutex_expire_locks(float max_age_sec)
Expire old locks on mutexes.
Thread aspect to provide a feature to CLIPS environments.
Definition: clips_feature.h:58
CLIPS feature maintainer.
Definition: clips_feature.h:42
Base class for exceptions in Fawkes.
Definition: exception.h:36
void lock() const
Lock access to the encapsulated object.
Definition: lockptr.h:257
void unlock() const
Unlock object mutex.
Definition: lockptr.h:273
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
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
virtual void log_error(const char *component, const char *format,...)
Log error message.
Definition: multi.cpp:237
Mutex locking helper.
Definition: mutex_locker.h:34
RobotMemory * robot_memory
RobotMemory object for storing and querying information.
Thread class encapsulation of pthreads.
Definition: thread.h:46
const char * name() const
Get name of thread.
Definition: thread.h:100
Fawkes library namespace.