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 
33 using 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 
42 ClipsRobotMemoryThread::ClipsRobotMemoryThread()
43 : Thread("ClipsRobotMemoryThread", Thread::OPMODE_WAITFORWAKEUP),
44  CLIPSFeature("robot_memory"),
45  CLIPSFeatureAspect(this)
46 {
47 }
48 
49 void
51 {
52 }
53 
54 void
56 {
57 }
58 
59 void
61 {
62  envs_.clear();
63  for (ClipsRmTrigger *trigger : clips_triggers_) {
64  delete trigger;
65  }
66 }
67 
68 void
69 ClipsRobotMemoryThread::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, 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)));
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-cursor-destroy",
134  sigc::slot<void, void *>(
135  sigc::mem_fun(*this,
136  &ClipsRobotMemoryThread::clips_robotmemory_cursor_destroy)));
137  clips->add_function("robmem-cursor-more",
138  sigc::slot<CLIPS::Value, void *>(
139  sigc::mem_fun(*this,
140  &ClipsRobotMemoryThread::clips_robotmemory_cursor_more)));
141  clips->add_function("robmem-cursor-next",
142  sigc::slot<CLIPS::Value, void *>(
143  sigc::mem_fun(*this,
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>(
147  sigc::mem_fun(*this,
148  &ClipsRobotMemoryThread::clips_robotmemory_register_trigger),
149  env_name)));
150  clips->add_function("robmem-trigger-destroy",
151  sigc::slot<void, void *>(
152  sigc::mem_fun(*this,
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 *>(
171  sigc::mem_fun(*this,
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)));
176 
177  clips->add_function("robmem-mutex-create",
178  sigc::slot<CLIPS::Value, std::string>(
179  sigc::mem_fun(*this,
180  &ClipsRobotMemoryThread::clips_robotmemory_mutex_create)));
181  clips->add_function("robmem-mutex-destroy",
182  sigc::slot<CLIPS::Value, std::string>(
183  sigc::mem_fun(*this,
184  &ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy)));
185  clips->add_function("robmem-mutex-try-lock",
186  sigc::slot<CLIPS::Value, std::string, std::string>(
187  sigc::mem_fun(*this,
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>(
197  sigc::mem_fun(*this,
198  &ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock)));
199  clips->add_function("robmem-mutex-setup-ttl",
200  sigc::slot<CLIPS::Value, float>(
201  sigc::mem_fun(*this,
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)));
206 
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)));
213  clips->add_function(
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),
217  env_name)));
218  clips->add_function(
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),
222  env_name)));
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)));
229  clips->add_function(
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),
233  env_name)));
234 
235  clips->build("(deffacts have-feature-mongodb (have-feature MongoDB))");
236 
237  //load helper functions written in CLIPS
238  clips->batch_evaluate(SRCDIR "/robot-memory.clp");
239 
240  clips.unlock();
241 }
242 
243 void
245 {
246  envs_.erase(env_name);
247  logger->log_debug(name(), "Removing environment %s", env_name.c_str());
248 }
249 
250 CLIPS::Value
251 ClipsRobotMemoryThread::clips_bson_create()
252 {
253  return CLIPS::Value(new bsoncxx::builder::basic::document());
254 }
255 
256 CLIPS::Value
257 ClipsRobotMemoryThread::clips_bson_parse(std::string document)
258 {
259  auto b = new bsoncxx::builder::basic::document();
260  try {
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());
264  }
265  return CLIPS::Value(b);
266 }
267 
268 void
269 ClipsRobotMemoryThread::clips_bson_destroy(void *bson)
270 {
271  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
272  delete b;
273 }
274 
275 std::string
276 ClipsRobotMemoryThread::clips_bson_tostring(void *bson)
277 {
278  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
279  return bsoncxx::to_json(b->view());
280 }
281 
282 void
283 ClipsRobotMemoryThread::clips_bson_append(void *bson, std::string field_name, CLIPS::Value value)
284 {
285  using namespace bsoncxx::builder;
286  try {
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;
290 
291  case CLIPS::TYPE_INTEGER:
292  b->append(basic::kvp(field_name, static_cast<int64_t>(value.as_integer())));
293  break;
294 
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()));
301  } break;
302 
303  default:
304  logger->log_warn("RefBox", "Tried to add unknown type to BSON field %s", field_name.c_str());
305  break;
306  }
307  } catch (bsoncxx::exception &e) {
308  logger->log_error("MongoDB",
309  "Failed to append array value to field %s: %s",
310  field_name.c_str(),
311  e.what());
312  }
313 }
314 
315 void
316 ClipsRobotMemoryThread::clips_bson_append_regex(void * bson,
317  std::string field_name,
318  CLIPS::Value regex_string)
319 {
320  using namespace bsoncxx::builder;
321  if (regex_string.type() != CLIPS::TYPE_STRING) {
322  logger->log_error("MongoDB", "Regex string has to be of type string");
323  return;
324  }
325  try {
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) {
329  logger->log_error("MongoDB",
330  "Failed to append regex to field %s: %s",
331  field_name.c_str(),
332  e.what());
333  }
334 }
335 
336 void
337 ClipsRobotMemoryThread::clips_bson_append_array(void * bson,
338  std::string field_name,
339  CLIPS::Values values)
340 {
341  using namespace bsoncxx::builder;
342  try {
343  auto b = static_cast<basic::document *>(bson);
344 
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;
349 
350  case CLIPS::TYPE_INTEGER: array.append(static_cast<int64_t>(value.as_integer())); break;
351 
352  case CLIPS::TYPE_SYMBOL:
353  case CLIPS::TYPE_STRING:
354  case CLIPS::TYPE_INSTANCE_NAME: array.append(value.as_string()); break;
355 
356  case CLIPS::TYPE_EXTERNAL_ADDRESS: {
357  auto subb = static_cast<bsoncxx::builder::basic::document *>(value.as_address());
358  array.append(subb->view());
359  } break;
360 
361  default:
362  logger->log_warn("MongoDB",
363  "Tried to add unknown type to BSON array field %s",
364  field_name.c_str());
365  break;
366  }
367  }
368  }));
369  } catch (bsoncxx::exception &e) {
370  logger->log_error("MongoDB",
371  "Failed to append array value to field %s: %s",
372  field_name.c_str(),
373  e.what());
374  }
375 }
376 
377 CLIPS::Value
378 ClipsRobotMemoryThread::clips_bson_array_start(void *bson, std::string field_name)
379 {
380  // With the new libmongocxx, we can no longer create an open array as
381  // sub-field of another document.
382  throw Exception("Not implemented");
383  /*
384  mongo::BSONObjBuilder * b = static_cast<mongo::BSONObjBuilder *>(bson);
385  mongo::BufBuilder & bb = b->subarrayStart(field_name);
386  mongo::BSONArrayBuilder *arrb = new mongo::BSONArrayBuilder(bb);
387  return CLIPS::Value(arrb);
388  */
389 }
390 
391 void
392 ClipsRobotMemoryThread::clips_bson_array_finish(void *barr)
393 {
394  throw Exception("Not implemented");
395  /*
396  mongo::BSONArrayBuilder *ab = static_cast<mongo::BSONArrayBuilder *>(barr);
397  delete ab;
398  */
399 }
400 
401 void
402 ClipsRobotMemoryThread::clips_bson_array_append(void *barr, CLIPS::Value value)
403 {
404  throw Exception("Not implemented");
405  /*
406  try {
407  auto *ab = static_cast<mongo::BSONArrayBuilder *>(barr);
408  switch (value.type()) {
409  case CLIPS::TYPE_FLOAT: ab->append(value.as_float()); break;
410 
411  case CLIPS::TYPE_INTEGER: ab->append(value.as_integer()); break;
412 
413  case CLIPS::TYPE_SYMBOL:
414  case CLIPS::TYPE_STRING:
415  case CLIPS::TYPE_INSTANCE_NAME: ab->append(value.as_string()); break;
416 
417  case CLIPS::TYPE_EXTERNAL_ADDRESS: {
418  mongo::BSONObjBuilder *subb = static_cast<mongo::BSONObjBuilder *>(value.as_address());
419  ab->append(subb->asTempObj());
420  } break;
421 
422  default: logger->log_warn("RefBox", "Tried to add unknown type to BSON array"); break;
423  }
424 #ifdef HAVE_MONGODB_VERSION_H
425  } catch (mongo::MsgAssertionException &e) {
426 #else
427  } catch (mongo::AssertionException &e) {
428 #endif
429  logger->log_error("MongoDB", "Failed to append to array: %s", e.what());
430  }
431  */
432 }
433 
434 void
435 ClipsRobotMemoryThread::clips_bson_append_time(void * bson,
436  std::string field_name,
437  CLIPS::Values time)
438 {
439  if (time.size() != 2) {
440  logger->log_warn("MongoDB", "Invalid time, %zu instead of 2 entries", time.size());
441  return;
442  }
443  if (time[0].type() != CLIPS::TYPE_INTEGER || time[1].type() != CLIPS::TYPE_INTEGER) {
444  logger->log_warn("MongoDB", "Invalid time, type mismatch");
445  return;
446  }
447 
448  try {
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) {
456  logger->log_error("MongoDB",
457  "Failed to append time value to field %s: %s",
458  field_name.c_str(),
459  e.what());
460  }
461 }
462 
463 void
464 ClipsRobotMemoryThread::clips_robotmemory_insert(std::string collection, void *bson)
465 {
466  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
467 
468  try {
469  robot_memory->insert(b->view(), collection);
470  } catch (mongocxx::exception &e) {
471  logger->log_warn("MongoDB", "Insert failed: %s", e.what());
472  }
473 }
474 
475 void
476 ClipsRobotMemoryThread::clips_robotmemory_create_index(std::string collection, void *bson)
477 {
478  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
479 
480  try {
481  robot_memory->create_index(b->view(), collection, /* unique */ false);
482  } catch (mongocxx::exception &e) {
483  logger->log_warn("MongoDB", "Creating index failed: %s", e.what());
484  }
485 }
486 
487 void
488 ClipsRobotMemoryThread::clips_robotmemory_create_unique_index(std::string collection, void *bson)
489 {
490  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
491 
492  try {
493  robot_memory->create_index(b->view(), collection, /* unique */ true);
494  } catch (mongocxx::exception &e) {
495  logger->log_warn("MongoDB", "Creating unique index failed: %s", e.what());
496  }
497 }
498 
499 void
500 ClipsRobotMemoryThread::robotmemory_update(std::string & collection,
501  const bsoncxx::document::view &update,
502  CLIPS::Value & query,
503  bool upsert)
504 {
505  try {
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());
511  robot_memory->update(qb->view(), update, collection, upsert);
512  } else {
513  logger->log_warn("MongoDB", "Invalid query, must be string or BSON document");
514  return;
515  }
516 
517  } catch (bsoncxx::exception &e) {
518  logger->log_warn("MongoDB", "Compiling query failed: %s", e.what());
519  } catch (mongocxx::exception &e) {
520  logger->log_warn("MongoDB", "Insert failed: %s", e.what());
521  }
522 }
523 
524 void
525 ClipsRobotMemoryThread::clips_robotmemory_upsert(std::string collection,
526  void * bson,
527  CLIPS::Value query)
528 {
529  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
530  if (!b) {
531  logger->log_warn("MongoDB", "Invalid BSON Builder passed");
532  return;
533  }
534  robotmemory_update(collection, b->view(), query, true);
535 }
536 
537 void
538 ClipsRobotMemoryThread::clips_robotmemory_update(std::string collection,
539  void * bson,
540  CLIPS::Value query)
541 {
542  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
543  if (!b) {
544  logger->log_warn("MongoDB", "Invalid BSON Builder passed");
545  return;
546  }
547  robotmemory_update(collection, b->view(), query, false);
548 }
549 
550 void
551 ClipsRobotMemoryThread::clips_robotmemory_replace(std::string collection,
552  void * bson,
553  CLIPS::Value query)
554 {
555  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
556  if (!b)
557  logger->log_warn("MongoDB", "Invalid BSON Builder passed");
558  robotmemory_update(collection, b->view(), query, false);
559 }
560 
561 CLIPS::Value
562 ClipsRobotMemoryThread::clips_robotmemory_query_sort(std::string collection,
563  void * bson,
564  void * bson_sort)
565 {
566  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
567 
568  try {
569  mongocxx::options::find find_opts{};
570  if (bson_sort) {
571  auto *bs = static_cast<bsoncxx::builder::basic::document *>(bson_sort);
572  find_opts.sort(bs->view());
573  }
574 
575  auto cursor = robot_memory->query(b->view(), collection, find_opts);
576  //std::unique_ptr<mongocxx::cursor> c = new mongocxx::cursor(std::move(cursor));
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) {
581  logger->log_warn("MongoDB", "Query failed: %s", e.what());
582  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
583  }
584 }
585 
586 void
587 ClipsRobotMemoryThread::clips_robotmemory_remove(std::string collection, void *bson)
588 {
589  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
590  try {
591  robot_memory->remove(b->view(), collection);
592  } catch (std::system_error &e) {
593  logger->log_warn("MongoDB", "Remove failed: %s", e.what());
594  }
595 }
596 
597 CLIPS::Value
598 ClipsRobotMemoryThread::clips_robotmemory_query(const std::string &collection, void *bson)
599 {
600  return clips_robotmemory_query_sort(collection, bson, NULL);
601 }
602 
603 void
604 ClipsRobotMemoryThread::clips_robotmemory_cursor_destroy(void *cursor)
605 {
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");
609  return;
610  }
611 
612  delete c;
613 }
614 
615 CLIPS::Value
616 ClipsRobotMemoryThread::clips_robotmemory_cursor_more(void *cursor)
617 {
618  throw Exception("The function cursor-more is no longer supported. Call cursor-next and check the "
619  "return value for FALSE instead.");
620 }
621 
622 CLIPS::Value
623 ClipsRobotMemoryThread::clips_robotmemory_cursor_next(void *cursor)
624 {
625  auto c = static_cast<std::unique_ptr<mongocxx::cursor> *>(cursor);
626 
627  if (!c || !c->get()) {
628  logger->log_error("MongoDB", "mongodb-cursor-next: got invalid cursor");
629  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
630  }
631 
632  try {
633  auto it = (*c)->begin();
634  if (it == (*c)->end()) {
635  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
636  } else {
637  auto b = new bsoncxx::builder::basic::document();
638  b->append(bsoncxx::builder::concatenate(*it));
639  it++;
640  return CLIPS::Value(b);
641  }
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);
645  }
646 }
647 
648 CLIPS::Values
649 ClipsRobotMemoryThread::clips_bson_field_names(void *bson)
650 {
651  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
652 
653  if (!b) {
654  logger->log_error("MongoDB", "mongodb-bson-field-names: invalid object");
655  CLIPS::Values rv;
656  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
657  return rv;
658  }
659 
660  CLIPS::Values rv;
661  for (auto element : b->view()) {
662  rv.push_back(CLIPS::Value(std::string(element.key())));
663  }
664  return rv;
665 }
666 
667 CLIPS::Value
668 ClipsRobotMemoryThread::clips_bson_get(void *bson, std::string field_name)
669 {
670  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
671 
672  if (!b) {
673  logger->log_error("MongoDB", "mongodb-bson-get: invalid object");
674  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
675  }
676 
677  try {
678  auto el = get_dotted_field(b->view(), field_name);
679  if (!el) {
680  logger->log_warn(name(),
681  "mongodb-bson-get: failed to get '%s', no such element in doc: %s",
682  field_name.c_str(),
683  bsoncxx::to_json(b->view()).c_str());
684  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
685  }
686  switch (el.type()) {
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);
697  }
698  case bsoncxx::type::k_oid: //ObjectId
699  return CLIPS::Value(el.get_oid().value.to_string());
700 
701  default: return CLIPS::Value("INVALID_VALUE_TYPE", CLIPS::TYPE_SYMBOL);
702  }
703  } catch (std::system_error &e) {
704  logger->log_warn(name(),
705  "mongodb-bson-get: failed to get '%s': %s",
706  field_name.c_str(),
707  e.what());
708  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
709  }
710 }
711 
712 CLIPS::Value
713 ClipsRobotMemoryThread::clips_bson_has_field(void *bson, std::string field_name)
714 {
715  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
716 
717  if (!b) {
718  logger->log_error("MongoDB", "mongodb-bson-get: invalid object");
719  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
720  }
721 
722  try {
723  auto el = get_dotted_field(b->view(), field_name);
724  if (!el.key().empty()) {
725  return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
726  } else {
727  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
728  }
729  } catch (bsoncxx::exception &e) {
730  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
731  }
732 }
733 
734 CLIPS::Values
735 ClipsRobotMemoryThread::clips_bson_get_array(void *bson, std::string field_name)
736 {
737  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
738 
739  CLIPS::Values rv;
740 
741  if (!b) {
742  logger->log_error("MongoDB", "mongodb-bson-get-array: invalid object");
743  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
744  return rv;
745  }
746 
747  try {
748  auto el = get_dotted_field(b->view(), field_name);
749 
750  if (el.type() != bsoncxx::type::k_array) {
751  logger->log_error("MongoDB",
752  "mongodb-bson-get-array: field %s is not an array",
753  field_name.c_str());
754  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
755  return rv;
756  }
757 
758  bsoncxx::array::view array_view{el.get_array()};
759  for (const auto e : array_view) {
760  switch (e.type()) {
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));
765  break;
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));
772  } break;
773  default:
774  rv.clear();
775  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
776  return rv;
777  }
778  }
779  return rv;
780  } catch (bsoncxx::exception &e) {
781  logger->log_warn(name(),
782  "mongodb-bson-get: failed to get '%s': %s",
783  field_name.c_str(),
784  e.what());
785  rv.clear();
786  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
787  return rv;
788  }
789 }
790 
791 CLIPS::Values
792 ClipsRobotMemoryThread::clips_bson_get_time(void *bson, std::string field_name)
793 {
794  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
795 
796  CLIPS::Values rv;
797 
798  if (!b) {
799  logger->log_error("MongoDB", "mongodb-bson-get-time: invalid object");
800  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
801  return rv;
802  }
803 
804  try {
805  auto el = get_dotted_field(b->view(), field_name);
806  int64_t ts = 0;
807  if (el.type() == bsoncxx::type::k_date) {
808  bsoncxx::types::b_date d = el.get_date();
809  ts = d.to_int64();
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;
813  } else {
814  logger->log_error("MongoDB",
815  "mongodb-bson-get-time: field %s is not a time",
816  field_name.c_str());
817  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
818  return rv;
819  }
820 
821  rv.resize(2);
822  rv[0] = CLIPS::Value((long long int)(ts / 1000));
823  rv[1] = CLIPS::Value((ts - (rv[0].as_integer() * 1000)) * 1000);
824  return rv;
825  } catch (bsoncxx::exception &e) {
826  rv.resize(2, CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
827  return rv;
828  }
829 }
830 
831 CLIPS::Value
832 ClipsRobotMemoryThread::clips_robotmemory_register_trigger(std::string env_name,
833  std::string collection,
834  void * query,
835  std::string assert_name)
836 {
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);
844  }
845  auto fut = std::async(std::launch::async, [this, b, env_name, collection, assert_name] {
846  try {
847  ClipsRmTrigger *clips_trigger =
848  new ClipsRmTrigger(assert_name, robot_memory, envs_[env_name], logger);
849  clips_trigger->set_trigger(robot_memory->register_trigger(
850  b.view(), collection, &ClipsRmTrigger::callback, clips_trigger));
851  MutexLocker triggers_lock(&clips_triggers_mutex_);
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)",
855  assert_name.c_str(),
856  CLIPS::Value(clips_trigger).as_address());
857  return true;
858  } catch (std::system_error &e) {
859  logger->log_warn(name(), "Error while registering trigger: %s", e.what());
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());
863  return false;
864  }
865  });
866 
867  mutex_futures_[future_name] = std::move(fut);
868  return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
869 }
870 
871 void
872 ClipsRobotMemoryThread::clips_robotmemory_destroy_trigger(void *trigger)
873 {
874  ClipsRmTrigger *clips_trigger = static_cast<ClipsRmTrigger *>(trigger);
875  MutexLocker triggers_lock(&clips_triggers_mutex_);
876  clips_triggers_.remove(clips_trigger);
877  delete clips_trigger; //the triger unregisteres itself at the robot memory
878 }
879 
880 CLIPS::Value
881 ClipsRobotMemoryThread::clips_robotmemory_mutex_create(std::string name)
882 {
883  bool rv = robot_memory->mutex_create(name);
884  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
885 }
886 
887 CLIPS::Value
888 ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy(std::string name)
889 {
890  bool rv = robot_memory->mutex_destroy(name);
891  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
892 }
893 
894 CLIPS::Value
895 ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock(std::string name, std::string identity)
896 {
897  bool rv = robot_memory->mutex_try_lock(name, identity);
898  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
899 }
900 
901 CLIPS::Value
902 ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock(std::string name, std::string identity)
903 {
904  bool rv = robot_memory->mutex_renew_lock(name, identity);
905  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
906 }
907 
908 CLIPS::Value
909 ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock(std::string name, std::string identity)
910 {
911  bool rv = robot_memory->mutex_try_lock(name, identity, /* force */ true);
912  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
913 }
914 
915 CLIPS::Value
916 ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock(std::string name, std::string identity)
917 {
918  bool rv = robot_memory->mutex_unlock(name, identity);
919  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
920 }
921 
922 CLIPS::Value
923 ClipsRobotMemoryThread::clips_robotmemory_mutex_setup_ttl(float max_age_sec)
924 {
925  bool rv = robot_memory->mutex_setup_ttl(max_age_sec);
926  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
927 }
928 
929 CLIPS::Value
930 ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks(float max_age_sec)
931 {
932  bool rv = robot_memory->mutex_expire_locks(max_age_sec);
933  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
934 }
935 
936 bool
937 ClipsRobotMemoryThread::mutex_future_ready(const std::string &name)
938 {
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) {
943  return false;
944  } else {
945  mutex_futures_.erase(mf_it);
946  }
947  }
948  return true;
949 }
950 
951 CLIPS::Values
952 ClipsRobotMemoryThread::clips_robotmemory_mutex_create_async(std::string name)
953 {
954  CLIPS::Values rv;
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)"));
958  return rv;
959  }
960 
961  auto fut =
962  std::async(std::launch::async, [this, name] { return robot_memory->mutex_create(name); });
963 
964  mutex_futures_[name] = std::move(fut);
965 
966  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
967  return rv;
968 }
969 
970 CLIPS::Values
971 ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy_async(std::string name)
972 {
973  CLIPS::Values rv;
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)"));
977  return rv;
978  }
979 
980  auto fut =
981  std::async(std::launch::async, [this, name] { return robot_memory->mutex_destroy(name); });
982 
983  mutex_futures_[name] = std::move(fut);
984 
985  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
986  return rv;
987 }
988 
989 CLIPS::Values
990 ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock_async(std::string env_name,
991  std::string name,
992  std::string identity)
993 {
994  CLIPS::Values rv;
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());
999  return rv;
1000  }
1001 
1002  auto fut = std::async(std::launch::async, [this, env_name, name, identity] {
1003  bool ok = robot_memory->mutex_try_lock(name, identity);
1004  if (!ok) {
1005  MutexLocker lock(envs_[env_name].objmutex_ptr());
1006  envs_[env_name]->assert_fact_f("(mutex-op-feedback try-lock-async FAIL %s)", name.c_str());
1007  }
1008  return ok;
1009  });
1010 
1011  mutex_futures_[name] = std::move(fut);
1012 
1013  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1014  return rv;
1015 }
1016 
1017 CLIPS::Values
1018 ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock_async(std::string env_name,
1019  std::string name,
1020  std::string identity)
1021 {
1022  CLIPS::Values rv;
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)"));
1026  MutexLocker lock(envs_[env_name].objmutex_ptr());
1027  envs_[env_name]->assert_fact_f("(mutex-op-feedback renew-lock-async FAIL %s)", name.c_str());
1028  return rv;
1029  }
1030 
1031  auto fut = std::async(std::launch::async, [this, env_name, name, identity] {
1032  bool ok = robot_memory->mutex_renew_lock(name, identity);
1033  MutexLocker lock(envs_[env_name].objmutex_ptr());
1034  envs_[env_name]->assert_fact_f("(mutex-op-feedback renew-lock-async %s %s)",
1035  ok ? "OK" : "FAIL",
1036  name.c_str());
1037  return ok;
1038  });
1039 
1040  mutex_futures_[name] = std::move(fut);
1041 
1042  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1043  return rv;
1044 }
1045 
1046 CLIPS::Values
1047 ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock_async(std::string name,
1048  std::string identity)
1049 {
1050  CLIPS::Values rv;
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)"));
1054  return rv;
1055  }
1056 
1057  auto fut = std::async(std::launch::async, [this, name, identity] {
1058  return robot_memory->mutex_try_lock(name, identity, /* force */ true);
1059  });
1060 
1061  mutex_futures_[name] = std::move(fut);
1062 
1063  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1064  return rv;
1065 }
1066 
1067 CLIPS::Values
1068 ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock_async(std::string name, std::string identity)
1069 {
1070  CLIPS::Values rv;
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)"));
1074  return rv;
1075  }
1076 
1077  auto fut = std::async(std::launch::async, [this, name, identity] {
1078  return robot_memory->mutex_unlock(name, identity);
1079  });
1080 
1081  mutex_futures_[name] = std::move(fut);
1082 
1083  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1084  return rv;
1085 }
1086 
1087 CLIPS::Value
1088 ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks_async(std::string env_name,
1089  float max_age_sec)
1090 {
1091  CLIPS::Values rv;
1092  if (mutex_expire_future_.valid()) {
1093  // have shared state, expire was or is running
1094  auto fut_status = mutex_expire_future_.wait_for(std::chrono::milliseconds(0));
1095  if (fut_status != std::future_status::ready) {
1096  MutexLocker lock(envs_[env_name].objmutex_ptr());
1097  envs_[env_name]->assert_fact_f("(mutex-op-feedback expire-locks-async FAIL)");
1098  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
1099  }
1100  }
1101 
1102  auto fut = std::async(std::launch::async, [this, env_name, max_age_sec] {
1103  bool ok = robot_memory->mutex_expire_locks(max_age_sec);
1104  MutexLocker lock(envs_[env_name].objmutex_ptr());
1105  envs_[env_name]->assert_fact_f("(mutex-op-feedback expire-locks-async %s)", ok ? "OK" : "FAIL");
1106  return ok;
1107  });
1108 
1109  mutex_expire_future_ = std::move(fut);
1110 
1111  return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
1112 }
RobotMemory::register_trigger
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:120
RobotMemory::create_index
int create_index(bsoncxx::document::view keys, const std::string &collection="", bool unique=false)
Create an index on a collection.
Definition: robot_memory.cpp:301
RobotMemory::mutex_expire_locks
bool mutex_expire_locks(float max_age_sec)
Expire old locks on mutexes.
Definition: robot_memory.cpp:1104
RobotMemory::insert
int insert(bsoncxx::document::view, const std::string &collection="")
Inserts a document into the robot memory.
Definition: robot_memory.cpp:276
ClipsRmTrigger::callback
void callback(const bsoncxx::document::view &update)
Callback function for the trigger.
Definition: clips_rm_trigger.cpp:73
fawkes::LockPtr< CLIPS::Environment >
ClipsRobotMemoryThread::finalize
virtual void finalize()
Finalize the thread.
Definition: clips_robot_memory_thread.cpp:60
ClipsRobotMemoryThread::loop
virtual void loop()
Code to execute in the thread.
Definition: clips_robot_memory_thread.cpp:55
ClipsRobotMemoryThread::clips_context_init
virtual void clips_context_init(const std::string &env_name, fawkes::LockPtr< CLIPS::Environment > &clips)
Definition: clips_robot_memory_thread.cpp:69
fawkes::MutexLocker
Definition: mutex_locker.h:39
fawkes::Thread::name
const char * name() const
Definition: thread.h:100
RobotMemory::mutex_renew_lock
bool mutex_renew_lock(const std::string &name, const std::string &identity)
Renew a mutex.
Definition: robot_memory.cpp:1018
ClipsRmTrigger::set_trigger
void set_trigger(EventTrigger *trigger)
Set the trigger object given by the robot memory.
Definition: clips_rm_trigger.cpp:62
RobotMemory::mutex_create
bool mutex_create(const std::string &name)
Explicitly create a mutex.
Definition: robot_memory.cpp:798
fawkes::LoggingAspect::logger
Logger * logger
Definition: logging.h:53
fawkes::LockPtr::unlock
void unlock() const
Unlock object mutex.
Definition: lockptr.h:289
fawkes::Logger::log_error
virtual void log_error(const char *component, const char *format,...)=0
ClipsRobotMemoryThread::init
virtual void init()
Initialize the thread.
Definition: clips_robot_memory_thread.cpp:50
fawkes
fawkes::RobotMemoryAspect::robot_memory
RobotMemory * robot_memory
RobotMemory object for storing and querying information.
Definition: robot_memory_aspect.h:58
RobotMemory::mutex_try_lock
bool mutex_try_lock(const std::string &name, bool force=false)
Try to acquire a lock for a mutex.
Definition: robot_memory.cpp:951
ClipsRobotMemoryThread::clips_context_destroyed
virtual void clips_context_destroyed(const std::string &env_name)
Definition: clips_robot_memory_thread.cpp:244
RobotMemory::remove
int remove(const bsoncxx::document::view &query, const std::string &collection="")
Remove documents from the robot memory.
Definition: robot_memory.cpp:478
fawkes::Logger::log_warn
virtual void log_warn(const char *component, const char *format,...)=0
fawkes::CLIPSFeature
Definition: clips_feature.h:41
RobotMemory::mutex_setup_ttl
bool mutex_setup_ttl(float max_age_sec)
Setup time-to-live index for mutexes.
Definition: robot_memory.cpp:1077
RobotMemory::mutex_destroy
bool mutex_destroy(const std::string &name)
Destroy a mutex.
Definition: robot_memory.cpp:828
fawkes::Thread
Definition: thread.h:45
RobotMemory::query
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.
Definition: robot_memory.cpp:202
ClipsRmTrigger
Definition: clips_rm_trigger.h:37
fawkes::LockPtr::lock
void lock() const
Lock access to the encapsulated object.
Definition: lockptr.h:273
RobotMemory::update
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.
Definition: robot_memory.cpp:380
fawkes::CLIPSFeatureAspect
Definition: clips_feature.h:57
fawkes::Logger::log_debug
virtual void log_debug(const char *component, const char *format,...)=0
RobotMemory::mutex_unlock
bool mutex_unlock(const std::string &name, const std::string &identity)
Release lock on mutex.
Definition: robot_memory.cpp:962
fawkes::Exception
Definition: exception.h:41