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-cursor-destroy",
134 sigc::slot<void, void *>(
136 &ClipsRobotMemoryThread::clips_robotmemory_cursor_destroy)));
137 clips->add_function(
"robmem-cursor-more",
138 sigc::slot<CLIPS::Value, void *>(
140 &ClipsRobotMemoryThread::clips_robotmemory_cursor_more)));
141 clips->add_function(
"robmem-cursor-next",
142 sigc::slot<CLIPS::Value, void *>(
144 &ClipsRobotMemoryThread::clips_robotmemory_cursor_next)));
145 clips->add_function(
"robmem-trigger-register",
146 sigc::slot<CLIPS::Value, std::string, void *, std::string>(sigc::bind<0>(
148 &ClipsRobotMemoryThread::clips_robotmemory_register_trigger),
150 clips->add_function(
"robmem-trigger-destroy",
151 sigc::slot<void, void *>(
153 &ClipsRobotMemoryThread::clips_robotmemory_destroy_trigger)));
154 clips->add_function(
"bson-field-names",
155 sigc::slot<CLIPS::Values, void *>(
156 sigc::mem_fun(*
this, &ClipsRobotMemoryThread::clips_bson_field_names)));
157 clips->add_function(
"bson-has-field",
158 sigc::slot<CLIPS::Value, void *, std::string>(
159 sigc::mem_fun(*
this, &ClipsRobotMemoryThread::clips_bson_has_field)));
160 clips->add_function(
"bson-get",
161 sigc::slot<CLIPS::Value, void *, std::string>(
162 sigc::mem_fun(*
this, &ClipsRobotMemoryThread::clips_bson_get)));
163 clips->add_function(
"bson-get-array",
164 sigc::slot<CLIPS::Values, void *, std::string>(
165 sigc::mem_fun(*
this, &ClipsRobotMemoryThread::clips_bson_get_array)));
166 clips->add_function(
"bson-get-time",
167 sigc::slot<CLIPS::Values, void *, std::string>(
168 sigc::mem_fun(*
this, &ClipsRobotMemoryThread::clips_bson_get_time)));
169 clips->add_function(
"robmem-create-index",
170 sigc::slot<void, std::string, void *>(
172 &ClipsRobotMemoryThread::clips_robotmemory_create_index)));
173 clips->add_function(
"robmem-create-unique-index",
174 sigc::slot<void, std::string, void *>(sigc::mem_fun(
175 *
this, &ClipsRobotMemoryThread::clips_robotmemory_create_unique_index)));
177 clips->add_function(
"robmem-mutex-create",
178 sigc::slot<CLIPS::Value, std::string>(
180 &ClipsRobotMemoryThread::clips_robotmemory_mutex_create)));
181 clips->add_function(
"robmem-mutex-destroy",
182 sigc::slot<CLIPS::Value, std::string>(
184 &ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy)));
185 clips->add_function(
"robmem-mutex-try-lock",
186 sigc::slot<CLIPS::Value, std::string, std::string>(
188 &ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock)));
189 clips->add_function(
"robmem-mutex-renew-lock",
190 sigc::slot<CLIPS::Value, std::string, std::string>(sigc::mem_fun(
191 *
this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock)));
192 clips->add_function(
"robmem-mutex-force-lock",
193 sigc::slot<CLIPS::Value, std::string, std::string>(sigc::mem_fun(
194 *
this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock)));
195 clips->add_function(
"robmem-mutex-unlock",
196 sigc::slot<CLIPS::Value, std::string, std::string>(
198 &ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock)));
199 clips->add_function(
"robmem-mutex-setup-ttl",
200 sigc::slot<CLIPS::Value, float>(
202 &ClipsRobotMemoryThread::clips_robotmemory_mutex_setup_ttl)));
203 clips->add_function(
"robmem-mutex-expire-locks",
204 sigc::slot<CLIPS::Value, float>(sigc::mem_fun(
205 *
this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks)));
207 clips->add_function(
"robmem-mutex-create-async",
208 sigc::slot<CLIPS::Values, std::string>(sigc::mem_fun(
209 *
this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_create_async)));
210 clips->add_function(
"robmem-mutex-destroy-async",
211 sigc::slot<CLIPS::Values, std::string>(sigc::mem_fun(
212 *
this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy_async)));
214 "robmem-mutex-try-lock-async",
215 sigc::slot<CLIPS::Values, std::string, std::string>(sigc::bind<0>(
216 sigc::mem_fun(*
this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock_async),
219 "robmem-mutex-renew-lock-async",
220 sigc::slot<CLIPS::Values, std::string, std::string>(sigc::bind<0>(
221 sigc::mem_fun(*
this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock_async),
223 clips->add_function(
"robmem-mutex-force-lock-async",
224 sigc::slot<CLIPS::Values, std::string, std::string>(sigc::mem_fun(
225 *
this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock_async)));
226 clips->add_function(
"robmem-mutex-unlock-async",
227 sigc::slot<CLIPS::Values, std::string, std::string>(sigc::mem_fun(
228 *
this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock_async)));
230 "robmem-mutex-expire-locks-async",
231 sigc::slot<CLIPS::Value, float>(sigc::bind<0>(
232 sigc::mem_fun(*
this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks_async),
235 clips->build(
"(deffacts have-feature-mongodb (have-feature MongoDB))");
238 clips->batch_evaluate(SRCDIR
"/robot-memory.clp");
246 envs_.erase(env_name);
251 ClipsRobotMemoryThread::clips_bson_create()
253 return CLIPS::Value(
new bsoncxx::builder::basic::document());
257 ClipsRobotMemoryThread::clips_bson_parse(std::string document)
259 auto b =
new bsoncxx::builder::basic::document();
261 b->append(bsoncxx::builder::concatenate(bsoncxx::from_json(document)));
262 }
catch (bsoncxx::exception &e) {
263 logger->
log_error(
"MongoDB",
"Parsing JSON doc failed: %s\n%s", e.what(), document.c_str());
265 return CLIPS::Value(b);
269 ClipsRobotMemoryThread::clips_bson_destroy(
void *bson)
271 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
276 ClipsRobotMemoryThread::clips_bson_tostring(
void *bson)
278 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
279 return bsoncxx::to_json(b->view());
283 ClipsRobotMemoryThread::clips_bson_append(
void *bson, std::string field_name, CLIPS::Value value)
285 using namespace bsoncxx::builder;
287 auto b =
static_cast<basic::document *
>(bson);
288 switch (value.type()) {
289 case CLIPS::TYPE_FLOAT: b->append(basic::kvp(field_name, value.as_float()));
break;
291 case CLIPS::TYPE_INTEGER:
292 b->append(basic::kvp(field_name,
static_cast<int64_t
>(value.as_integer())));
295 case CLIPS::TYPE_SYMBOL:
296 case CLIPS::TYPE_INSTANCE_NAME:
297 case CLIPS::TYPE_STRING: b->append(basic::kvp(field_name, value.as_string()));
break;
298 case CLIPS::TYPE_EXTERNAL_ADDRESS: {
299 auto subb =
static_cast<basic::document *
>(value.as_address());
300 b->append(basic::kvp(field_name, subb->view()));
304 logger->
log_warn(
"RefBox",
"Tried to add unknown type to BSON field %s", field_name.c_str());
307 }
catch (bsoncxx::exception &e) {
309 "Failed to append array value to field %s: %s",
316 ClipsRobotMemoryThread::clips_bson_append_regex(
void * bson,
317 std::string field_name,
318 CLIPS::Value regex_string)
320 using namespace bsoncxx::builder;
321 if (regex_string.type() != CLIPS::TYPE_STRING) {
326 auto b =
static_cast<basic::document *
>(bson);
327 b->append(basic::kvp(field_name, bsoncxx::types::b_regex{regex_string.as_string()}));
328 }
catch (bsoncxx::exception &e) {
330 "Failed to append regex to field %s: %s",
337 ClipsRobotMemoryThread::clips_bson_append_array(
void * bson,
338 std::string field_name,
339 CLIPS::Values values)
341 using namespace bsoncxx::builder;
343 auto b =
static_cast<basic::document *
>(bson);
345 b->append(basic::kvp(field_name, [&](basic::sub_array array) {
346 for (
auto value : values) {
347 switch (value.type()) {
348 case CLIPS::TYPE_FLOAT: array.append(value.as_float()); break;
350 case CLIPS::TYPE_INTEGER: array.append(static_cast<int64_t>(value.as_integer())); break;
352 case CLIPS::TYPE_SYMBOL:
353 case CLIPS::TYPE_STRING:
354 case CLIPS::TYPE_INSTANCE_NAME: array.append(value.as_string()); break;
356 case CLIPS::TYPE_EXTERNAL_ADDRESS: {
357 auto subb = static_cast<bsoncxx::builder::basic::document *>(value.as_address());
358 array.append(subb->view());
363 "Tried to add unknown type to BSON array field %s",
369 }
catch (bsoncxx::exception &e) {
371 "Failed to append array value to field %s: %s",
378 ClipsRobotMemoryThread::clips_bson_array_start(
void *bson, std::string field_name)
392 ClipsRobotMemoryThread::clips_bson_array_finish(
void *barr)
402 ClipsRobotMemoryThread::clips_bson_array_append(
void *barr, CLIPS::Value value)
435 ClipsRobotMemoryThread::clips_bson_append_time(
void * bson,
436 std::string field_name,
439 if (time.size() != 2) {
440 logger->
log_warn(
"MongoDB",
"Invalid time, %zu instead of 2 entries", time.size());
443 if (time[0].type() != CLIPS::TYPE_INTEGER || time[1].type() != CLIPS::TYPE_INTEGER) {
449 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
450 struct timeval now = {time[0].as_integer(), time[1].as_integer()};
451 bsoncxx::types::b_date nowd{
452 std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>{
453 std::chrono::milliseconds{now.tv_sec * 1000 + now.tv_usec / 1000}}};
454 b->append(bsoncxx::builder::basic::kvp(field_name, nowd));
455 }
catch (bsoncxx::exception &e) {
457 "Failed to append time value to field %s: %s",
464 ClipsRobotMemoryThread::clips_robotmemory_insert(std::string collection,
void *bson)
466 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
470 }
catch (mongocxx::exception &e) {
476 ClipsRobotMemoryThread::clips_robotmemory_create_index(std::string collection,
void *bson)
478 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
482 }
catch (mongocxx::exception &e) {
483 logger->
log_warn(
"MongoDB",
"Creating index failed: %s", e.what());
488 ClipsRobotMemoryThread::clips_robotmemory_create_unique_index(std::string collection,
void *bson)
490 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
494 }
catch (mongocxx::exception &e) {
495 logger->
log_warn(
"MongoDB",
"Creating unique index failed: %s", e.what());
500 ClipsRobotMemoryThread::robotmemory_update(std::string & collection,
501 const bsoncxx::document::view &update,
502 CLIPS::Value & query,
506 if (query.type() == CLIPS::TYPE_STRING) {
507 robot_memory->
update(bsoncxx::from_json(query.as_string()), update, collection, upsert);
508 }
else if (query.type() == CLIPS::TYPE_EXTERNAL_ADDRESS) {
509 bsoncxx::builder::basic::document *qb =
510 static_cast<bsoncxx::builder::basic::document *
>(query.as_address());
513 logger->
log_warn(
"MongoDB",
"Invalid query, must be string or BSON document");
517 }
catch (bsoncxx::exception &e) {
518 logger->
log_warn(
"MongoDB",
"Compiling query failed: %s", e.what());
519 }
catch (mongocxx::exception &e) {
525 ClipsRobotMemoryThread::clips_robotmemory_upsert(std::string collection,
529 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
534 robotmemory_update(collection, b->view(), query,
true);
538 ClipsRobotMemoryThread::clips_robotmemory_update(std::string collection,
542 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
547 robotmemory_update(collection, b->view(), query,
false);
551 ClipsRobotMemoryThread::clips_robotmemory_replace(std::string collection,
555 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
558 robotmemory_update(collection, b->view(), query,
false);
562 ClipsRobotMemoryThread::clips_robotmemory_query_sort(std::string collection,
566 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
569 mongocxx::options::find find_opts{};
571 auto *bs =
static_cast<bsoncxx::builder::basic::document *
>(bson_sort);
572 find_opts.sort(bs->view());
577 return CLIPS::Value(
new std::unique_ptr<mongocxx::cursor>(
578 new mongocxx::cursor(std::move(cursor))),
579 CLIPS::TYPE_EXTERNAL_ADDRESS);
580 }
catch (std::system_error &e) {
582 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
587 ClipsRobotMemoryThread::clips_robotmemory_remove(std::string collection,
void *bson)
589 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
592 }
catch (std::system_error &e) {
598 ClipsRobotMemoryThread::clips_robotmemory_query(
const std::string &collection,
void *bson)
600 return clips_robotmemory_query_sort(collection, bson, NULL);
604 ClipsRobotMemoryThread::clips_robotmemory_cursor_destroy(
void *cursor)
606 auto c =
static_cast<std::unique_ptr<mongocxx::cursor> *
>(cursor);
607 if (!c || !c->get()) {
608 logger->
log_error(
"MongoDB",
"mongodb-cursor-destroy: got invalid cursor");
616 ClipsRobotMemoryThread::clips_robotmemory_cursor_more(
void *cursor)
618 throw Exception(
"The function cursor-more is no longer supported. Call cursor-next and check the "
619 "return value for FALSE instead.");
623 ClipsRobotMemoryThread::clips_robotmemory_cursor_next(
void *cursor)
625 auto c =
static_cast<std::unique_ptr<mongocxx::cursor> *
>(cursor);
627 if (!c || !c->get()) {
628 logger->
log_error(
"MongoDB",
"mongodb-cursor-next: got invalid cursor");
629 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
633 auto it = (*c)->begin();
634 if (it == (*c)->end()) {
635 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
637 auto b =
new bsoncxx::builder::basic::document();
638 b->append(bsoncxx::builder::concatenate(*it));
640 return CLIPS::Value(b);
642 }
catch (std::system_error &e) {
643 logger->
log_error(
"MongoDB",
"mongodb-cursor-next: got invalid query: %s", e.what());
644 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
649 ClipsRobotMemoryThread::clips_bson_field_names(
void *bson)
651 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
654 logger->
log_error(
"MongoDB",
"mongodb-bson-field-names: invalid object");
656 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
661 for (
auto element : b->view()) {
662 rv.push_back(CLIPS::Value(std::string(element.key())));
668 ClipsRobotMemoryThread::clips_bson_get(
void *bson, std::string field_name)
670 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
674 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
678 auto el = get_dotted_field(b->view(), field_name);
681 "mongodb-bson-get: failed to get '%s', no such element in doc: %s",
683 bsoncxx::to_json(b->view()).c_str());
684 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
687 case bsoncxx::type::k_double:
return CLIPS::Value(el.get_double());
688 case bsoncxx::type::k_utf8:
return CLIPS::Value(el.get_utf8().value.to_string());
689 case bsoncxx::type::k_bool:
690 return CLIPS::Value(el.get_bool() ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
691 case bsoncxx::type::k_int32:
return CLIPS::Value(el.get_int32());
692 case bsoncxx::type::k_int64:
return CLIPS::Value(el.get_int64());
693 case bsoncxx::type::k_document: {
694 auto b =
new bsoncxx::builder::basic::document();
695 b->append(bsoncxx::builder::concatenate(el.get_document().view()));
696 return CLIPS::Value(b);
698 case bsoncxx::type::k_oid:
699 return CLIPS::Value(el.get_oid().value.to_string());
701 default:
return CLIPS::Value(
"INVALID_VALUE_TYPE", CLIPS::TYPE_SYMBOL);
703 }
catch (std::system_error &e) {
705 "mongodb-bson-get: failed to get '%s': %s",
708 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
713 ClipsRobotMemoryThread::clips_bson_has_field(
void *bson, std::string field_name)
715 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
719 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
723 auto el = get_dotted_field(b->view(), field_name);
724 if (!el.key().empty()) {
725 return CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL);
727 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
729 }
catch (bsoncxx::exception &e) {
730 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
735 ClipsRobotMemoryThread::clips_bson_get_array(
void *bson, std::string field_name)
737 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
742 logger->
log_error(
"MongoDB",
"mongodb-bson-get-array: invalid object");
743 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
748 auto el = get_dotted_field(b->view(), field_name);
750 if (el.type() != bsoncxx::type::k_array) {
752 "mongodb-bson-get-array: field %s is not an array",
754 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
758 bsoncxx::array::view array_view{el.get_array()};
759 for (
const auto e : array_view) {
761 case bsoncxx::type::k_double: rv.push_back(CLIPS::Value(e.get_double()));
break;
762 case bsoncxx::type::k_utf8: rv.push_back(CLIPS::Value(e.get_utf8().value.to_string()));
break;
763 case bsoncxx::type::k_bool:
764 rv.push_back(CLIPS::Value(e.get_bool() ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL));
766 case bsoncxx::type::k_int32: rv.push_back(CLIPS::Value(e.get_int32()));
break;
767 case bsoncxx::type::k_int64: rv.push_back(CLIPS::Value(e.get_int64()));
break;
768 case bsoncxx::type::k_document: {
769 auto b =
new bsoncxx::builder::basic::document();
770 b->append(bsoncxx::builder::concatenate(e.get_document().view()));
771 rv.push_back(CLIPS::Value(b));
775 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
780 }
catch (bsoncxx::exception &e) {
782 "mongodb-bson-get: failed to get '%s': %s",
786 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
792 ClipsRobotMemoryThread::clips_bson_get_time(
void *bson, std::string field_name)
794 auto b =
static_cast<bsoncxx::builder::basic::document *
>(bson);
800 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
805 auto el = get_dotted_field(b->view(), field_name);
807 if (el.type() == bsoncxx::type::k_date) {
808 bsoncxx::types::b_date d = el.get_date();
810 }
else if (el.type() == bsoncxx::type::k_timestamp) {
811 bsoncxx::types::b_timestamp t = el.get_timestamp();
812 ts = (int64_t)t.timestamp * 1000;
815 "mongodb-bson-get-time: field %s is not a time",
817 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
822 rv[0] = CLIPS::Value((
long long int)(ts / 1000));
823 rv[1] = CLIPS::Value((ts - (rv[0].as_integer() * 1000)) * 1000);
825 }
catch (bsoncxx::exception &e) {
826 rv.resize(2, CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
832 ClipsRobotMemoryThread::clips_robotmemory_register_trigger(std::string env_name,
833 std::string collection,
835 std::string assert_name)
837 bsoncxx::document::value b{
static_cast<bsoncxx::builder::basic::document *
>(query)->view()};
838 std::string future_name =
"register_trigger_" + assert_name;
839 if (!mutex_future_ready(future_name)) {
840 MutexLocker clips_lock(envs_[env_name].objmutex_ptr());
841 envs_[env_name]->assert_fact_f(
"(mutex-trigger-register-feedback FAIL \"%s\")",
842 assert_name.c_str());
843 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
845 auto fut = std::async(std::launch::async, [
this, b, env_name, collection, assert_name] {
852 clips_triggers_.push_back(clips_trigger);
853 MutexLocker clips_lock(envs_[env_name].objmutex_ptr());
854 envs_[env_name]->assert_fact_f(
"(mutex-trigger-register-feedback SUCCESS \"%s\" %p)",
856 CLIPS::Value(clips_trigger).as_address());
858 }
catch (std::system_error &e) {
860 MutexLocker clips_lock(envs_[env_name].objmutex_ptr());
861 envs_[env_name]->assert_fact_f(
"(mutex-trigger-register-feedback FAIL \"%s\")",
862 assert_name.c_str());
867 mutex_futures_[future_name] = std::move(fut);
868 return CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL);
872 ClipsRobotMemoryThread::clips_robotmemory_destroy_trigger(
void *trigger)
876 clips_triggers_.remove(clips_trigger);
877 delete clips_trigger;
881 ClipsRobotMemoryThread::clips_robotmemory_mutex_create(std::string
name)
884 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
888 ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy(std::string
name)
891 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
895 ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock(std::string
name, std::string identity)
898 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
902 ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock(std::string
name, std::string identity)
905 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
909 ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock(std::string
name, std::string identity)
912 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
916 ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock(std::string
name, std::string identity)
919 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
923 ClipsRobotMemoryThread::clips_robotmemory_mutex_setup_ttl(
float max_age_sec)
926 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
930 ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks(
float max_age_sec)
933 return CLIPS::Value(rv ?
"TRUE" :
"FALSE", CLIPS::TYPE_SYMBOL);
937 ClipsRobotMemoryThread::mutex_future_ready(
const std::string &
name)
939 auto mf_it = mutex_futures_.find(
name);
940 if (mf_it != mutex_futures_.end()) {
941 auto fut_status = mutex_futures_[
name].wait_for(std::chrono::milliseconds(0));
942 if (fut_status != std::future_status::ready) {
945 mutex_futures_.erase(mf_it);
952 ClipsRobotMemoryThread::clips_robotmemory_mutex_create_async(std::string
name)
955 if (!mutex_future_ready(
name)) {
956 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
957 rv.push_back(CLIPS::Value(
"Task already running for " +
name +
" (create failed)"));
964 mutex_futures_[
name] = std::move(fut);
966 rv.push_back(CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL));
971 ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy_async(std::string
name)
974 if (!mutex_future_ready(
name)) {
975 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
976 rv.push_back(CLIPS::Value(
"Task already running for " +
name +
" (destroy failed)"));
983 mutex_futures_[
name] = std::move(fut);
985 rv.push_back(CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL));
990 ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock_async(std::string env_name,
992 std::string identity)
995 if (!mutex_future_ready(
name)) {
996 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
997 rv.push_back(CLIPS::Value(
"Task already running for " +
name +
" (try-lock failed)"));
998 envs_[env_name]->assert_fact_f(
"(mutex-op-feedback try-lock-async FAIL %s)",
name.c_str());
1002 auto fut = std::async(std::launch::async, [
this, env_name,
name, identity] {
1006 envs_[env_name]->assert_fact_f(
"(mutex-op-feedback try-lock-async FAIL %s)",
name.c_str());
1011 mutex_futures_[
name] = std::move(fut);
1013 rv.push_back(CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL));
1018 ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock_async(std::string env_name,
1020 std::string identity)
1023 if (!mutex_future_ready(
name)) {
1024 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
1025 rv.push_back(CLIPS::Value(
"Task already running for " +
name +
" (try-lock failed)"));
1027 envs_[env_name]->assert_fact_f(
"(mutex-op-feedback renew-lock-async FAIL %s)",
name.c_str());
1031 auto fut = std::async(std::launch::async, [
this, env_name,
name, identity] {
1034 envs_[env_name]->assert_fact_f(
"(mutex-op-feedback renew-lock-async %s %s)",
1040 mutex_futures_[
name] = std::move(fut);
1042 rv.push_back(CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL));
1047 ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock_async(std::string
name,
1048 std::string identity)
1051 if (!mutex_future_ready(
name)) {
1052 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
1053 rv.push_back(CLIPS::Value(
"Task already running for " +
name +
" (force-lock failed)"));
1057 auto fut = std::async(std::launch::async, [
this,
name, identity] {
1061 mutex_futures_[
name] = std::move(fut);
1063 rv.push_back(CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL));
1068 ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock_async(std::string
name, std::string identity)
1071 if (!mutex_future_ready(
name)) {
1072 rv.push_back(CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL));
1073 rv.push_back(CLIPS::Value(
"Task already running for " +
name +
" (unlock failed)"));
1077 auto fut = std::async(std::launch::async, [
this,
name, identity] {
1081 mutex_futures_[
name] = std::move(fut);
1083 rv.push_back(CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL));
1088 ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks_async(std::string env_name,
1092 if (mutex_expire_future_.valid()) {
1094 auto fut_status = mutex_expire_future_.wait_for(std::chrono::milliseconds(0));
1095 if (fut_status != std::future_status::ready) {
1097 envs_[env_name]->assert_fact_f(
"(mutex-op-feedback expire-locks-async FAIL)");
1098 return CLIPS::Value(
"FALSE", CLIPS::TYPE_SYMBOL);
1102 auto fut = std::async(std::launch::async, [
this, env_name, max_age_sec] {
1105 envs_[env_name]->assert_fact_f(
"(mutex-op-feedback expire-locks-async %s)", ok ?
"OK" :
"FAIL");
1109 mutex_expire_future_ = std::move(fut);
1111 return CLIPS::Value(
"TRUE", CLIPS::TYPE_SYMBOL);