23 #include "clips_robot_memory_thread.h"
25 #include <core/threading/mutex_locker.h>
26 #include <plugins/mongodb/utils.h>
28 #include <bsoncxx/document/element.hpp>
29 #include <bsoncxx/exception/exception.hpp>
30 #include <bsoncxx/types.hpp>
31 #include <mongocxx/exception/exception.hpp>
42 ClipsRobotMemoryThread::ClipsRobotMemoryThread()
43 :
Thread(
"ClipsRobotMemoryThread",
Thread::OPMODE_WAITFORWAKEUP),
72 envs_[env_name] = clips;
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, void *, std::string>(
97 sigc::mem_fun(*
this, &ClipsRobotMemoryThread::clips_bson_array_start)));
98 clips->add_function(
"bson-array-finish",
99 sigc::slot<void, 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)));
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 *>(
132 &ClipsRobotMemoryThread::clips_robotmemory_query_sort)));
133 clips->add_function(
"robmem-dump-collection",
134 sigc::slot<CLIPS::Value, std::string, std::string>(
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 *>(
143 &ClipsRobotMemoryThread::clips_robotmemory_cursor_destroy)));
144 clips->add_function(
"robmem-cursor-more",
145 sigc::slot<CLIPS::Value, void *>(
147 &ClipsRobotMemoryThread::clips_robotmemory_cursor_more)));
148 clips->add_function(
"robmem-cursor-next",
149 sigc::slot<CLIPS::Value, void *>(
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>(
155 &ClipsRobotMemoryThread::clips_robotmemory_register_trigger),
157 clips->add_function(
"robmem-trigger-destroy",
158 sigc::slot<void, void *>(
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 *>(
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)));
184 clips->add_function(
"robmem-mutex-create",
185 sigc::slot<CLIPS::Value, std::string>(
187 &ClipsRobotMemoryThread::clips_robotmemory_mutex_create)));
188 clips->add_function(
"robmem-mutex-destroy",
189 sigc::slot<CLIPS::Value, std::string>(
191 &ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy)));
192 clips->add_function(
"robmem-mutex-try-lock",
193 sigc::slot<CLIPS::Value, std::string, std::string>(
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>(
205 &ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock)));
206 clips->add_function(
"robmem-mutex-setup-ttl",
207 sigc::slot<CLIPS::Value, float>(
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)));
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)));
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),
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),
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)));
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),
242 clips->build(
"(deffacts have-feature-mongodb (have-feature MongoDB))");
245 clips->batch_evaluate(SRCDIR
"/robot-memory.clp");
253 envs_.erase(env_name);
258 ClipsRobotMemoryThread::clips_bson_create()
260 return CLIPS::Value(
new bsoncxx::builder::basic::document());
264 ClipsRobotMemoryThread::clips_bson_parse(std::string document)
266 auto b =
new bsoncxx::builder::basic::document();
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());
272 return CLIPS::Value(b);
276 ClipsRobotMemoryThread::clips_bson_destroy(
void *bson)
278 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
283 ClipsRobotMemoryThread::clips_bson_tostring(
void *bson)
285 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
286 return bsoncxx::to_json(b->view());
290 ClipsRobotMemoryThread::clips_bson_append(
void *bson, std::string field_name, CLIPS::Value value)
292 using namespace bsoncxx::builder;
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;
298 case CLIPS::TYPE_INTEGER:
299 b->append(basic::kvp(field_name,
static_cast<int64_t
>(value.as_integer())));
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()));
311 logger->
log_warn(
"RefBox",
"Tried to add unknown type to BSON field %s", field_name.c_str());
314 }
catch (bsoncxx::exception &e) {
316 "Failed to append array value to field %s: %s",
323 ClipsRobotMemoryThread::clips_bson_append_regex(
void * bson,
324 std::string field_name,
325 CLIPS::Value regex_string)
327 using namespace bsoncxx::builder;
328 if (regex_string.type() != CLIPS::TYPE_STRING) {
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) {
337 "Failed to append regex to field %s: %s",
344 ClipsRobotMemoryThread::clips_bson_append_array(
void * bson,
345 std::string field_name,
346 CLIPS::Values values)
348 using namespace bsoncxx::builder;
350 auto b =
static_cast<basic::document *
>(bson);
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;
357 case CLIPS::TYPE_INTEGER: array.append(static_cast<int64_t>(value.as_integer())); break;
359 case CLIPS::TYPE_SYMBOL:
360 case CLIPS::TYPE_STRING:
361 case CLIPS::TYPE_INSTANCE_NAME: array.append(value.as_string()); break;
363 case CLIPS::TYPE_EXTERNAL_ADDRESS: {
364 auto subb = static_cast<bsoncxx::builder::basic::document *>(value.as_address());
365 array.append(subb->view());
370 "Tried to add unknown type to BSON array field %s",
376 }
catch (bsoncxx::exception &e) {
378 "Failed to append array value to field %s: %s",
385 ClipsRobotMemoryThread::clips_bson_array_start(
void *bson, std::string field_name)
399 ClipsRobotMemoryThread::clips_bson_array_finish(
void *barr)
409 ClipsRobotMemoryThread::clips_bson_array_append(
void *barr, CLIPS::Value value)
442 ClipsRobotMemoryThread::clips_bson_append_time(
void * bson,
443 std::string field_name,
446 if (time.size() != 2) {
447 logger->
log_warn(
"MongoDB",
"Invalid time, %zu instead of 2 entries", time.size());
450 if (time[0].type() != CLIPS::TYPE_INTEGER || time[1].type() != CLIPS::TYPE_INTEGER) {
456 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
457 struct timeval now = {time[0].as_integer(), time[1].as_integer()};
458 bsoncxx::types::b_date nowd{
459 std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>{
460 std::chrono::milliseconds{now.tv_sec * 1000 + now.tv_usec / 1000}}};
461 b->append(bsoncxx::builder::basic::kvp(field_name, nowd));
462 }
catch (bsoncxx::exception &e) {
464 "Failed to append time value to field %s: %s",
471 ClipsRobotMemoryThread::clips_robotmemory_insert(std::string collection,
void *bson)
473 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
477 }
catch (mongocxx::exception &e) {
483 ClipsRobotMemoryThread::clips_robotmemory_create_index(std::string collection,
void *bson)
485 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
489 }
catch (mongocxx::exception &e) {
490 logger->
log_warn(
"MongoDB",
"Creating index failed: %s", e.what());
495 ClipsRobotMemoryThread::clips_robotmemory_create_unique_index(std::string collection,
void *bson)
497 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
501 }
catch (mongocxx::exception &e) {
502 logger->
log_warn(
"MongoDB",
"Creating unique index failed: %s", e.what());
507 ClipsRobotMemoryThread::robotmemory_update(std::string & collection,
508 const bsoncxx::document::view &update,
509 CLIPS::Value & query,
513 if (query.type() == CLIPS::TYPE_STRING) {
514 robot_memory->
update(bsoncxx::from_json(query.as_string()), update, collection, upsert);
515 }
else if (query.type() == CLIPS::TYPE_EXTERNAL_ADDRESS) {
516 bsoncxx::builder::basic::document *qb =
517 static_cast<bsoncxx::builder::basic::document *
>(query.as_address());
520 logger->
log_warn(
"MongoDB",
"Invalid query, must be string or BSON document");
524 }
catch (bsoncxx::exception &e) {
525 logger->
log_warn(
"MongoDB",
"Compiling query failed: %s", e.what());
526 }
catch (mongocxx::exception &e) {
532 ClipsRobotMemoryThread::clips_robotmemory_upsert(std::string collection,
536 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
541 robotmemory_update(collection, b->view(), query,
true);
545 ClipsRobotMemoryThread::clips_robotmemory_update(std::string collection,
549 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
554 robotmemory_update(collection, b->view(), query,
false);
558 ClipsRobotMemoryThread::clips_robotmemory_replace(std::string collection,
562 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
565 robotmemory_update(collection, b->view(), query,
false);
569 ClipsRobotMemoryThread::clips_robotmemory_query_sort(std::string collection,
573 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
576 mongocxx::options::find find_opts{};
578 auto *bs =
static_cast<bsoncxx::builder::basic::document *
>(bson_sort);
579 find_opts.sort(bs->view());
584 return CLIPS::Value(
new std::unique_ptr<mongocxx::cursor>(
585 new mongocxx::cursor(std::move(cursor))),
586 CLIPS::TYPE_EXTERNAL_ADDRESS);
587 }
catch (std::system_error &e) {
589 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
594 ClipsRobotMemoryThread::clips_robotmemory_dump_collection(std::string collection,
595 std::string directory)
600 return CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL);
602 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
604 }
catch (mongocxx::exception &e) {
606 "Dumping collection %s to %s failed: \n %s",
610 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
615 ClipsRobotMemoryThread::clips_robotmemory_restore_collection(std::string collection,
616 std::string directory,
617 std::string target_collection)
622 return CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL);
624 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
626 }
catch (mongocxx::exception &e) {
628 "Restoring collection %s to %s failed: \n %s",
632 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
637 ClipsRobotMemoryThread::clips_robotmemory_remove(std::string collection,
void *bson)
639 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
642 }
catch (std::system_error &e) {
648 ClipsRobotMemoryThread::clips_robotmemory_query(
const std::string &collection,
void *bson)
650 return clips_robotmemory_query_sort(collection, bson, NULL);
654 ClipsRobotMemoryThread::clips_robotmemory_cursor_destroy(
void *cursor)
656 auto c =
static_cast<std::unique_ptr<mongocxx::cursor> *
>(cursor);
657 if (!c || !c->get()) {
658 logger->
log_error(
"MongoDB",
"mongodb-cursor-destroy: got invalid cursor");
666 ClipsRobotMemoryThread::clips_robotmemory_cursor_more(
void *cursor)
668 throw Exception(
"The function cursor-more is no longer supported. Call cursor-next and check the "
669 "return value for FALSE instead.");
673 ClipsRobotMemoryThread::clips_robotmemory_cursor_next(
void *cursor)
675 auto c =
static_cast<std::unique_ptr<mongocxx::cursor> *
>(cursor);
677 if (!c || !c->get()) {
678 logger->
log_error(
"MongoDB",
"mongodb-cursor-next: got invalid cursor");
679 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
683 auto it = (*c)->begin();
684 if (it == (*c)->end()) {
685 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
687 auto b =
new bsoncxx::builder::basic::document();
688 b->append(bsoncxx::builder::concatenate(*it));
690 return CLIPS::Value(b);
692 }
catch (std::system_error &e) {
693 logger->
log_error(
"MongoDB",
"mongodb-cursor-next: got invalid query: %s", e.what());
694 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
699 ClipsRobotMemoryThread::clips_bson_field_names(
void *bson)
701 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
704 logger->
log_error(
"MongoDB",
"mongodb-bson-field-names: invalid object");
706 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
711 for (
auto element : b->view()) {
712 rv.push_back(CLIPS::Value(std::string(element.key())));
718 ClipsRobotMemoryThread::clips_bson_get(
void *bson, std::string field_name)
720 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
724 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
728 auto el = get_dotted_field(b->view(), field_name);
731 "mongodb-bson-get: failed to get '%s', no such element in doc: %s",
733 bsoncxx::to_json(b->view()).c_str());
734 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
737 case bsoncxx::type::k_double:
return CLIPS::Value(el.get_double());
738 case bsoncxx::type::k_utf8:
return CLIPS::Value(el.get_utf8().value.to_string());
739 case bsoncxx::type::k_bool:
740 return CLIPS::Value(el.get_bool() ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
741 case bsoncxx::type::k_int32:
return CLIPS::Value(el.get_int32());
742 case bsoncxx::type::k_int64:
return CLIPS::Value(el.get_int64());
743 case bsoncxx::type::k_document: {
744 auto b =
new bsoncxx::builder::basic::document();
745 b->append(bsoncxx::builder::concatenate(el.get_document().view()));
746 return CLIPS::Value(b);
748 case bsoncxx::type::k_oid:
749 return CLIPS::Value(el.get_oid().value.to_string());
751 default:
return CLIPS::Value(
"INVALID_VALUE_TYPE", CLIPS::TYPE_SYMBOL);
753 }
catch (std::system_error &e) {
755 "mongodb-bson-get: failed to get '%s': %s",
758 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
763 ClipsRobotMemoryThread::clips_bson_has_field(
void *bson, std::string field_name)
765 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
769 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
773 auto el = get_dotted_field(b->view(), field_name);
774 if (!el.key().empty()) {
775 return CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL);
777 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
779 }
catch (bsoncxx::exception &e) {
780 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
785 ClipsRobotMemoryThread::clips_bson_get_array(
void *bson, std::string field_name)
787 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
792 logger->
log_error(
"MongoDB",
"mongodb-bson-get-array: invalid object");
793 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
798 auto el = get_dotted_field(b->view(), field_name);
800 if (el.type() != bsoncxx::type::k_array) {
802 "mongodb-bson-get-array: field %s is not an array",
804 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
808 bsoncxx::array::view array_view{el.get_array()};
809 for (
const auto e : array_view) {
811 case bsoncxx::type::k_double: rv.push_back(CLIPS::Value(e.get_double()));
break;
812 case bsoncxx::type::k_utf8: rv.push_back(CLIPS::Value(e.get_utf8().value.to_string()));
break;
813 case bsoncxx::type::k_bool:
814 rv.push_back(CLIPS::Value(e.get_bool() ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL));
816 case bsoncxx::type::k_int32: rv.push_back(CLIPS::Value(e.get_int32()));
break;
817 case bsoncxx::type::k_int64: rv.push_back(CLIPS::Value(e.get_int64()));
break;
818 case bsoncxx::type::k_document: {
819 auto b =
new bsoncxx::builder::basic::document();
820 b->append(bsoncxx::builder::concatenate(e.get_document().view()));
821 rv.push_back(CLIPS::Value(b));
825 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
830 }
catch (bsoncxx::exception &e) {
832 "mongodb-bson-get: failed to get '%s': %s",
836 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
842 ClipsRobotMemoryThread::clips_bson_get_time(
void *bson, std::string field_name)
844 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
850 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
855 auto el = get_dotted_field(b->view(), field_name);
857 if (el.type() == bsoncxx::type::k_date) {
858 bsoncxx::types::b_date d = el.get_date();
860 }
else if (el.type() == bsoncxx::type::k_timestamp) {
861 bsoncxx::types::b_timestamp t = el.get_timestamp();
862 ts = (int64_t)t.timestamp * 1000;
865 "mongodb-bson-get-time: field %s is not a time",
867 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
872 rv[0] = CLIPS::Value((
long long int)(ts / 1000));
873 rv[1] = CLIPS::Value((ts - (rv[0].as_integer() * 1000)) * 1000);
875 }
catch (bsoncxx::exception &e) {
876 rv.resize(2, CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
882 ClipsRobotMemoryThread::clips_robotmemory_register_trigger(std::string env_name,
883 std::string collection,
885 std::string assert_name)
887 bsoncxx::document::value b{
static_cast<bsoncxx::builder::basic::document *
>(query)->view()};
888 std::string future_name =
"register_trigger_" + assert_name;
889 if (!mutex_future_ready(future_name)) {
890 MutexLocker clips_lock(envs_[env_name].objmutex_ptr());
891 envs_[env_name]->assert_fact_f(
"(mutex-trigger-register-feedback FAIL \"%s\")",
892 assert_name.c_str());
893 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
895 auto fut = std::async(std::launch::async, [
this, b, env_name, collection, assert_name] {
902 clips_triggers_.push_back(clips_trigger);
903 MutexLocker clips_lock(envs_[env_name].objmutex_ptr());
904 envs_[env_name]->assert_fact_f(
"(mutex-trigger-register-feedback SUCCESS \"%s\" %p)",
906 CLIPS::Value(clips_trigger).as_address());
908 }
catch (std::system_error &e) {
910 MutexLocker clips_lock(envs_[env_name].objmutex_ptr());
911 envs_[env_name]->assert_fact_f(
"(mutex-trigger-register-feedback FAIL \"%s\")",
912 assert_name.c_str());
917 mutex_futures_[future_name] = std::move(fut);
918 return CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL);
922 ClipsRobotMemoryThread::clips_robotmemory_destroy_trigger(
void *trigger)
926 clips_triggers_.remove(clips_trigger);
927 delete clips_trigger;
931 ClipsRobotMemoryThread::clips_robotmemory_mutex_create(std::string
name)
934 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
938 ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy(std::string
name)
941 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
945 ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock(std::string
name, std::string identity)
948 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
952 ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock(std::string
name, std::string identity)
955 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
959 ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock(std::string
name, std::string identity)
962 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
966 ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock(std::string
name, std::string identity)
969 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
973 ClipsRobotMemoryThread::clips_robotmemory_mutex_setup_ttl(
float max_age_sec)
976 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
980 ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks(
float max_age_sec)
983 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
987 ClipsRobotMemoryThread::mutex_future_ready(
const std::string &
name)
989 auto mf_it = mutex_futures_.find(
name);
990 if (mf_it != mutex_futures_.end()) {
991 auto fut_status = mutex_futures_[
name].wait_for(std::chrono::milliseconds(0));
992 if (fut_status != std::future_status::ready) {
995 mutex_futures_.erase(mf_it);
1002 ClipsRobotMemoryThread::clips_robotmemory_mutex_create_async(std::string
name)
1005 if (!mutex_future_ready(
name)) {
1006 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
1007 rv.push_back(CLIPS::Value(
"Task already running for " +
name +
" (create failed)"));
1014 mutex_futures_[
name] = std::move(fut);
1016 rv.push_back(CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL));
1021 ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy_async(std::string
name)
1024 if (!mutex_future_ready(
name)) {
1025 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
1026 rv.push_back(CLIPS::Value(
"Task already running for " +
name +
" (destroy failed)"));
1033 mutex_futures_[
name] = std::move(fut);
1035 rv.push_back(CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL));
1040 ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock_async(std::string env_name,
1042 std::string identity)
1045 if (!mutex_future_ready(
name)) {
1046 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
1047 rv.push_back(CLIPS::Value(
"Task already running for " +
name +
" (try-lock failed)"));
1048 envs_[env_name]->assert_fact_f(
"(mutex-op-feedback try-lock-async FAIL %s)",
name.c_str());
1052 auto fut = std::async(std::launch::async, [
this, env_name,
name, identity] {
1056 envs_[env_name]->assert_fact_f(
"(mutex-op-feedback try-lock-async FAIL %s)",
name.c_str());
1061 mutex_futures_[
name] = std::move(fut);
1063 rv.push_back(CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL));
1068 ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock_async(std::string env_name,
1070 std::string identity)
1073 if (!mutex_future_ready(
name)) {
1074 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
1075 rv.push_back(CLIPS::Value(
"Task already running for " +
name +
" (try-lock failed)"));
1077 envs_[env_name]->assert_fact_f(
"(mutex-op-feedback renew-lock-async FAIL %s)",
name.c_str());
1081 auto fut = std::async(std::launch::async, [
this, env_name,
name, identity] {
1084 envs_[env_name]->assert_fact_f(
"(mutex-op-feedback renew-lock-async %s %s)",
1090 mutex_futures_[
name] = std::move(fut);
1092 rv.push_back(CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL));
1097 ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock_async(std::string
name,
1098 std::string identity)
1101 if (!mutex_future_ready(
name)) {
1102 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
1103 rv.push_back(CLIPS::Value(
"Task already running for " +
name +
" (force-lock failed)"));
1107 auto fut = std::async(std::launch::async, [
this,
name, identity] {
1111 mutex_futures_[
name] = std::move(fut);
1113 rv.push_back(CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL));
1118 ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock_async(std::string
name, std::string identity)
1121 if (!mutex_future_ready(
name)) {
1122 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
1123 rv.push_back(CLIPS::Value(
"Task already running for " +
name +
" (unlock failed)"));
1127 auto fut = std::async(std::launch::async, [
this,
name, identity] {
1131 mutex_futures_[
name] = std::move(fut);
1133 rv.push_back(CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL));
1138 ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks_async(std::string env_name,
1142 if (mutex_expire_future_.valid()) {
1144 auto fut_status = mutex_expire_future_.wait_for(std::chrono::milliseconds(0));
1145 if (fut_status != std::future_status::ready) {
1147 envs_[env_name]->assert_fact_f(
"(mutex-op-feedback expire-locks-async FAIL)");
1148 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
1152 auto fut = std::async(std::launch::async, [
this, env_name, max_age_sec] {
1155 envs_[env_name]->assert_fact_f(
"(mutex-op-feedback expire-locks-async %s)", ok ?
"OK" :
"FAIL");
1159 mutex_expire_future_ = std::move(fut);
1161 return CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL);
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.
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.
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...
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.
CLIPS feature maintainer.
Base class for exceptions in Fawkes.
void lock() const
Lock access to the encapsulated object.
void unlock() const
Unlock object mutex.
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.
RobotMemory * robot_memory
RobotMemory object for storing and querying information.
Thread class encapsulation of pthreads.
const char * name() const
Get name of thread.
Fawkes library namespace.