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);