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-dump-collection",
134  sigc::slot<CLIPS::Value, std::string, std::string>(
135  sigc::mem_fun(*this,
136  &ClipsRobotMemoryThread::clips_robotmemory_dump_collection)));
137  clips->add_function("robmem-restore-collection",
138  sigc::slot<CLIPS::Value, std::string, std::string, std::string>(sigc::mem_fun(
139  *this, &ClipsRobotMemoryThread::clips_robotmemory_restore_collection)));
140  clips->add_function("robmem-cursor-destroy",
141  sigc::slot<void, void *>(
142  sigc::mem_fun(*this,
143  &ClipsRobotMemoryThread::clips_robotmemory_cursor_destroy)));
144  clips->add_function("robmem-cursor-more",
145  sigc::slot<CLIPS::Value, void *>(
146  sigc::mem_fun(*this,
147  &ClipsRobotMemoryThread::clips_robotmemory_cursor_more)));
148  clips->add_function("robmem-cursor-next",
149  sigc::slot<CLIPS::Value, void *>(
150  sigc::mem_fun(*this,
151  &ClipsRobotMemoryThread::clips_robotmemory_cursor_next)));
152  clips->add_function("robmem-trigger-register",
153  sigc::slot<CLIPS::Value, std::string, void *, std::string>(sigc::bind<0>(
154  sigc::mem_fun(*this,
155  &ClipsRobotMemoryThread::clips_robotmemory_register_trigger),
156  env_name)));
157  clips->add_function("robmem-trigger-destroy",
158  sigc::slot<void, void *>(
159  sigc::mem_fun(*this,
160  &ClipsRobotMemoryThread::clips_robotmemory_destroy_trigger)));
161  clips->add_function("bson-field-names",
162  sigc::slot<CLIPS::Values, void *>(
163  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_field_names)));
164  clips->add_function("bson-has-field",
165  sigc::slot<CLIPS::Value, void *, std::string>(
166  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_has_field)));
167  clips->add_function("bson-get",
168  sigc::slot<CLIPS::Value, void *, std::string>(
169  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_get)));
170  clips->add_function("bson-get-array",
171  sigc::slot<CLIPS::Values, void *, std::string>(
172  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_get_array)));
173  clips->add_function("bson-get-time",
174  sigc::slot<CLIPS::Values, void *, std::string>(
175  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_get_time)));
176  clips->add_function("robmem-create-index",
177  sigc::slot<void, std::string, void *>(
178  sigc::mem_fun(*this,
179  &ClipsRobotMemoryThread::clips_robotmemory_create_index)));
180  clips->add_function("robmem-create-unique-index",
181  sigc::slot<void, std::string, void *>(sigc::mem_fun(
182  *this, &ClipsRobotMemoryThread::clips_robotmemory_create_unique_index)));
183 
184  clips->add_function("robmem-mutex-create",
185  sigc::slot<CLIPS::Value, std::string>(
186  sigc::mem_fun(*this,
187  &ClipsRobotMemoryThread::clips_robotmemory_mutex_create)));
188  clips->add_function("robmem-mutex-destroy",
189  sigc::slot<CLIPS::Value, std::string>(
190  sigc::mem_fun(*this,
191  &ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy)));
192  clips->add_function("robmem-mutex-try-lock",
193  sigc::slot<CLIPS::Value, std::string, std::string>(
194  sigc::mem_fun(*this,
195  &ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock)));
196  clips->add_function("robmem-mutex-renew-lock",
197  sigc::slot<CLIPS::Value, std::string, std::string>(sigc::mem_fun(
198  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock)));
199  clips->add_function("robmem-mutex-force-lock",
200  sigc::slot<CLIPS::Value, std::string, std::string>(sigc::mem_fun(
201  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock)));
202  clips->add_function("robmem-mutex-unlock",
203  sigc::slot<CLIPS::Value, std::string, std::string>(
204  sigc::mem_fun(*this,
205  &ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock)));
206  clips->add_function("robmem-mutex-setup-ttl",
207  sigc::slot<CLIPS::Value, float>(
208  sigc::mem_fun(*this,
209  &ClipsRobotMemoryThread::clips_robotmemory_mutex_setup_ttl)));
210  clips->add_function("robmem-mutex-expire-locks",
211  sigc::slot<CLIPS::Value, float>(sigc::mem_fun(
212  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks)));
213 
214  clips->add_function("robmem-mutex-create-async",
215  sigc::slot<CLIPS::Values, std::string>(sigc::mem_fun(
216  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_create_async)));
217  clips->add_function("robmem-mutex-destroy-async",
218  sigc::slot<CLIPS::Values, std::string>(sigc::mem_fun(
219  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy_async)));
220  clips->add_function(
221  "robmem-mutex-try-lock-async",
222  sigc::slot<CLIPS::Values, std::string, std::string>(sigc::bind<0>(
223  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock_async),
224  env_name)));
225  clips->add_function(
226  "robmem-mutex-renew-lock-async",
227  sigc::slot<CLIPS::Values, std::string, std::string>(sigc::bind<0>(
228  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock_async),
229  env_name)));
230  clips->add_function("robmem-mutex-force-lock-async",
231  sigc::slot<CLIPS::Values, std::string, std::string>(sigc::mem_fun(
232  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock_async)));
233  clips->add_function("robmem-mutex-unlock-async",
234  sigc::slot<CLIPS::Values, std::string, std::string>(sigc::mem_fun(
235  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock_async)));
236  clips->add_function(
237  "robmem-mutex-expire-locks-async",
238  sigc::slot<CLIPS::Value, float>(sigc::bind<0>(
239  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks_async),
240  env_name)));
241 
242  clips->build("(deffacts have-feature-mongodb (have-feature MongoDB))");
243 
244  //load helper functions written in CLIPS
245  clips->batch_evaluate(SRCDIR "/robot-memory.clp");
246 
247  clips.unlock();
248 }
249 
250 void
252 {
253  envs_.erase(env_name);
254  logger->log_debug(name(), "Removing environment %s", env_name.c_str());
255 }
256 
257 CLIPS::Value
258 ClipsRobotMemoryThread::clips_bson_create()
259 {
260  return CLIPS::Value(new bsoncxx::builder::basic::document());
261 }
262 
263 CLIPS::Value
264 ClipsRobotMemoryThread::clips_bson_parse(std::string document)
265 {
266  auto b = new bsoncxx::builder::basic::document();
267  try {
268  b->append(bsoncxx::builder::concatenate(bsoncxx::from_json(document)));
269  } catch (bsoncxx::exception &e) {
270  logger->log_error("MongoDB", "Parsing JSON doc failed: %s\n%s", e.what(), document.c_str());
271  }
272  return CLIPS::Value(b);
273 }
274 
275 void
276 ClipsRobotMemoryThread::clips_bson_destroy(void *bson)
277 {
278  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
279  delete b;
280 }
281 
282 std::string
283 ClipsRobotMemoryThread::clips_bson_tostring(void *bson)
284 {
285  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
286  return bsoncxx::to_json(b->view());
287 }
288 
289 void
290 ClipsRobotMemoryThread::clips_bson_append(void *bson, std::string field_name, CLIPS::Value value)
291 {
292  using namespace bsoncxx::builder;
293  try {
294  auto b = static_cast<basic::document *>(bson);
295  switch (value.type()) {
296  case CLIPS::TYPE_FLOAT: b->append(basic::kvp(field_name, value.as_float())); break;
297 
298  case CLIPS::TYPE_INTEGER:
299  b->append(basic::kvp(field_name, static_cast<int64_t>(value.as_integer())));
300  break;
301 
302  case CLIPS::TYPE_SYMBOL:
303  case CLIPS::TYPE_INSTANCE_NAME:
304  case CLIPS::TYPE_STRING: b->append(basic::kvp(field_name, value.as_string())); break;
305  case CLIPS::TYPE_EXTERNAL_ADDRESS: {
306  auto subb = static_cast<basic::document *>(value.as_address());
307  b->append(basic::kvp(field_name, subb->view()));
308  } break;
309 
310  default:
311  logger->log_warn("RefBox", "Tried to add unknown type to BSON field %s", field_name.c_str());
312  break;
313  }
314  } catch (bsoncxx::exception &e) {
315  logger->log_error("MongoDB",
316  "Failed to append array value to field %s: %s",
317  field_name.c_str(),
318  e.what());
319  }
320 }
321 
322 void
323 ClipsRobotMemoryThread::clips_bson_append_regex(void * bson,
324  std::string field_name,
325  CLIPS::Value regex_string)
326 {
327  using namespace bsoncxx::builder;
328  if (regex_string.type() != CLIPS::TYPE_STRING) {
329  logger->log_error("MongoDB", "Regex string has to be of type string");
330  return;
331  }
332  try {
333  auto b = static_cast<basic::document *>(bson);
334  b->append(basic::kvp(field_name, bsoncxx::types::b_regex{regex_string.as_string()}));
335  } catch (bsoncxx::exception &e) {
336  logger->log_error("MongoDB",
337  "Failed to append regex to field %s: %s",
338  field_name.c_str(),
339  e.what());
340  }
341 }
342 
343 void
344 ClipsRobotMemoryThread::clips_bson_append_array(void * bson,
345  std::string field_name,
346  CLIPS::Values values)
347 {
348  using namespace bsoncxx::builder;
349  try {
350  auto b = static_cast<basic::document *>(bson);
351 
352  b->append(basic::kvp(field_name, [&](basic::sub_array array) {
353  for (auto value : values) {
354  switch (value.type()) {
355  case CLIPS::TYPE_FLOAT: array.append(value.as_float()); break;
356 
357  case CLIPS::TYPE_INTEGER: array.append(static_cast<int64_t>(value.as_integer())); break;
358 
359  case CLIPS::TYPE_SYMBOL:
360  case CLIPS::TYPE_STRING:
361  case CLIPS::TYPE_INSTANCE_NAME: array.append(value.as_string()); break;
362 
363  case CLIPS::TYPE_EXTERNAL_ADDRESS: {
364  auto subb = static_cast<bsoncxx::builder::basic::document *>(value.as_address());
365  array.append(subb->view());
366  } break;
367 
368  default:
369  logger->log_warn("MongoDB",
370  "Tried to add unknown type to BSON array field %s",
371  field_name.c_str());
372  break;
373  }
374  }
375  }));
376  } catch (bsoncxx::exception &e) {
377  logger->log_error("MongoDB",
378  "Failed to append array value to field %s: %s",
379  field_name.c_str(),
380  e.what());
381  }
382 }
383 
384 CLIPS::Value
385 ClipsRobotMemoryThread::clips_bson_array_start(void *bson, std::string field_name)
386 {
387  // With the new libmongocxx, we can no longer create an open array as
388  // sub-field of another document.
389  throw Exception("Not implemented");
390  /*
391  mongo::BSONObjBuilder * b = static_cast<mongo::BSONObjBuilder *>(bson);
392  mongo::BufBuilder & bb = b->subarrayStart(field_name);
393  mongo::BSONArrayBuilder *arrb = new mongo::BSONArrayBuilder(bb);
394  return CLIPS::Value(arrb);
395  */
396 }
397 
398 void
399 ClipsRobotMemoryThread::clips_bson_array_finish(void *barr)
400 {
401  throw Exception("Not implemented");
402  /*
403  mongo::BSONArrayBuilder *ab = static_cast<mongo::BSONArrayBuilder *>(barr);
404  delete ab;
405  */
406 }
407 
408 void
409 ClipsRobotMemoryThread::clips_bson_array_append(void *barr, CLIPS::Value value)
410 {
411  throw Exception("Not implemented");
412  /*
413  try {
414  auto *ab = static_cast<mongo::BSONArrayBuilder *>(barr);
415  switch (value.type()) {
416  case CLIPS::TYPE_FLOAT: ab->append(value.as_float()); break;
417 
418  case CLIPS::TYPE_INTEGER: ab->append(value.as_integer()); break;
419 
420  case CLIPS::TYPE_SYMBOL:
421  case CLIPS::TYPE_STRING:
422  case CLIPS::TYPE_INSTANCE_NAME: ab->append(value.as_string()); break;
423 
424  case CLIPS::TYPE_EXTERNAL_ADDRESS: {
425  mongo::BSONObjBuilder *subb = static_cast<mongo::BSONObjBuilder *>(value.as_address());
426  ab->append(subb->asTempObj());
427  } break;
428 
429  default: logger->log_warn("RefBox", "Tried to add unknown type to BSON array"); break;
430  }
431 #ifdef HAVE_MONGODB_VERSION_H
432  } catch (mongo::MsgAssertionException &e) {
433 #else
434  } catch (mongo::AssertionException &e) {
435 #endif
436  logger->log_error("MongoDB", "Failed to append to array: %s", e.what());
437  }
438  */
439 }
440 
441 void
442 ClipsRobotMemoryThread::clips_bson_append_time(void * bson,
443  std::string field_name,
444  CLIPS::Values time)
445 {
446  if (time.size() != 2) {
447  logger->log_warn("MongoDB", "Invalid time, %zu instead of 2 entries", time.size());
448  return;
449  }
450  if (time[0].type() != CLIPS::TYPE_INTEGER || time[1].type() != CLIPS::TYPE_INTEGER) {
451  logger->log_warn("MongoDB", "Invalid time, type mismatch");
452  return;
453  }
454 
455  try {
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) {
463  logger->log_error("MongoDB",
464  "Failed to append time value to field %s: %s",
465  field_name.c_str(),
466  e.what());
467  }
468 }
469 
470 void
471 ClipsRobotMemoryThread::clips_robotmemory_insert(std::string collection, void *bson)
472 {
473  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
474 
475  try {
476  robot_memory->insert(b->view(), collection);
477  } catch (mongocxx::exception &e) {
478  logger->log_warn("MongoDB", "Insert failed: %s", e.what());
479  }
480 }
481 
482 void
483 ClipsRobotMemoryThread::clips_robotmemory_create_index(std::string collection, void *bson)
484 {
485  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
486 
487  try {
488  robot_memory->create_index(b->view(), collection, /* unique */ false);
489  } catch (mongocxx::exception &e) {
490  logger->log_warn("MongoDB", "Creating index failed: %s", e.what());
491  }
492 }
493 
494 void
495 ClipsRobotMemoryThread::clips_robotmemory_create_unique_index(std::string collection, void *bson)
496 {
497  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
498 
499  try {
500  robot_memory->create_index(b->view(), collection, /* unique */ true);
501  } catch (mongocxx::exception &e) {
502  logger->log_warn("MongoDB", "Creating unique index failed: %s", e.what());
503  }
504 }
505 
506 void
507 ClipsRobotMemoryThread::robotmemory_update(std::string & collection,
508  const bsoncxx::document::view &update,
509  CLIPS::Value & query,
510  bool upsert)
511 {
512  try {
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());
518  robot_memory->update(qb->view(), update, collection, upsert);
519  } else {
520  logger->log_warn("MongoDB", "Invalid query, must be string or BSON document");
521  return;
522  }
523 
524  } catch (bsoncxx::exception &e) {
525  logger->log_warn("MongoDB", "Compiling query failed: %s", e.what());
526  } catch (mongocxx::exception &e) {
527  logger->log_warn("MongoDB", "Insert failed: %s", e.what());
528  }
529 }
530 
531 void
532 ClipsRobotMemoryThread::clips_robotmemory_upsert(std::string collection,
533  void * bson,
534  CLIPS::Value query)
535 {
536  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
537  if (!b) {
538  logger->log_warn("MongoDB", "Invalid BSON Builder passed");
539  return;
540  }
541  robotmemory_update(collection, b->view(), query, true);
542 }
543 
544 void
545 ClipsRobotMemoryThread::clips_robotmemory_update(std::string collection,
546  void * bson,
547  CLIPS::Value query)
548 {
549  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
550  if (!b) {
551  logger->log_warn("MongoDB", "Invalid BSON Builder passed");
552  return;
553  }
554  robotmemory_update(collection, b->view(), query, false);
555 }
556 
557 void
558 ClipsRobotMemoryThread::clips_robotmemory_replace(std::string collection,
559  void * bson,
560  CLIPS::Value query)
561 {
562  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
563  if (!b)
564  logger->log_warn("MongoDB", "Invalid BSON Builder passed");
565  robotmemory_update(collection, b->view(), query, false);
566 }
567 
568 CLIPS::Value
569 ClipsRobotMemoryThread::clips_robotmemory_query_sort(std::string collection,
570  void * bson,
571  void * bson_sort)
572 {
573  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
574 
575  try {
576  mongocxx::options::find find_opts{};
577  if (bson_sort) {
578  auto *bs = static_cast<bsoncxx::builder::basic::document *>(bson_sort);
579  find_opts.sort(bs->view());
580  }
581 
582  auto cursor = robot_memory->query(b->view(), collection, find_opts);
583  //std::unique_ptr<mongocxx::cursor> c = new mongocxx::cursor(std::move(cursor));
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) {
588  logger->log_warn("MongoDB", "Query failed: %s", e.what());
589  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
590  }
591 }
592 
593 CLIPS::Value
594 ClipsRobotMemoryThread::clips_robotmemory_dump_collection(std::string collection,
595  std::string directory)
596 {
597  try {
598  int succ = robot_memory->dump_collection(collection, directory);
599  if (succ == 1) {
600  return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
601  } else {
602  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
603  }
604  } catch (mongocxx::exception &e) {
605  logger->log_error("MongoDB",
606  "Dumping collection %s to %s failed: \n %s",
607  collection.c_str(),
608  directory.c_str(),
609  e.what());
610  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
611  }
612 }
613 
614 CLIPS::Value
615 ClipsRobotMemoryThread::clips_robotmemory_restore_collection(std::string collection,
616  std::string directory,
617  std::string target_collection)
618 {
619  try {
620  int succ = robot_memory->restore_collection(collection, directory, target_collection);
621  if (succ == 1) {
622  return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
623  } else {
624  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
625  }
626  } catch (mongocxx::exception &e) {
627  logger->log_error("MongoDB",
628  "Restoring collection %s to %s failed: \n %s",
629  collection.c_str(),
630  directory.c_str(),
631  e.what());
632  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
633  }
634 }
635 
636 void
637 ClipsRobotMemoryThread::clips_robotmemory_remove(std::string collection, void *bson)
638 {
639  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
640  try {
641  robot_memory->remove(b->view(), collection);
642  } catch (std::system_error &e) {
643  logger->log_warn("MongoDB", "Remove failed: %s", e.what());
644  }
645 }
646 
647 CLIPS::Value
648 ClipsRobotMemoryThread::clips_robotmemory_query(const std::string &collection, void *bson)
649 {
650  return clips_robotmemory_query_sort(collection, bson, NULL);
651 }
652 
653 void
654 ClipsRobotMemoryThread::clips_robotmemory_cursor_destroy(void *cursor)
655 {
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");
659  return;
660  }
661 
662  delete c;
663 }
664 
665 CLIPS::Value
666 ClipsRobotMemoryThread::clips_robotmemory_cursor_more(void *cursor)
667 {
668  throw Exception("The function cursor-more is no longer supported. Call cursor-next and check the "
669  "return value for FALSE instead.");
670 }
671 
672 CLIPS::Value
673 ClipsRobotMemoryThread::clips_robotmemory_cursor_next(void *cursor)
674 {
675  auto c = static_cast<std::unique_ptr<mongocxx::cursor> *>(cursor);
676 
677  if (!c || !c->get()) {
678  logger->log_error("MongoDB", "mongodb-cursor-next: got invalid cursor");
679  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
680  }
681 
682  try {
683  auto it = (*c)->begin();
684  if (it == (*c)->end()) {
685  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
686  } else {
687  auto b = new bsoncxx::builder::basic::document();
688  b->append(bsoncxx::builder::concatenate(*it));
689  it++;
690  return CLIPS::Value(b);
691  }
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);
695  }
696 }
697 
698 CLIPS::Values
699 ClipsRobotMemoryThread::clips_bson_field_names(void *bson)
700 {
701  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
702 
703  if (!b) {
704  logger->log_error("MongoDB", "mongodb-bson-field-names: invalid object");
705  CLIPS::Values rv;
706  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
707  return rv;
708  }
709 
710  CLIPS::Values rv;
711  for (auto element : b->view()) {
712  rv.push_back(CLIPS::Value(std::string(element.key())));
713  }
714  return rv;
715 }
716 
717 CLIPS::Value
718 ClipsRobotMemoryThread::clips_bson_get(void *bson, std::string field_name)
719 {
720  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
721 
722  if (!b) {
723  logger->log_error("MongoDB", "mongodb-bson-get: invalid object");
724  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
725  }
726 
727  try {
728  auto el = get_dotted_field(b->view(), field_name);
729  if (!el) {
730  logger->log_warn(name(),
731  "mongodb-bson-get: failed to get '%s', no such element in doc: %s",
732  field_name.c_str(),
733  bsoncxx::to_json(b->view()).c_str());
734  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
735  }
736  switch (el.type()) {
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);
747  }
748  case bsoncxx::type::k_oid: //ObjectId
749  return CLIPS::Value(el.get_oid().value.to_string());
750 
751  default: return CLIPS::Value("INVALID_VALUE_TYPE", CLIPS::TYPE_SYMBOL);
752  }
753  } catch (std::system_error &e) {
754  logger->log_warn(name(),
755  "mongodb-bson-get: failed to get '%s': %s",
756  field_name.c_str(),
757  e.what());
758  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
759  }
760 }
761 
762 CLIPS::Value
763 ClipsRobotMemoryThread::clips_bson_has_field(void *bson, std::string field_name)
764 {
765  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
766 
767  if (!b) {
768  logger->log_error("MongoDB", "mongodb-bson-get: invalid object");
769  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
770  }
771 
772  try {
773  auto el = get_dotted_field(b->view(), field_name);
774  if (!el.key().empty()) {
775  return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
776  } else {
777  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
778  }
779  } catch (bsoncxx::exception &e) {
780  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
781  }
782 }
783 
784 CLIPS::Values
785 ClipsRobotMemoryThread::clips_bson_get_array(void *bson, std::string field_name)
786 {
787  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
788 
789  CLIPS::Values rv;
790 
791  if (!b) {
792  logger->log_error("MongoDB", "mongodb-bson-get-array: invalid object");
793  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
794  return rv;
795  }
796 
797  try {
798  auto el = get_dotted_field(b->view(), field_name);
799 
800  if (el.type() != bsoncxx::type::k_array) {
801  logger->log_error("MongoDB",
802  "mongodb-bson-get-array: field %s is not an array",
803  field_name.c_str());
804  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
805  return rv;
806  }
807 
808  bsoncxx::array::view array_view{el.get_array()};
809  for (const auto e : array_view) {
810  switch (e.type()) {
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));
815  break;
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));
822  } break;
823  default:
824  rv.clear();
825  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
826  return rv;
827  }
828  }
829  return rv;
830  } catch (bsoncxx::exception &e) {
831  logger->log_warn(name(),
832  "mongodb-bson-get: failed to get '%s': %s",
833  field_name.c_str(),
834  e.what());
835  rv.clear();
836  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
837  return rv;
838  }
839 }
840 
841 CLIPS::Values
842 ClipsRobotMemoryThread::clips_bson_get_time(void *bson, std::string field_name)
843 {
844  auto b = static_cast<bsoncxx::builder::basic::document *>(bson);
845 
846  CLIPS::Values rv;
847 
848  if (!b) {
849  logger->log_error("MongoDB", "mongodb-bson-get-time: invalid object");
850  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
851  return rv;
852  }
853 
854  try {
855  auto el = get_dotted_field(b->view(), field_name);
856  int64_t ts = 0;
857  if (el.type() == bsoncxx::type::k_date) {
858  bsoncxx::types::b_date d = el.get_date();
859  ts = d.to_int64();
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;
863  } else {
864  logger->log_error("MongoDB",
865  "mongodb-bson-get-time: field %s is not a time",
866  field_name.c_str());
867  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
868  return rv;
869  }
870 
871  rv.resize(2);
872  rv[0] = CLIPS::Value((long long int)(ts / 1000));
873  rv[1] = CLIPS::Value((ts - (rv[0].as_integer() * 1000)) * 1000);
874  return rv;
875  } catch (bsoncxx::exception &e) {
876  rv.resize(2, CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
877  return rv;
878  }
879 }
880 
881 CLIPS::Value
882 ClipsRobotMemoryThread::clips_robotmemory_register_trigger(std::string env_name,
883  std::string collection,
884  void * query,
885  std::string assert_name)
886 {
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);
894  }
895  auto fut = std::async(std::launch::async, [this, b, env_name, collection, assert_name] {
896  try {
897  ClipsRmTrigger *clips_trigger =
898  new ClipsRmTrigger(assert_name, robot_memory, envs_[env_name], logger);
899  clips_trigger->set_trigger(robot_memory->register_trigger(
900  b.view(), collection, &ClipsRmTrigger::callback, clips_trigger));
901  MutexLocker triggers_lock(&clips_triggers_mutex_);
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)",
905  assert_name.c_str(),
906  CLIPS::Value(clips_trigger).as_address());
907  return true;
908  } catch (std::system_error &e) {
909  logger->log_warn(name(), "Error while registering trigger: %s", e.what());
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());
913  return false;
914  }
915  });
916 
917  mutex_futures_[future_name] = std::move(fut);
918  return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
919 }
920 
921 void
922 ClipsRobotMemoryThread::clips_robotmemory_destroy_trigger(void *trigger)
923 {
924  ClipsRmTrigger *clips_trigger = static_cast<ClipsRmTrigger *>(trigger);
925  MutexLocker triggers_lock(&clips_triggers_mutex_);
926  clips_triggers_.remove(clips_trigger);
927  delete clips_trigger; //the triger unregisteres itself at the robot memory
928 }
929 
930 CLIPS::Value
931 ClipsRobotMemoryThread::clips_robotmemory_mutex_create(std::string name)
932 {
933  bool rv = robot_memory->mutex_create(name);
934  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
935 }
936 
937 CLIPS::Value
938 ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy(std::string name)
939 {
940  bool rv = robot_memory->mutex_destroy(name);
941  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
942 }
943 
944 CLIPS::Value
945 ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock(std::string name, std::string identity)
946 {
947  bool rv = robot_memory->mutex_try_lock(name, identity);
948  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
949 }
950 
951 CLIPS::Value
952 ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock(std::string name, std::string identity)
953 {
954  bool rv = robot_memory->mutex_renew_lock(name, identity);
955  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
956 }
957 
958 CLIPS::Value
959 ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock(std::string name, std::string identity)
960 {
961  bool rv = robot_memory->mutex_try_lock(name, identity, /* force */ true);
962  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
963 }
964 
965 CLIPS::Value
966 ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock(std::string name, std::string identity)
967 {
968  bool rv = robot_memory->mutex_unlock(name, identity);
969  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
970 }
971 
972 CLIPS::Value
973 ClipsRobotMemoryThread::clips_robotmemory_mutex_setup_ttl(float max_age_sec)
974 {
975  bool rv = robot_memory->mutex_setup_ttl(max_age_sec);
976  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
977 }
978 
979 CLIPS::Value
980 ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks(float max_age_sec)
981 {
982  bool rv = robot_memory->mutex_expire_locks(max_age_sec);
983  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
984 }
985 
986 bool
987 ClipsRobotMemoryThread::mutex_future_ready(const std::string &name)
988 {
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) {
993  return false;
994  } else {
995  mutex_futures_.erase(mf_it);
996  }
997  }
998  return true;
999 }
1000 
1001 CLIPS::Values
1002 ClipsRobotMemoryThread::clips_robotmemory_mutex_create_async(std::string name)
1003 {
1004  CLIPS::Values rv;
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)"));
1008  return rv;
1009  }
1010 
1011  auto fut =
1012  std::async(std::launch::async, [this, name] { return robot_memory->mutex_create(name); });
1013 
1014  mutex_futures_[name] = std::move(fut);
1015 
1016  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1017  return rv;
1018 }
1019 
1020 CLIPS::Values
1021 ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy_async(std::string name)
1022 {
1023  CLIPS::Values rv;
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)"));
1027  return rv;
1028  }
1029 
1030  auto fut =
1031  std::async(std::launch::async, [this, name] { return robot_memory->mutex_destroy(name); });
1032 
1033  mutex_futures_[name] = std::move(fut);
1034 
1035  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1036  return rv;
1037 }
1038 
1039 CLIPS::Values
1040 ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock_async(std::string env_name,
1041  std::string name,
1042  std::string identity)
1043 {
1044  CLIPS::Values rv;
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());
1049  return rv;
1050  }
1051 
1052  auto fut = std::async(std::launch::async, [this, env_name, name, identity] {
1053  bool ok = robot_memory->mutex_try_lock(name, identity);
1054  if (!ok) {
1055  MutexLocker lock(envs_[env_name].objmutex_ptr());
1056  envs_[env_name]->assert_fact_f("(mutex-op-feedback try-lock-async FAIL %s)", name.c_str());
1057  }
1058  return ok;
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_renew_lock_async(std::string env_name,
1069  std::string name,
1070  std::string identity)
1071 {
1072  CLIPS::Values rv;
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)"));
1076  MutexLocker lock(envs_[env_name].objmutex_ptr());
1077  envs_[env_name]->assert_fact_f("(mutex-op-feedback renew-lock-async FAIL %s)", name.c_str());
1078  return rv;
1079  }
1080 
1081  auto fut = std::async(std::launch::async, [this, env_name, name, identity] {
1082  bool ok = robot_memory->mutex_renew_lock(name, identity);
1083  MutexLocker lock(envs_[env_name].objmutex_ptr());
1084  envs_[env_name]->assert_fact_f("(mutex-op-feedback renew-lock-async %s %s)",
1085  ok ? "OK" : "FAIL",
1086  name.c_str());
1087  return ok;
1088  });
1089 
1090  mutex_futures_[name] = std::move(fut);
1091 
1092  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1093  return rv;
1094 }
1095 
1096 CLIPS::Values
1097 ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock_async(std::string name,
1098  std::string identity)
1099 {
1100  CLIPS::Values rv;
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)"));
1104  return rv;
1105  }
1106 
1107  auto fut = std::async(std::launch::async, [this, name, identity] {
1108  return robot_memory->mutex_try_lock(name, identity, /* force */ true);
1109  });
1110 
1111  mutex_futures_[name] = std::move(fut);
1112 
1113  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1114  return rv;
1115 }
1116 
1117 CLIPS::Values
1118 ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock_async(std::string name, std::string identity)
1119 {
1120  CLIPS::Values rv;
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)"));
1124  return rv;
1125  }
1126 
1127  auto fut = std::async(std::launch::async, [this, name, identity] {
1128  return robot_memory->mutex_unlock(name, identity);
1129  });
1130 
1131  mutex_futures_[name] = std::move(fut);
1132 
1133  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1134  return rv;
1135 }
1136 
1137 CLIPS::Value
1138 ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks_async(std::string env_name,
1139  float max_age_sec)
1140 {
1141  CLIPS::Values rv;
1142  if (mutex_expire_future_.valid()) {
1143  // have shared state, expire was or is running
1144  auto fut_status = mutex_expire_future_.wait_for(std::chrono::milliseconds(0));
1145  if (fut_status != std::future_status::ready) {
1146  MutexLocker lock(envs_[env_name].objmutex_ptr());
1147  envs_[env_name]->assert_fact_f("(mutex-op-feedback expire-locks-async FAIL)");
1148  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
1149  }
1150  }
1151 
1152  auto fut = std::async(std::launch::async, [this, env_name, max_age_sec] {
1153  bool ok = robot_memory->mutex_expire_locks(max_age_sec);
1154  MutexLocker lock(envs_[env_name].objmutex_ptr());
1155  envs_[env_name]->assert_fact_f("(mutex-op-feedback expire-locks-async %s)", ok ? "OK" : "FAIL");
1156  return ok;
1157  });
1158 
1159  mutex_expire_future_ = std::move(fut);
1160 
1161  return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
1162 }
void callback(const bsoncxx::document::view &update)
Callback function for the trigger.
void set_trigger(EventTrigger *trigger)
Set the trigger object given by the robot memory.
virtual void loop()
Code to execute in the thread.
virtual void finalize()
Finalize the thread.
virtual void clips_context_destroyed(const std::string &env_name)
Notification that a CLIPS environment has been destroyed.
virtual void init()
Initialize the thread.
virtual void clips_context_init(const std::string &env_name, fawkes::LockPtr< CLIPS::Environment > &clips)
Initialize a CLIPS context to use the provided feature.
bool mutex_create(const std::string &name)
Explicitly create a mutex.
int dump_collection(const std::string &dbcollection, const std::string &directory="@CONFDIR@/robot-memory")
Dump (= save) a collection to the filesystem to restore it later.
bool mutex_destroy(const std::string &name)
Destroy a mutex.
bool mutex_renew_lock(const std::string &name, const std::string &identity)
Renew a mutex.
bool mutex_unlock(const std::string &name, const std::string &identity)
Release lock on mutex.
mongocxx::cursor query(bsoncxx::document::view query, const std::string &collection_name="", mongocxx::options::find query_options=mongocxx::options::find())
Query information from the robot memory.
bool mutex_setup_ttl(float max_age_sec)
Setup time-to-live index for mutexes.
int remove(const bsoncxx::document::view &query, const std::string &collection="")
Remove documents from the robot memory.
int insert(bsoncxx::document::view, const std::string &collection="")
Inserts a document into the robot memory.
EventTrigger * register_trigger(const bsoncxx::document::view &query, const std::string &collection, void(T::*callback)(const bsoncxx::document::view &), T *_obj)
Register a trigger to be notified when the robot memory is updated and the updated document matches t...
Definition: robot_memory.h:121
int update(const bsoncxx::document::view &query, const bsoncxx::document::view &update, const std::string &collection="", bool upsert=false)
Updates documents in the robot memory.
bool mutex_try_lock(const std::string &name, bool force=false)
Try to acquire a lock for a mutex.
int create_index(bsoncxx::document::view keys, const std::string &collection="", bool unique=false)
Create an index on a collection.
int restore_collection(const std::string &dbcollection, const std::string &directory="@CONFDIR@/robot-memory", std::string target_dbcollection="")
Restore a previously dumped collection from a directory.
bool mutex_expire_locks(float max_age_sec)
Expire old locks on mutexes.
Thread aspect to provide a feature to CLIPS environments.
Definition: clips_feature.h:58
CLIPS feature maintainer.
Definition: clips_feature.h:42
Base class for exceptions in Fawkes.
Definition: exception.h:36
void lock() const
Lock access to the encapsulated object.
Definition: lockptr.h:257
void unlock() const
Unlock object mutex.
Definition: lockptr.h:273
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:41
Mutex locking helper.
Definition: mutex_locker.h:34
RobotMemory * robot_memory
RobotMemory object for storing and querying information.
Thread class encapsulation of pthreads.
Definition: thread.h:46
const char * name() const
Get name of thread.
Definition: thread.h:100
Fawkes library namespace.