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 
27 using namespace fawkes;
28 
29 /** @class ClipsRobotMemoryThread 'clips_robot_memory_thread.h'
30  * CLIPS feature to access the robot memory.
31  * MongoDB access through CLIPS first appeared in the RCLL referee box.
32  * @author Tim Niemueller
33  * @author Frederik Zwilling
34  */
35 
36 ClipsRobotMemoryThread::ClipsRobotMemoryThread()
37 : Thread("ClipsRobotMemoryThread", Thread::OPMODE_WAITFORWAKEUP),
38  CLIPSFeature("robot_memory"),
39  CLIPSFeatureAspect(this)
40 {
41 }
42 
43 void
45 {
46 }
47 
48 void
50 {
51 }
52 
53 void
55 {
56  envs_.clear();
57  for (ClipsRmTrigger *trigger : clips_triggers_) {
58  delete trigger;
59  }
60 }
61 
62 void
63 ClipsRobotMemoryThread::clips_context_init(const std::string & env_name,
65 {
66  envs_[env_name] = clips;
67  logger->log_debug(name(), "Called to initialize environment %s", env_name.c_str());
68 
69  clips.lock();
70 
71  clips->add_function("bson-create",
72  sigc::slot<CLIPS::Value>(
73  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_create)));
74  clips->add_function("bson-parse",
75  sigc::slot<CLIPS::Value, std::string>(
76  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_parse)));
77  clips->add_function("bson-destroy",
78  sigc::slot<void, void *>(
79  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_destroy)));
80  clips->add_function("bson-append",
81  sigc::slot<void, void *, std::string, CLIPS::Value>(
82  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_append)));
83  clips->add_function("bson-append-array",
84  sigc::slot<void, void *, std::string, CLIPS::Values>(
85  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_append_array)));
86  clips->add_function("bson-array-start",
87  sigc::slot<CLIPS::Value, void *, std::string>(
88  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_array_start)));
89  clips->add_function("bson-array-finish",
90  sigc::slot<void, void *>(
91  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_array_finish)));
92  clips->add_function("bson-array-append",
93  sigc::slot<void, void *, CLIPS::Value>(
94  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_array_append)));
95 
96  clips->add_function("bson-append-time",
97  sigc::slot<void, void *, std::string, CLIPS::Values>(
98  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_append_time)));
99  clips->add_function("bson-tostring",
100  sigc::slot<std::string, void *>(
101  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_tostring)));
102  clips->add_function("robmem-insert",
103  sigc::slot<void, std::string, void *>(
104  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_insert)));
105  clips->add_function("robmem-upsert",
106  sigc::slot<void, std::string, void *, CLIPS::Value>(
107  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_upsert)));
108  clips->add_function("robmem-update",
109  sigc::slot<void, std::string, void *, CLIPS::Value>(
110  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_update)));
111  clips->add_function("robmem-replace",
112  sigc::slot<void, std::string, void *, CLIPS::Value>(
113  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_replace)));
114  clips->add_function("robmem-query",
115  sigc::slot<CLIPS::Value, std::string, void *>(
116  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_query)));
117  clips->add_function("robmem-remove",
118  sigc::slot<void, std::string, void *>(
119  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_remove)));
120  clips->add_function("robmem-query-sort",
121  sigc::slot<CLIPS::Value, std::string, void *, void *>(
122  sigc::mem_fun(*this,
123  &ClipsRobotMemoryThread::clips_robotmemory_query_sort)));
124  clips->add_function("robmem-cursor-destroy",
125  sigc::slot<void, void *>(
126  sigc::mem_fun(*this,
127  &ClipsRobotMemoryThread::clips_robotmemory_cursor_destroy)));
128  clips->add_function("robmem-cursor-more",
129  sigc::slot<CLIPS::Value, void *>(
130  sigc::mem_fun(*this,
131  &ClipsRobotMemoryThread::clips_robotmemory_cursor_more)));
132  clips->add_function("robmem-cursor-next",
133  sigc::slot<CLIPS::Value, void *>(
134  sigc::mem_fun(*this,
135  &ClipsRobotMemoryThread::clips_robotmemory_cursor_next)));
136  clips->add_function("robmem-trigger-register",
137  sigc::slot<CLIPS::Value, std::string, void *, std::string>(sigc::bind<0>(
138  sigc::mem_fun(*this,
139  &ClipsRobotMemoryThread::clips_robotmemory_register_trigger),
140  env_name)));
141  clips->add_function("robmem-trigger-destroy",
142  sigc::slot<void, void *>(
143  sigc::mem_fun(*this,
144  &ClipsRobotMemoryThread::clips_robotmemory_destroy_trigger)));
145  clips->add_function("bson-field-names",
146  sigc::slot<CLIPS::Values, void *>(
147  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_field_names)));
148  clips->add_function("bson-has-field",
149  sigc::slot<CLIPS::Value, void *, std::string>(
150  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_has_field)));
151  clips->add_function("bson-get",
152  sigc::slot<CLIPS::Value, void *, std::string>(
153  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_get)));
154  clips->add_function("bson-get-array",
155  sigc::slot<CLIPS::Values, void *, std::string>(
156  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_get_array)));
157  clips->add_function("bson-get-time",
158  sigc::slot<CLIPS::Values, void *, std::string>(
159  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_bson_get_time)));
160  clips->add_function("robmem-create-index",
161  sigc::slot<void, std::string, void *>(
162  sigc::mem_fun(*this,
163  &ClipsRobotMemoryThread::clips_robotmemory_create_index)));
164  clips->add_function("robmem-create-unique-index",
165  sigc::slot<void, std::string, void *>(sigc::mem_fun(
166  *this, &ClipsRobotMemoryThread::clips_robotmemory_create_unique_index)));
167 
168  clips->add_function("robmem-mutex-create",
169  sigc::slot<CLIPS::Value, std::string>(
170  sigc::mem_fun(*this,
171  &ClipsRobotMemoryThread::clips_robotmemory_mutex_create)));
172  clips->add_function("robmem-mutex-destroy",
173  sigc::slot<CLIPS::Value, std::string>(
174  sigc::mem_fun(*this,
175  &ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy)));
176  clips->add_function("robmem-mutex-try-lock",
177  sigc::slot<CLIPS::Value, std::string, std::string>(
178  sigc::mem_fun(*this,
179  &ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock)));
180  clips->add_function("robmem-mutex-renew-lock",
181  sigc::slot<CLIPS::Value, std::string, std::string>(sigc::mem_fun(
182  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock)));
183  clips->add_function("robmem-mutex-force-lock",
184  sigc::slot<CLIPS::Value, std::string, std::string>(sigc::mem_fun(
185  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock)));
186  clips->add_function("robmem-mutex-unlock",
187  sigc::slot<CLIPS::Value, std::string, std::string>(
188  sigc::mem_fun(*this,
189  &ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock)));
190  clips->add_function("robmem-mutex-setup-ttl",
191  sigc::slot<CLIPS::Value, float>(
192  sigc::mem_fun(*this,
193  &ClipsRobotMemoryThread::clips_robotmemory_mutex_setup_ttl)));
194  clips->add_function("robmem-mutex-expire-locks",
195  sigc::slot<CLIPS::Value, float>(sigc::mem_fun(
196  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks)));
197 
198  clips->add_function("robmem-mutex-create-async",
199  sigc::slot<CLIPS::Values, std::string>(sigc::mem_fun(
200  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_create_async)));
201  clips->add_function("robmem-mutex-destroy-async",
202  sigc::slot<CLIPS::Values, std::string>(sigc::mem_fun(
203  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy_async)));
204  clips->add_function(
205  "robmem-mutex-try-lock-async",
206  sigc::slot<CLIPS::Values, std::string, std::string>(sigc::bind<0>(
207  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock_async),
208  env_name)));
209  clips->add_function(
210  "robmem-mutex-renew-lock-async",
211  sigc::slot<CLIPS::Values, std::string, std::string>(sigc::bind<0>(
212  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock_async),
213  env_name)));
214  clips->add_function("robmem-mutex-force-lock-async",
215  sigc::slot<CLIPS::Values, std::string, std::string>(sigc::mem_fun(
216  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock_async)));
217  clips->add_function("robmem-mutex-unlock-async",
218  sigc::slot<CLIPS::Values, std::string, std::string>(sigc::mem_fun(
219  *this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock_async)));
220  clips->add_function(
221  "robmem-mutex-expire-locks-async",
222  sigc::slot<CLIPS::Value, float>(sigc::bind<0>(
223  sigc::mem_fun(*this, &ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks_async),
224  env_name)));
225 
226  clips->build("(deffacts have-feature-mongodb (have-feature MongoDB))");
227 
228  //load helper functions written in CLIPS
229  clips->batch_evaluate(SRCDIR "/robot-memory.clp");
230 
231  clips.unlock();
232 }
233 
234 void
236 {
237  envs_.erase(env_name);
238  logger->log_debug(name(), "Removing environment %s", env_name.c_str());
239 }
240 
241 CLIPS::Value
242 ClipsRobotMemoryThread::clips_bson_create()
243 {
244  mongo::BSONObjBuilder *b = new mongo::BSONObjBuilder();
245  return CLIPS::Value(b);
246 }
247 
248 CLIPS::Value
249 ClipsRobotMemoryThread::clips_bson_parse(std::string document)
250 {
251  mongo::BSONObjBuilder *b = new mongo::BSONObjBuilder();
252  try {
253  b->appendElements(mongo::fromjson(document));
254 #ifdef HAVE_MONGODB_VERSION_H
255  } catch (mongo::MsgAssertionException &e) {
256 #else
257  } catch (mongo::AssertionException &e) {
258 #endif
259  logger->log_error("MongoDB", "Parsing JSON doc failed: %s\n%s", e.what(), document.c_str());
260  }
261  return CLIPS::Value(b);
262 }
263 
264 void
265 ClipsRobotMemoryThread::clips_bson_destroy(void *bson)
266 {
267  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
268  delete b;
269 }
270 
271 std::string
272 ClipsRobotMemoryThread::clips_bson_tostring(void *bson)
273 {
274  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
275  return b->asTempObj().jsonString(mongo::Strict, true);
276 }
277 
278 void
279 ClipsRobotMemoryThread::clips_bson_append(void *bson, std::string field_name, CLIPS::Value value)
280 {
281  try {
282  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
283  switch (value.type()) {
284  case CLIPS::TYPE_FLOAT: b->append(field_name, value.as_float()); break;
285 
286  case CLIPS::TYPE_INTEGER: b->append(field_name, value.as_integer()); break;
287 
288  case CLIPS::TYPE_SYMBOL:
289  case CLIPS::TYPE_INSTANCE_NAME:
290  case CLIPS::TYPE_STRING: b->append(field_name, value.as_string()); break;
291  case CLIPS::TYPE_EXTERNAL_ADDRESS: {
292  mongo::BSONObjBuilder *subb = static_cast<mongo::BSONObjBuilder *>(value.as_address());
293  b->append(field_name, subb->asTempObj());
294  } break;
295 
296  default:
297  logger->log_warn("RefBox", "Tried to add unknown type to BSON field %s", field_name.c_str());
298  break;
299  }
300 #ifdef HAVE_MONGODB_VERSION_H
301  } catch (mongo::MsgAssertionException &e) {
302 #else
303  } catch (mongo::AssertionException &e) {
304 #endif
305  logger->log_error("MongoDB",
306  "Failed to append array value to field %s: %s",
307  field_name.c_str(),
308  e.what());
309  }
310 }
311 
312 void
313 ClipsRobotMemoryThread::clips_bson_append_array(void * bson,
314  std::string field_name,
315  CLIPS::Values values)
316 {
317  try {
318  mongo::BSONObjBuilder * b = static_cast<mongo::BSONObjBuilder *>(bson);
319  mongo::BSONArrayBuilder ab(b->subarrayStart(field_name));
320 
321  for (auto value : values) {
322  switch (value.type()) {
323  case CLIPS::TYPE_FLOAT: ab.append(value.as_float()); break;
324 
325  case CLIPS::TYPE_INTEGER: ab.append(value.as_integer()); break;
326 
327  case CLIPS::TYPE_SYMBOL:
328  case CLIPS::TYPE_STRING:
329  case CLIPS::TYPE_INSTANCE_NAME: ab.append(value.as_string()); break;
330 
331  case CLIPS::TYPE_EXTERNAL_ADDRESS: {
332  mongo::BSONObjBuilder *subb = static_cast<mongo::BSONObjBuilder *>(value.as_address());
333  ab.append(subb->asTempObj());
334  } break;
335 
336  default:
337  logger->log_warn("MongoDB",
338  "Tried to add unknown type to BSON array field %s",
339  field_name.c_str());
340  break;
341  }
342  }
343 #ifdef HAVE_MONGODB_VERSION_H
344  } catch (mongo::MsgAssertionException &e) {
345 #else
346  } catch (mongo::AssertionException &e) {
347 #endif
348  logger->log_error("MongoDB",
349  "Failed to append array value to field %s: %s",
350  field_name.c_str(),
351  e.what());
352  }
353 }
354 
355 CLIPS::Value
356 ClipsRobotMemoryThread::clips_bson_array_start(void *bson, std::string field_name)
357 {
358  mongo::BSONObjBuilder * b = static_cast<mongo::BSONObjBuilder *>(bson);
359  mongo::BufBuilder & bb = b->subarrayStart(field_name);
360  mongo::BSONArrayBuilder *arrb = new mongo::BSONArrayBuilder(bb);
361  return CLIPS::Value(arrb);
362 }
363 
364 void
365 ClipsRobotMemoryThread::clips_bson_array_finish(void *barr)
366 {
367  mongo::BSONArrayBuilder *ab = static_cast<mongo::BSONArrayBuilder *>(barr);
368  delete ab;
369 }
370 
371 void
372 ClipsRobotMemoryThread::clips_bson_array_append(void *barr, CLIPS::Value value)
373 {
374  try {
375  mongo::BSONArrayBuilder *ab = static_cast<mongo::BSONArrayBuilder *>(barr);
376  switch (value.type()) {
377  case CLIPS::TYPE_FLOAT: ab->append(value.as_float()); break;
378 
379  case CLIPS::TYPE_INTEGER: ab->append(value.as_integer()); break;
380 
381  case CLIPS::TYPE_SYMBOL:
382  case CLIPS::TYPE_STRING:
383  case CLIPS::TYPE_INSTANCE_NAME: ab->append(value.as_string()); break;
384 
385  case CLIPS::TYPE_EXTERNAL_ADDRESS: {
386  mongo::BSONObjBuilder *subb = static_cast<mongo::BSONObjBuilder *>(value.as_address());
387  ab->append(subb->asTempObj());
388  } break;
389 
390  default: logger->log_warn("RefBox", "Tried to add unknown type to BSON array"); break;
391  }
392 #ifdef HAVE_MONGODB_VERSION_H
393  } catch (mongo::MsgAssertionException &e) {
394 #else
395  } catch (mongo::AssertionException &e) {
396 #endif
397  logger->log_error("MongoDB", "Failed to append to array: %s", e.what());
398  }
399 }
400 
401 void
402 ClipsRobotMemoryThread::clips_bson_append_time(void * bson,
403  std::string field_name,
404  CLIPS::Values time)
405 {
406  if (time.size() != 2) {
407  logger->log_warn("MongoDB", "Invalid time, %zu instead of 2 entries", time.size());
408  return;
409  }
410  if (time[0].type() != CLIPS::TYPE_INTEGER || time[1].type() != CLIPS::TYPE_INTEGER) {
411  logger->log_warn("MongoDB", "Invalid time, type mismatch");
412  return;
413  }
414 
415  try {
416  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
417  struct timeval now = {time[0].as_integer(), time[1].as_integer()};
418  mongo::Date_t nowd = now.tv_sec * 1000 + now.tv_usec / 1000;
419  b->appendDate(field_name, nowd);
420 #ifdef HAVE_MONGODB_VERSION_H
421  } catch (mongo::MsgAssertionException &e) {
422 #else
423  } catch (mongo::AssertionException &e) {
424 #endif
425  logger->log_error("MongoDB",
426  "Failed to append time value to field %s: %s",
427  field_name.c_str(),
428  e.what());
429  }
430 }
431 
432 void
433 ClipsRobotMemoryThread::clips_robotmemory_insert(std::string collection, void *bson)
434 {
435  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
436 
437  try {
438  robot_memory->insert(b->asTempObj(), collection);
439  } catch (mongo::DBException &e) {
440  logger->log_warn("MongoDB", "Insert failed: %s", e.what());
441  }
442 }
443 
444 void
445 ClipsRobotMemoryThread::clips_robotmemory_create_index(std::string collection, void *bson)
446 {
447  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
448 
449  try {
450  robot_memory->create_index(b->asTempObj(), collection, /* unique */ false);
451  } catch (mongo::DBException &e) {
452  logger->log_warn("MongoDB", "Creating index failed: %s", e.what());
453  }
454 }
455 
456 void
457 ClipsRobotMemoryThread::clips_robotmemory_create_unique_index(std::string collection, void *bson)
458 {
459  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
460 
461  try {
462  robot_memory->create_index(b->asTempObj(), collection, /* unique */ true);
463  } catch (mongo::DBException &e) {
464  logger->log_warn("MongoDB", "Creating unique index failed: %s", e.what());
465  }
466 }
467 
468 void
469 ClipsRobotMemoryThread::robotmemory_update(std::string & collection,
470  mongo::BSONObj obj,
471  CLIPS::Value & query,
472  bool upsert)
473 {
474  try {
475  mongo::BSONObj query_obj;
476  if (query.type() == CLIPS::TYPE_STRING) {
477  query_obj = mongo::fromjson(query.as_string());
478  } else if (query.type() == CLIPS::TYPE_EXTERNAL_ADDRESS) {
479  mongo::BSONObjBuilder *qb = static_cast<mongo::BSONObjBuilder *>(query.as_address());
480  query_obj = qb->asTempObj();
481  } else {
482  logger->log_warn("MongoDB", "Invalid query, must be string or BSON document");
483  return;
484  }
485 
486  robot_memory->update(query_obj, obj, collection, upsert);
487 #ifdef HAVE_MONGODB_VERSION_H
488  } catch (mongo::MsgAssertionException &e) {
489 #else
490  } catch (mongo::AssertionException &e) {
491 #endif
492  logger->log_warn("MongoDB", "Compiling query failed: %s", e.what());
493  } catch (mongo::DBException &e) {
494  logger->log_warn("MongoDB", "Insert failed: %s", e.what());
495  }
496 }
497 
498 void
499 ClipsRobotMemoryThread::clips_robotmemory_upsert(std::string collection,
500  void * bson,
501  CLIPS::Value query)
502 {
503  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
504  if (!b) {
505  logger->log_warn("MongoDB", "Invalid BSON Obj Builder passed");
506  return;
507  }
508  robotmemory_update(collection, b->asTempObj(), query, true);
509 }
510 
511 void
512 ClipsRobotMemoryThread::clips_robotmemory_update(std::string collection,
513  void * bson,
514  CLIPS::Value query)
515 {
516  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
517  if (!b) {
518  logger->log_warn("MongoDB", "Invalid BSON Obj Builder passed");
519  return;
520  }
521 
522  mongo::BSONObjBuilder update_doc;
523  update_doc.append("$set", b->asTempObj());
524 
525  robotmemory_update(collection, update_doc.obj(), query, false);
526 }
527 
528 void
529 ClipsRobotMemoryThread::clips_robotmemory_replace(std::string collection,
530  void * bson,
531  CLIPS::Value query)
532 {
533  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
534  if (!b)
535  logger->log_warn("MongoDB", "Invalid BSON Obj Builder passed");
536  robotmemory_update(collection, b->asTempObj(), query, false);
537 }
538 
539 CLIPS::Value
540 ClipsRobotMemoryThread::clips_robotmemory_query_sort(std::string collection,
541  void * bson,
542  void * bson_sort)
543 {
544  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
545 
546  try {
547  mongo::Query q(b->asTempObj());
548  if (bson_sort) {
549  mongo::BSONObjBuilder *bs = static_cast<mongo::BSONObjBuilder *>(bson_sort);
550  q.sort(bs->asTempObj());
551  }
552 
553 #if __cplusplus >= 201103L
554  std::unique_ptr<mongo::DBClientCursor> c = robot_memory->query(q, collection);
555 
556  return CLIPS::Value(new std::unique_ptr<mongo::DBClientCursor>(std::move(c)),
557  CLIPS::TYPE_EXTERNAL_ADDRESS);
558 #else
559  std::auto_ptr<mongo::DBClientCursor> c = robot_memory->query(collection, q);
560 
561  return CLIPS::Value(new std::auto_ptr<mongo::DBClientCursor>(c), CLIPS::TYPE_EXTERNAL_ADDRESS);
562 #endif
563 
564  } catch (mongo::DBException &e) {
565  logger->log_warn("MongoDB", "Query failed: %s", e.what());
566  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
567  }
568 }
569 
570 void
571 ClipsRobotMemoryThread::clips_robotmemory_remove(std::string collection, void *bson)
572 {
573  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
574  try {
575  mongo::Query q(b->asTempObj());
576  robot_memory->remove(q, collection);
577  } catch (mongo::DBException &e) {
578  logger->log_warn("MongoDB", "Remove failed: %s", e.what());
579  }
580 }
581 
582 CLIPS::Value
583 ClipsRobotMemoryThread::clips_robotmemory_query(const std::string &collection, void *bson)
584 {
585  return clips_robotmemory_query_sort(collection, bson, NULL);
586 }
587 
588 void
589 ClipsRobotMemoryThread::clips_robotmemory_cursor_destroy(void *cursor)
590 {
591 #if __cplusplus >= 201103L
592  std::unique_ptr<mongo::DBClientCursor> *c =
593  static_cast<std::unique_ptr<mongo::DBClientCursor> *>(cursor);
594 #else
595  std::auto_ptr<mongo::DBClientCursor> *c =
596  static_cast<std::auto_ptr<mongo::DBClientCursor> *>(cursor);
597 #endif
598 
599  if (!c || !c->get()) {
600  logger->log_error("MongoDB", "mongodb-cursor-destroy: got invalid cursor");
601  return;
602  }
603 
604  delete c;
605 }
606 
607 CLIPS::Value
608 ClipsRobotMemoryThread::clips_robotmemory_cursor_more(void *cursor)
609 {
610 #if __cplusplus >= 201103L
611  std::unique_ptr<mongo::DBClientCursor> *c =
612  static_cast<std::unique_ptr<mongo::DBClientCursor> *>(cursor);
613 #else
614  std::auto_ptr<mongo::DBClientCursor> *c =
615  static_cast<std::auto_ptr<mongo::DBClientCursor> *>(cursor);
616 #endif
617 
618  if (!c || !c->get()) {
619  logger->log_error("MongoDB", "mongodb-cursor-more: got invalid cursor");
620  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
621  }
622 
623  return CLIPS::Value((*c)->more() ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
624 }
625 
626 CLIPS::Value
627 ClipsRobotMemoryThread::clips_robotmemory_cursor_next(void *cursor)
628 {
629 #if __cplusplus >= 201103L
630  std::unique_ptr<mongo::DBClientCursor> *c =
631  static_cast<std::unique_ptr<mongo::DBClientCursor> *>(cursor);
632 #else
633  std::auto_ptr<mongo::DBClientCursor> *c =
634  static_cast<std::auto_ptr<mongo::DBClientCursor> *>(cursor);
635 #endif
636 
637  if (!c || !c->get()) {
638  logger->log_error("MongoDB", "mongodb-cursor-next: got invalid cursor");
639  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
640  }
641 
642  mongo::BSONObjBuilder *b = new mongo::BSONObjBuilder();
643  try {
644  b->appendElements((*c)->nextSafe());
645 #ifdef HAVE_MONGODB_VERSION_H
646  } catch (mongo::MsgAssertionException &e) {
647 #else
648  } catch (mongo::AssertionException &e) {
649 #endif
650  logger->log_error("MongoDB",
651  "mongodb-cursor: No more objects in result cursor. What: %s",
652  e.what());
653  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
654  }
655  return CLIPS::Value(b);
656 }
657 
658 CLIPS::Values
659 ClipsRobotMemoryThread::clips_bson_field_names(void *bson)
660 {
661  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
662 
663  if (!b) {
664  logger->log_error("MongoDB", "mongodb-bson-field-names: invalid object");
665  CLIPS::Values rv;
666  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
667  return rv;
668  }
669 
670  std::set<std::string> field_names;
671  b->asTempObj().getFieldNames(field_names);
672 
673  CLIPS::Values rv;
674  for (const std::string &n : field_names) {
675  rv.push_back(CLIPS::Value(n));
676  }
677  return rv;
678 }
679 
680 CLIPS::Value
681 ClipsRobotMemoryThread::clips_bson_get(void *bson, std::string field_name)
682 {
683  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
684 
685  if (!b) {
686  logger->log_error("MongoDB", "mongodb-bson-get: invalid object");
687  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
688  }
689 
690  try {
691  mongo::BSONObj o(b->asTempObj());
692 
693  mongo::BSONElement el = o.getFieldDotted(field_name);
694 
695  switch (el.type()) {
696  case mongo::NumberDouble: return CLIPS::Value(el.Double());
697  case mongo::String: return CLIPS::Value(el.String());
698  case mongo::Bool: return CLIPS::Value(el.Bool() ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
699  case mongo::NumberInt: return CLIPS::Value(el.Int());
700  case mongo::NumberLong: return CLIPS::Value(el.Long());
701  case mongo::Object: {
702  mongo::BSONObjBuilder *b = new mongo::BSONObjBuilder();
703  b->appendElements(el.Obj());
704  return CLIPS::Value(b);
705  }
706  case 7: //ObjectId
707  return CLIPS::Value(el.OID().toString());
708 
709  default: return CLIPS::Value("INVALID_VALUE_TYPE", CLIPS::TYPE_SYMBOL);
710  }
711  } catch (mongo::DBException &e) {
712  logger->log_warn(name(),
713  "mongodb-bson-get: failed to get '%s': %s",
714  field_name.c_str(),
715  e.what());
716  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
717  }
718 }
719 
720 CLIPS::Value
721 ClipsRobotMemoryThread::clips_bson_has_field(void *bson, std::string field_name)
722 {
723  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
724 
725  if (!b) {
726  logger->log_error("MongoDB", "mongodb-bson-get: invalid object");
727  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
728  }
729 
730  mongo::BSONObj o(b->asTempObj());
731 
732  if (o.getFieldDotted(field_name).eoo()) {
733  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
734  } else {
735  return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
736  }
737 }
738 
739 CLIPS::Values
740 ClipsRobotMemoryThread::clips_bson_get_array(void *bson, std::string field_name)
741 {
742  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
743 
744  CLIPS::Values rv;
745 
746  if (!b) {
747  logger->log_error("MongoDB", "mongodb-bson-get-array: invalid object");
748  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
749  return rv;
750  }
751 
752  try {
753  mongo::BSONObj o(b->asTempObj());
754 
755  mongo::BSONElement el = o.getFieldDotted(field_name);
756 
757  if (el.type() != mongo::Array) {
758  logger->log_error("MongoDB",
759  "mongodb-bson-get-array: field %s is not an array",
760  field_name.c_str());
761  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
762  return rv;
763  }
764 
765  std::vector<mongo::BSONElement> elements(el.Array());
766 
767  for (const mongo::BSONElement &e : elements) {
768  switch (e.type()) {
769  case mongo::NumberDouble: rv.push_back(CLIPS::Value(e.Double())); break;
770  case mongo::String: rv.push_back(CLIPS::Value(e.String())); break;
771  case mongo::Bool:
772  rv.push_back(CLIPS::Value(e.Bool() ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL));
773  break;
774  case mongo::NumberInt: rv.push_back(CLIPS::Value(e.Int())); break;
775  case mongo::NumberLong: rv.push_back(CLIPS::Value(e.Long())); break;
776  case mongo::Object: {
777  mongo::BSONObjBuilder *b = new mongo::BSONObjBuilder();
778  b->appendElements(e.Obj());
779  rv.push_back(CLIPS::Value(b));
780  } break;
781  default:
782  rv.clear();
783  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
784  return rv;
785  }
786  }
787  return rv;
788  } catch (mongo::DBException &e) {
789  logger->log_warn(name(),
790  "mongodb-bson-get: failed to get '%s': %s",
791  field_name.c_str(),
792  e.what());
793  rv.clear();
794  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
795  return rv;
796  }
797 }
798 
799 CLIPS::Values
800 ClipsRobotMemoryThread::clips_bson_get_time(void *bson, std::string field_name)
801 {
802  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(bson);
803 
804  CLIPS::Values rv;
805 
806  if (!b) {
807  logger->log_error("MongoDB", "mongodb-bson-get-time: invalid object");
808  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
809  return rv;
810  }
811 
812  try {
813  mongo::BSONObj o(b->asTempObj());
814 
815  mongo::BSONElement el = o.getFieldDotted(field_name);
816 
817  int64_t ts = 0;
818  if (el.type() == mongo::Date) {
819  mongo::Date_t d = el.Date();
820  ts = d.asInt64();
821  } else if (el.type() == mongo::Timestamp) {
822  mongo::Timestamp_t t = el.Timestamp();
823  ts = (int64_t)t.seconds() * 1000;
824  } else {
825  logger->log_error("MongoDB",
826  "mongodb-bson-get-time: field %s is not a time",
827  field_name.c_str());
828  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
829  return rv;
830  }
831 
832  rv.resize(2);
833  rv[0] = CLIPS::Value((long long int)(ts / 1000));
834  rv[1] = CLIPS::Value((ts - (rv[0].as_integer() * 1000)) * 1000);
835  return rv;
836  } catch (mongo::DBException &e) {
837  rv.resize(2, CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
838  return rv;
839  }
840 }
841 
842 CLIPS::Value
843 ClipsRobotMemoryThread::clips_robotmemory_register_trigger(std::string env_name,
844  std::string collection,
845  void * query,
846  std::string assert_name)
847 {
848  mongo::BSONObjBuilder *b = static_cast<mongo::BSONObjBuilder *>(query);
849  try {
850  mongo::Query q(b->asTempObj());
851  ClipsRmTrigger *clips_trigger =
852  new ClipsRmTrigger(assert_name, robot_memory, envs_[env_name], logger);
853  clips_trigger->set_trigger(
854  robot_memory->register_trigger(q, collection, &ClipsRmTrigger::callback, clips_trigger));
855  clips_triggers_.push_back(clips_trigger);
856  return CLIPS::Value(clips_trigger);
857  } catch (mongo::DBException &e) {
858  logger->log_warn("CLIPS RobotMemory", "Trigger query failed: %s", e.what());
859  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
860  }
861 }
862 
863 void
864 ClipsRobotMemoryThread::clips_robotmemory_destroy_trigger(void *trigger)
865 {
866  ClipsRmTrigger *clips_trigger = static_cast<ClipsRmTrigger *>(trigger);
867  clips_triggers_.remove(clips_trigger);
868  delete clips_trigger; //the triger unregisteres itself at the robot memory
869 }
870 
871 CLIPS::Value
872 ClipsRobotMemoryThread::clips_robotmemory_mutex_create(std::string name)
873 {
874  bool rv = robot_memory->mutex_create(name);
875  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
876 }
877 
878 CLIPS::Value
879 ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy(std::string name)
880 {
881  bool rv = robot_memory->mutex_destroy(name);
882  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
883 }
884 
885 CLIPS::Value
886 ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock(std::string name, std::string identity)
887 {
888  bool rv = robot_memory->mutex_try_lock(name, identity);
889  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
890 }
891 
892 CLIPS::Value
893 ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock(std::string name, std::string identity)
894 {
895  bool rv = robot_memory->mutex_renew_lock(name, identity);
896  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
897 }
898 
899 CLIPS::Value
900 ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock(std::string name, std::string identity)
901 {
902  bool rv = robot_memory->mutex_try_lock(name, identity, /* force */ true);
903  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
904 }
905 
906 CLIPS::Value
907 ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock(std::string name, std::string identity)
908 {
909  bool rv = robot_memory->mutex_unlock(name, identity);
910  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
911 }
912 
913 CLIPS::Value
914 ClipsRobotMemoryThread::clips_robotmemory_mutex_setup_ttl(float max_age_sec)
915 {
916  bool rv = robot_memory->mutex_setup_ttl(max_age_sec);
917  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
918 }
919 
920 CLIPS::Value
921 ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks(float max_age_sec)
922 {
923  bool rv = robot_memory->mutex_expire_locks(max_age_sec);
924  return CLIPS::Value(rv ? "TRUE" : "FALSE", CLIPS::TYPE_SYMBOL);
925 }
926 
927 bool
928 ClipsRobotMemoryThread::mutex_future_ready(const std::string &name)
929 {
930  auto mf_it = mutex_futures_.find(name);
931  if (mf_it != mutex_futures_.end()) {
932  auto fut_status = mutex_futures_[name].wait_for(std::chrono::milliseconds(0));
933  if (fut_status != std::future_status::ready) {
934  return false;
935  } else {
936  mutex_futures_.erase(mf_it);
937  }
938  }
939  return true;
940 }
941 
942 CLIPS::Values
943 ClipsRobotMemoryThread::clips_robotmemory_mutex_create_async(std::string name)
944 {
945  CLIPS::Values rv;
946  if (!mutex_future_ready(name)) {
947  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
948  rv.push_back(CLIPS::Value("Task already running for " + name + " (create failed)"));
949  return rv;
950  }
951 
952  auto fut =
953  std::async(std::launch::async, [this, name] { return robot_memory->mutex_create(name); });
954 
955  mutex_futures_[name] = std::move(fut);
956 
957  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
958  return rv;
959 }
960 
961 CLIPS::Values
962 ClipsRobotMemoryThread::clips_robotmemory_mutex_destroy_async(std::string name)
963 {
964  CLIPS::Values rv;
965  if (!mutex_future_ready(name)) {
966  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
967  rv.push_back(CLIPS::Value("Task already running for " + name + " (destroy failed)"));
968  return rv;
969  }
970 
971  auto fut =
972  std::async(std::launch::async, [this, name] { return robot_memory->mutex_destroy(name); });
973 
974  mutex_futures_[name] = std::move(fut);
975 
976  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
977  return rv;
978 }
979 
980 CLIPS::Values
981 ClipsRobotMemoryThread::clips_robotmemory_mutex_try_lock_async(std::string env_name,
982  std::string name,
983  std::string identity)
984 {
985  CLIPS::Values rv;
986  if (!mutex_future_ready(name)) {
987  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
988  rv.push_back(CLIPS::Value("Task already running for " + name + " (try-lock failed)"));
989  envs_[env_name]->assert_fact_f("(mutex-op-feedback try-lock-async FAIL %s)", name.c_str());
990  return rv;
991  }
992 
993  auto fut = std::async(std::launch::async, [this, env_name, name, identity] {
994  bool ok = robot_memory->mutex_try_lock(name, identity);
995  if (!ok) {
996  MutexLocker lock(envs_[env_name].objmutex_ptr());
997  envs_[env_name]->assert_fact_f("(mutex-op-feedback try-lock-async FAIL %s)", name.c_str());
998  }
999  return ok;
1000  });
1001 
1002  mutex_futures_[name] = std::move(fut);
1003 
1004  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1005  return rv;
1006 }
1007 
1008 CLIPS::Values
1009 ClipsRobotMemoryThread::clips_robotmemory_mutex_renew_lock_async(std::string env_name,
1010  std::string name,
1011  std::string identity)
1012 {
1013  CLIPS::Values rv;
1014  if (!mutex_future_ready(name)) {
1015  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
1016  rv.push_back(CLIPS::Value("Task already running for " + name + " (try-lock failed)"));
1017  MutexLocker lock(envs_[env_name].objmutex_ptr());
1018  envs_[env_name]->assert_fact_f("(mutex-op-feedback renew-lock-async FAIL %s)", name.c_str());
1019  return rv;
1020  }
1021 
1022  auto fut = std::async(std::launch::async, [this, env_name, name, identity] {
1023  bool ok = robot_memory->mutex_renew_lock(name, identity);
1024  MutexLocker lock(envs_[env_name].objmutex_ptr());
1025  envs_[env_name]->assert_fact_f("(mutex-op-feedback renew-lock-async %s %s)",
1026  ok ? "OK" : "FAIL",
1027  name.c_str());
1028  return ok;
1029  });
1030 
1031  mutex_futures_[name] = std::move(fut);
1032 
1033  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1034  return rv;
1035 }
1036 
1037 CLIPS::Values
1038 ClipsRobotMemoryThread::clips_robotmemory_mutex_force_lock_async(std::string name,
1039  std::string identity)
1040 {
1041  CLIPS::Values rv;
1042  if (!mutex_future_ready(name)) {
1043  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
1044  rv.push_back(CLIPS::Value("Task already running for " + name + " (force-lock failed)"));
1045  return rv;
1046  }
1047 
1048  auto fut = std::async(std::launch::async, [this, name, identity] {
1049  return robot_memory->mutex_try_lock(name, identity, /* force */ true);
1050  });
1051 
1052  mutex_futures_[name] = std::move(fut);
1053 
1054  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1055  return rv;
1056 }
1057 
1058 CLIPS::Values
1059 ClipsRobotMemoryThread::clips_robotmemory_mutex_unlock_async(std::string name, std::string identity)
1060 {
1061  CLIPS::Values rv;
1062  if (!mutex_future_ready(name)) {
1063  rv.push_back(CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL));
1064  rv.push_back(CLIPS::Value("Task already running for " + name + " (unlock failed)"));
1065  return rv;
1066  }
1067 
1068  auto fut = std::async(std::launch::async, [this, name, identity] {
1069  return robot_memory->mutex_unlock(name, identity);
1070  });
1071 
1072  mutex_futures_[name] = std::move(fut);
1073 
1074  rv.push_back(CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL));
1075  return rv;
1076 }
1077 
1078 CLIPS::Value
1079 ClipsRobotMemoryThread::clips_robotmemory_mutex_expire_locks_async(std::string env_name,
1080  float max_age_sec)
1081 {
1082  CLIPS::Values rv;
1083  if (mutex_expire_future_.valid()) {
1084  // have shared state, expire was or is running
1085  auto fut_status = mutex_expire_future_.wait_for(std::chrono::milliseconds(0));
1086  if (fut_status != std::future_status::ready) {
1087  MutexLocker lock(envs_[env_name].objmutex_ptr());
1088  envs_[env_name]->assert_fact_f("(mutex-op-feedback expire-locks-async FAIL)");
1089  return CLIPS::Value("FALSE", CLIPS::TYPE_SYMBOL);
1090  }
1091  }
1092 
1093  auto fut = std::async(std::launch::async, [this, env_name, max_age_sec] {
1094  bool ok = robot_memory->mutex_expire_locks(max_age_sec);
1095  MutexLocker lock(envs_[env_name].objmutex_ptr());
1096  envs_[env_name]->assert_fact_f("(mutex-op-feedback expire-locks-async %s)", ok ? "OK" : "FAIL");
1097  return ok;
1098  });
1099 
1100  mutex_expire_future_ = std::move(fut);
1101 
1102  return CLIPS::Value("TRUE", CLIPS::TYPE_SYMBOL);
1103 }
Thread aspect to provide a feature to CLIPS environments.
Definition: clips_feature.h:57
QResCursor query(mongo::Query query, const std::string &collection="")
Query information from the robot memory.
virtual void finalize()
Finalize the thread.
bool mutex_unlock(const std::string &name, const std::string &identity)
Release lock on mutex.
int create_index(mongo::BSONObj keys, const std::string &collection="", bool unique=false)
Create an index on a collection.
int remove(mongo::Query query, const std::string &collection="")
Remove documents from the robot memory.
Fawkes library namespace.
int update(mongo::Query query, mongo::BSONObj update, const std::string &collection="", bool upsert=false)
Updates documents in the robot memory.
Mutex locking helper.
Definition: mutex_locker.h:33
virtual void loop()
Code to execute in the thread.
void unlock() const
Unlock object mutex.
Definition: lockptr.h:273
Thread class encapsulation of pthreads.
Definition: thread.h:45
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:41
void callback(mongo::BSONObj update)
Callback function for the trigger.
int insert(mongo::BSONObj obj, const std::string &collection="")
Inserts a document into the robot memory.
bool mutex_try_lock(const std::string &name, bool force=false)
Try to acquire a lock for a mutex.
bool mutex_renew_lock(const std::string &name, const std::string &identity)
Renew a mutex.
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_setup_ttl(float max_age_sec)
Setup time-to-live index for mutexes.
CLIPS feature maintainer.
Definition: clips_feature.h:41
const char * name() const
Get name of thread.
Definition: thread.h:100
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.
RobotMemory * robot_memory
RobotMemory object for storing and querying information.
bool mutex_create(const std::string &name)
Explicitly create a mutex.
EventTrigger * register_trigger(mongo::Query query, const std::string &collection, void(T::*callback)(mongo::BSONObj), T *_obj)
Register a trigger to be notified when the robot memory is updated and the updated document matches t...
Definition: robot_memory.h:117
bool mutex_destroy(const std::string &name)
Destroy a mutex.
virtual void clips_context_destroyed(const std::string &env_name)
Notification that a CLIPS environment has been destroyed.
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
bool mutex_expire_locks(float max_age_sec)
Expire old locks on mutexes.
void lock() const
Lock access to the encapsulated object.
Definition: lockptr.h:257
virtual void init()
Initialize the thread.