diff --git a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp index c1ebb7ba455032cf3d48fa32b40081a6a2fcdb3d..48be5ead78768c516c63004c0fd0bd24494b5f8f 100644 --- a/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp +++ b/source/RobotAPI/components/armem/client/ExampleMemoryClient/ExampleMemoryClient.cpp @@ -136,7 +136,7 @@ namespace armarx queryExampleData(); } - CycleUtil c(100); + CycleUtil c(1000); int i = 0; while (!task->isStopped()) { @@ -379,6 +379,7 @@ namespace armarx { "three", 3 }, }; { + data.the_ivt_image = std::make_shared<CByteImage>(); CByteImage& image = *data.the_ivt_image; image.Set(20, 10, CByteImage::ImageType::eRGB24); simox::ColorMap cmap = simox::color::cmaps::plasma(); diff --git a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp index a868149874e6f4d354c03f1cfc4847fa7fa1024f..3ed4b4612c5dd3f6e0afbd71630dba7a4753f460 100644 --- a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp +++ b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp @@ -61,6 +61,7 @@ namespace armarx void ExampleMemory::onInitComponent() { workingMemory.name() = p.memoryName; + longtermMemory.name() = p.memoryName; // Usually, the memory server will specify a number of core segments with a specific aron type. workingMemory.addCoreSegment("ExampleData", armem::example::ExampleData::toAronType()); diff --git a/source/RobotAPI/components/armem/server/ExampleMemory/aron/ExampleData.xml b/source/RobotAPI/components/armem/server/ExampleMemory/aron/ExampleData.xml index dd0bdb30189442e796b5a778f6855959ad7d5b6f..e2127dedac1fab56502a1d95d535c0454f725a87 100644 --- a/source/RobotAPI/components/armem/server/ExampleMemory/aron/ExampleData.xml +++ b/source/RobotAPI/components/armem/server/ExampleMemory/aron/ExampleData.xml @@ -33,7 +33,7 @@ <EigenMatrix rows="4" cols="4" type="float" /> </ObjectChild> <ObjectChild key='the_ivt_image'> - <IVTCByteImage type="GrayScale" raw_ptr="true"/> + <IVTCByteImage type="GrayScale" shared_ptr="true"/> </ObjectChild> <ObjectChild key='the_float_list'> diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt index eb83670b3cf4633d3fe2ce6bf52e61256a8d7931..5801958db476bb4f7c5c6ae34685fe6db551429b 100644 --- a/source/RobotAPI/libraries/armem/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem/CMakeLists.txt @@ -3,6 +3,15 @@ set(LIB_NAME armem) armarx_component_set_name("${LIB_NAME}") armarx_set_target("Library: ${LIB_NAME}") +find_package(libmongocxx REQUIRED) +find_package(libbsoncxx REQUIRED) + +#message("LIBMONGOCXX:") +#message("${LIBMONGOCXX_FOUND}") +#message("${LIBMONGOCXX_INCLUDE_DIRS}") +#message("${LIBMONGOCXX_LIBRARIES}") + + set(LIBS ArmarXCoreInterfaces ArmarXCore RemoteGui @@ -42,6 +51,8 @@ set(LIB_FILES core/workingmemory/ProviderSegment.cpp core/workingmemory/Visitor.cpp core/workingmemory/ice_conversions.cpp + core/workingmemory/json_conversions.cpp + core/workingmemory/entityInstance_conversions.cpp core/longtermmemory/CoreSegment.cpp core/longtermmemory/Entity.cpp @@ -49,6 +60,7 @@ set(LIB_FILES core/longtermmemory/EntitySnapshot.cpp core/longtermmemory/Memory.cpp core/longtermmemory/ProviderSegment.cpp + core/longtermmemory/mongodb/MongoDBConnectionManager.cpp core/diskmemory/TypeIO.cpp core/diskmemory/CoreSegment.cpp @@ -136,6 +148,8 @@ set(LIB_HEADERS core/workingmemory/ProviderSegment.h core/workingmemory/Visitor.h core/workingmemory/ice_conversions.h + core/workingmemory/json_conversions.h + core/workingmemory/entityInstance_conversions.h core/longtermmemory/CoreSegment.h core/longtermmemory/Entity.h @@ -217,6 +231,8 @@ armarx_enable_aron_file_generation_for_target( add_library(RobotAPI::armem ALIAS "${LIB_NAME}") +target_include_directories("${LIB_NAME}" PUBLIC ${LIBMONGOCXX_INCLUDE_DIRS}) +target_include_directories("${LIB_NAME}" PUBLIC ${LIBBSONCXX_INCLUDE_DIRS}) # add unit tests add_subdirectory(test) diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.cpp b/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.cpp index 49bfe419d8a8cf1052fad7e47a0ecba9e355c529..dac6b538299c93fe954a9678ccc20df1f18629bf 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.cpp +++ b/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.cpp @@ -6,10 +6,6 @@ #include "../../core/error.h" #include <ArmarXCore/core/exceptions/local/ExpressionException.h> -#include <RobotAPI/libraries/aron/core/io/dataIO/converter/Converter.h> -#include <RobotAPI/libraries/aron/core/io/dataIO/visitor/Visitor.h> -#include <RobotAPI/libraries/aron/core/io/dataIO/reader/nlohmannJSON/NlohmannJSONReader.h> -#include <RobotAPI/libraries/aron/core/io/dataIO/writer/nlohmannJSON/NlohmannJSONWriter.h> namespace armarx::armem::d_ltm { @@ -69,13 +65,13 @@ namespace armarx::armem::d_ltm { std::ifstream ifs(d); std::string file_content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>())); - aron::dataIO::reader::NlohmannJSONReader dataReader(file_content); - aron::dataIO::writer::NavigatorWriter navWriter; - aron::dataIO::Converter::ReadAndConvert(dataReader, navWriter, expectedStructure); - - aron::datanavigator::DictNavigatorPtr aron = aron::datanavigator::DictNavigator::DynamicCastAndCheck(navWriter.getResult()); - return unwrapData(aron); + nlohmann::json j(file_content); + auto aron = std::make_shared<aron::datanavigator::DictNavigator>(); + to_aron(aron, j, expectedStructure); + wm::EntityInstance e(id()); + from_aron(aron, e); + return e; } else { @@ -115,71 +111,12 @@ namespace armarx::armem::d_ltm std::ofstream ofs; ofs.open(d); - aron::datanavigator::DictNavigatorPtr aron = wrapData(m); - aron::dataIO::writer::NlohmannJSONWriter dataWriter; - aron::dataIO::Visitor::VisitAndSetup(dataWriter, aron); - std::string new_file_full_content = dataWriter.getResult().dump(2); + auto aron = std::make_shared<aron::datanavigator::DictNavigator>(); + to_aron(aron, m); + nlohmann::json j; + from_aron(aron, j); - ofs << new_file_full_content; + ofs << j.dump(2); ofs.close(); } - - - wm::EntityInstance EntityInstance::unwrapData(const aron::datanavigator::DictNavigatorPtr& dataWrapped) const - { - wm::EntityInstance e(id()); - wm::EntityInstanceMetadata& metadata = e.metadata(); - - if (dataWrapped->hasElement(DATA_WRAPPER_DATA_FIELD)) - { - aron::datanavigator::DictNavigatorPtr data = aron::datanavigator::DictNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_DATA_FIELD)); - e.setData(data); - } - - auto timeCreated = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_CREATED_FIELD)); - metadata.timeCreated = Time::microSeconds(timeCreated->toAronLongPtr()->value); - - auto timeSent = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_SENT_FIELD)); - metadata.timeSent = Time::microSeconds(timeSent->toAronLongPtr()->value); - - auto timeArrived = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_ARRIVED_FIELD)); - metadata.timeArrived = Time::microSeconds(timeArrived->toAronLongPtr()->value); - - auto confidence = aron::datanavigator::DoubleNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_CONFIDENCE_FIELD)); - metadata.confidence = static_cast<float>(confidence->toAronDoublePtr()->value); - - return e; - } - - aron::datanavigator::DictNavigatorPtr EntityInstance::wrapData(const wm::EntityInstance& e) const - { - auto dataWrapped = std::make_shared<aron::datanavigator::DictNavigator>(); - if (e.data()) - { - dataWrapped->addElement(DATA_WRAPPER_DATA_FIELD, e.data()); - } - - auto timeWrapped = std::make_shared<aron::datanavigator::LongNavigator>(); - timeWrapped->setValue(Time::now().toMicroSeconds()); - dataWrapped->addElement(DATA_WRAPPER_TIME_STORED_FIELD, timeWrapped); - - const wm::EntityInstanceMetadata& metadata = e.metadata(); - auto timeCreated = std::make_shared<aron::datanavigator::LongNavigator>(); - timeCreated->setValue(metadata.timeCreated.toMicroSeconds()); - dataWrapped->addElement(DATA_WRAPPER_TIME_CREATED_FIELD, timeCreated); - - auto timeSent = std::make_shared<aron::datanavigator::LongNavigator>(); - timeSent->setValue(metadata.timeSent.toMicroSeconds()); - dataWrapped->addElement(DATA_WRAPPER_TIME_SENT_FIELD, timeSent); - - auto timeArrived = std::make_shared<aron::datanavigator::LongNavigator>(); - timeArrived->setValue(metadata.timeArrived.toMicroSeconds()); - dataWrapped->addElement(DATA_WRAPPER_TIME_ARRIVED_FIELD, timeArrived); - - auto confidence = std::make_shared<aron::datanavigator::DoubleNavigator>(); - confidence->setValue(static_cast<double>(metadata.confidence)); - dataWrapped->addElement(DATA_WRAPPER_CONFIDENCE_FIELD, confidence); - - return dataWrapped; - } } diff --git a/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.h b/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.h index 9ee48c55b33dca02c88f57de1ac30426f8d5ae37..89b96c011fcccb6bfc5471850185b0cea49f77b0 100644 --- a/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.h +++ b/source/RobotAPI/libraries/armem/core/diskmemory/EntityInstance.h @@ -5,6 +5,9 @@ #include "../base/EntityInstanceBase.h" #include "../workingmemory/EntityInstance.h" +#include "../workingmemory/entityInstance_conversions.h" +#include "../workingmemory/json_conversions.h" + namespace armarx::armem::d_ltm { @@ -51,19 +54,10 @@ namespace armarx::armem::d_ltm std::filesystem::path _fullPath() const; std::filesystem::path _fullPath(const std::filesystem::path&) const; - wm::EntityInstance unwrapData(const aron::datanavigator::DictNavigatorPtr&) const; - aron::datanavigator::DictNavigatorPtr wrapData(const wm::EntityInstance&) const; - public: std::shared_ptr<std::filesystem::path> path; private: static const constexpr char* DATA_FILENAME = "data"; - static constexpr const char* DATA_WRAPPER_DATA_FIELD = "__ARON_DATA"; - static constexpr const char* DATA_WRAPPER_TIME_STORED_FIELD = "__WRITER_METADATA__TIME_STORED"; - static constexpr const char* DATA_WRAPPER_TIME_CREATED_FIELD = "__ENTITY_METADATA__TIME_CREATED"; - static constexpr const char* DATA_WRAPPER_TIME_SENT_FIELD = "__ENTITY_METADATA__TIME_SENT"; - static constexpr const char* DATA_WRAPPER_TIME_ARRIVED_FIELD = "__ENTITY_METADATA__TIME_ARRIVED"; - static constexpr const char* DATA_WRAPPER_CONFIDENCE_FIELD = "__ENTITY_METADATA__CONFIDENCE"; }; } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.cpp index 78f275fe1a8b1285b852431acaa67dc13963874d..a99518db24ed00819be69f8085670272281daf58 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.cpp @@ -8,28 +8,73 @@ namespace armarx::armem::ltm { - wm::CoreSegment CoreSegment::convert() const + wm::CoreSegment CoreSegment::convert(const MongoDBConnectionManager::MongoDBSettings& dbsettings) const { - wm::CoreSegment m; + wm::CoreSegment m(id()); for (const auto& [_, s] : _container) { - m.addProviderSegment(s.convert()); + m.addProviderSegment(s.convert(dbsettings)); } return m; } - void CoreSegment::append(const wm::CoreSegment& m) + void CoreSegment::reload(const MongoDBConnectionManager::MongoDBSettings& dbsettings) { + _container.clear(); + + mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); + mongocxx::database db = client[dbsettings.database]; + mongocxx::collection coll = db[MONGO_DB_COLLECTION_PREFIX + id().coreSegmentName]; + + + mongocxx::cursor cursor = coll.find({}); + for (auto doc : cursor) + { + nlohmann::json json = nlohmann::json::parse(bsoncxx::to_json(doc)); + ARMARX_INFO << "CoreSegment: Found foreign key: " << json.at("foreign_key"); + + MemoryID i((std::string) json.at("foreign_key")); + if (i.coreSegmentName != id().coreSegmentName) + { + throw error::InvalidMemoryID(i, "A MemoryID in mongodb was invalid. Found the wrong coreSegment name. Expected " + id().coreSegmentName); + } + + std::string k = i.providerSegmentName; + + if (const auto& it = _container.find(k); it != _container.end()) + { + throw error::ArMemError("Somehow after clearing the container a key k = " + k + " was found. Do you have double entries in mongodb?"); + } + else + { + auto wms = _container.emplace(std::make_pair(k, id().withProviderSegmentName(k))); + wms.first->second.reload(dbsettings); + } + } + } + + void CoreSegment::append(const wm::CoreSegment& m, const MongoDBConnectionManager::MongoDBSettings& dbsettings) + { + mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); + mongocxx::database db = client[dbsettings.database]; + mongocxx::collection coll = db[MONGO_DB_COLLECTION_PREFIX + id().coreSegmentName]; + for (const auto& [k, s] : m.container()) { if (const auto& it = _container.find(k); it != _container.end()) { - it->second.append(s); + it->second.append(s, dbsettings); } else { - auto wms = _container.emplace(std::make_pair(k, id().withCoreSegmentName(k))); - wms.first->second.append(s); + auto builder = bsoncxx::builder::stream::document{}; + bsoncxx::document::value foreign_key = builder + << "foreign_key" << s.id().withProviderSegmentName(k).str() + << bsoncxx::builder::stream::finalize; + coll.insert_one(foreign_key.view()); + + auto wms = _container.emplace(std::make_pair(k, id().withProviderSegmentName(k))); + wms.first->second.append(s, dbsettings); } } } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.h b/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.h index 67f9da6f465820534a4214cbb423e14916819daf..1bbcd26b7a056907498c8b78607f1d77ebc0f5a4 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.h +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/CoreSegment.h @@ -25,10 +25,14 @@ namespace armarx::armem::ltm // Conversion - wm::CoreSegment convert() const; + wm::CoreSegment convert(const MongoDBConnectionManager::MongoDBSettings&) const; // MongoDB connection - void append(const wm::CoreSegment&); + void reload(const MongoDBConnectionManager::MongoDBSettings&); + void append(const wm::CoreSegment&, const MongoDBConnectionManager::MongoDBSettings&); + + private: + static const constexpr char* MONGO_DB_COLLECTION_PREFIX = "CoreSegment__"; }; } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.cpp index 15e232c01fb0edb2ce6e0bffec0f2f0b2c0a3110..00dbd2ae85c2d8fac7ab2ff73131c17da41eb7fe 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.cpp @@ -3,28 +3,63 @@ namespace armarx::armem::ltm { - wm::Entity Entity::convert() const + wm::Entity Entity::convert(const MongoDBConnectionManager::MongoDBSettings& dbsettings) const { - wm::Entity m; + wm::Entity m(id()); for (const auto& [_, s] : _container) { - m.addSnapshot(s.convert()); + m.addSnapshot(s.convert(dbsettings)); } return m; } - void Entity::append(const wm::Entity& m) + void Entity::reload(const MongoDBConnectionManager::MongoDBSettings& dbsettings) { + _container.clear(); + + ARMARX_INFO << "Reloading entity: " << id().entityName; + + mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); + mongocxx::database db = client[dbsettings.database]; + mongocxx::collection coll = db[MONGO_DB_COLLECTION_PREFIX + id().entityName]; + + mongocxx::cursor cursor = coll.find({}); + for (auto doc : cursor) + { + nlohmann::json json = nlohmann::json::parse(bsoncxx::to_json(doc)); + + auto k = armem::Time::microSeconds(json.at("timestamp")); + ARMARX_INFO << "Entity: Found timestamp: " << std::to_string(k.toMicroSeconds()); + + if (const auto& it = _container.find(k); it != _container.end()) + { + throw error::ArMemError("Somehow after clearing the container a key k = " + std::to_string(k.toMicroSeconds()) + " was found. Do you have double entries in mongodb?"); + } + else + { + auto wms = _container.emplace(std::make_pair(k, id().withTimestamp(k))); + wms.first->second.reload(dbsettings); + } + } + } + + void Entity::append(const wm::Entity& m, const MongoDBConnectionManager::MongoDBSettings& dbsettings) + { + mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); + mongocxx::database db = client[dbsettings.database]; + mongocxx::collection coll = db[MONGO_DB_COLLECTION_PREFIX + id().entityName]; + coll.drop(); + for (const auto& [k, s] : m.container()) { if (const auto& it = _container.find(k); it != _container.end()) { - it->second.setTo(s); + it->second.setTo(s, k, dbsettings); } else { auto wms = _container.emplace(std::make_pair(k, id().withTimestamp(k))); - wms.first->second.setTo(s); + wms.first->second.setTo(s, k, dbsettings); } } } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.h b/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.h index ecdf297c13fae4d24b070f2af13fd6c84ed93392..0dfe62f51c92011cf8587c0bdb06655948b3c378 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.h +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/Entity.h @@ -40,10 +40,14 @@ namespace armarx::armem::ltm // Conversion - wm::Entity convert() const; + wm::Entity convert(const MongoDBConnectionManager::MongoDBSettings&) const; // MongoDB connection - void append(const wm::Entity&); + void reload(const MongoDBConnectionManager::MongoDBSettings&); + void append(const wm::Entity&, const MongoDBConnectionManager::MongoDBSettings&); + + private: + static const constexpr char* MONGO_DB_COLLECTION_PREFIX = "Entity__"; }; } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.cpp index 6332be7ea52f3c547101ae3ee196a524a36aab17..5e44714904efe74f920b891b665e13497b749508 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.cpp @@ -1,5 +1,7 @@ #include "EntityInstance.h" +#include "../../core/error.h" + #include <ArmarXCore/core/exceptions/local/ExpressionException.h> namespace armarx::armem::ltm @@ -42,15 +44,4 @@ namespace armarx::armem::ltm Base::_copySelf(other); other._metadata = _metadata; } - - wm::EntityInstance EntityInstance::convert() const - { - wm::EntityInstance m; - return m; - } - - void EntityInstance::setTo(const wm::EntityInstance& m) - { - ARMARX_IMPORTANT << "Longtermmemory received an entity instance: " << m.id().str(); - } } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.h b/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.h index f78668e5e1a4e1506c2b63c8d2721126e293d6c9..e95ae277e83b2a927172ad1e663c42a700fef849 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.h +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/EntityInstance.h @@ -3,6 +3,10 @@ #include "../base/EntityInstanceBase.h" #include "../workingmemory/EntityInstance.h" +#include "mongodb/MongoDBConnectionManager.h" + +#include "../workingmemory/entityInstance_conversions.h" +#include "../workingmemory/json_conversions.h" namespace armarx::armem::ltm { @@ -69,12 +73,6 @@ namespace armarx::armem::ltm virtual EntityInstance copy() const override; - // Conversion - wm::EntityInstance convert() const; - - // MongoDB connection - void setTo(const wm::EntityInstance&); - protected: virtual void _copySelf(EntityInstance& other) const override; diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.cpp index 73d4932155562ffe213504ce3b7bccfc93690b51..412dbe1c41603f80960f9087c2a6277274f67c89 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.cpp @@ -2,32 +2,103 @@ #include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include "../workingmemory/entityInstance_conversions.h" +#include "../workingmemory/json_conversions.h" + #include "error.h" namespace armarx::armem::ltm { - wm::EntitySnapshot EntitySnapshot::convert() const + wm::EntitySnapshot EntitySnapshot::convert(const MongoDBConnectionManager::MongoDBSettings& dbsettings, const aron::typenavigator::NavigatorPtr& expectedStructure) const { - wm::EntitySnapshot m; - for (const auto& s : _container) + mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); + mongocxx::database db = client[dbsettings.database]; + mongocxx::collection coll = db[MONGO_DB_COLLECTION_PREFIX + id().coreSegmentName]; + + auto res = coll.find_one(document{} << "id" << id().getEntitySnapshotID().str() << finalize); + + if (!res) + { + throw error::ArMemError("Could not load an instance from the memory. Tried to access: " + id().getEntitySnapshotID().str()); + } + + nlohmann::json json = bsoncxx::to_json(*res); + nlohmann::json instances = json["instances"]; + + if (instances.size() != _container.size()) { - m.addInstance(s.convert()); + throw error::ArMemError("The size of the mongodb entity entry at id " + id().getEntitySnapshotID().str() + " has wrong size. Expected: " + std::to_string(_container.size()) + " but got: " + std::to_string(instances.size())); + } + + wm::EntitySnapshot m(id()); + for (unsigned int i = 0; i < _container.size(); ++i) + { + nlohmann::json doc = instances[i++]; + + auto aron = std::make_shared<aron::datanavigator::DictNavigator>(); + to_aron(aron, doc, expectedStructure); + wm::EntityInstance e(id()); + from_aron(aron, e); + m.addInstance(e); } return m; } - void EntitySnapshot::setTo(const wm::EntitySnapshot& m) + void EntitySnapshot::reload(const MongoDBConnectionManager::MongoDBSettings& dbsettings) + { + _container.clear(); + + mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); + mongocxx::database db = client[dbsettings.database]; + mongocxx::collection coll = db[MONGO_DB_COLLECTION_PREFIX + id().coreSegmentName]; + + mongocxx::cursor cursor = coll.find({}); + for (auto doc : cursor) + { + nlohmann::json json = nlohmann::json::parse(bsoncxx::to_json(doc)); + for (unsigned int i = 0; i < json.at("instances").size(); ++i) + { + auto wms = _container.emplace_back(id().withInstanceIndex(i)); + } + + ARMARX_INFO << "Entity: Found instances: " << json.at("instances").size(); + } + } + + void EntitySnapshot::setTo(const wm::EntitySnapshot& m, const armem::Time& t, const MongoDBConnectionManager::MongoDBSettings& dbsettings) { // We remove the contente here and reset it with new values _container.clear(); + mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); + mongocxx::database db = client[dbsettings.database]; + mongocxx::collection coll = db[MONGO_DB_COLLECTION_PREFIX + id().entityName]; + + bsoncxx::builder::stream::document builder{}; + auto in_array = builder + << "id" << id().getEntitySnapshotID().str() + << "timestamp" << t.toMicroSeconds() + << "instances" << bsoncxx::builder::stream::open_array; + auto array_builder = bsoncxx::builder::basic::array{}; + int i = 0; for (const auto& s : m.container()) { auto wms = _container.emplace_back(id().withInstanceIndex(i++)); - wms.setTo(s); + + auto aron = std::make_shared<aron::datanavigator::DictNavigator>(); + to_aron(aron, s); + nlohmann::json j; + from_aron(aron, j); + + auto doc_value = bsoncxx::from_json(j.dump(2)); + array_builder.append(doc_value); } + + auto after_array = in_array << array_builder << bsoncxx::builder::stream::close_array; + bsoncxx::document::value doc = after_array << bsoncxx::builder::stream::finalize; + coll.insert_one(doc.view()); } } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.h b/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.h index 79c0341643c4619270e6b264454ce50dffd0a202..b81f0f8e1140eaaa6d0e916ac38d86655ab86140 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.h +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/EntitySnapshot.h @@ -25,9 +25,13 @@ namespace armarx::armem::ltm // Conversion - wm::EntitySnapshot convert() const; + wm::EntitySnapshot convert(const MongoDBConnectionManager::MongoDBSettings&, const aron::typenavigator::NavigatorPtr& = nullptr) const; // MongoDB connection - void setTo(const wm::EntitySnapshot&); + void reload(const MongoDBConnectionManager::MongoDBSettings&); + void setTo(const wm::EntitySnapshot&, const armem::Time& t, const MongoDBConnectionManager::MongoDBSettings&); + + private: + static const constexpr char* MONGO_DB_COLLECTION_PREFIX = "Entity__"; }; } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.cpp index ac204816011ee0b760fa65a9fecea330edcadf97..4079ebde68babd7d77fc01c1bea827c99e2d11a5 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.cpp @@ -1,5 +1,6 @@ #include "Memory.h" +#include <ArmarXCore/core/time/TimeUtil.h> #include <ArmarXCore/core/logging/Logging.h> #include <ArmarXCore/core/exceptions/local/ExpressionException.h> @@ -11,33 +12,79 @@ namespace armarx::armem::ltm wm::Memory Memory::convert() const { - wm::Memory m; + wm::Memory m(id()); for (const auto& [_, s] : _container) { - m.addCoreSegment(s.convert()); + m.addCoreSegment(s.convert(dbsettings)); } return m; } - void Memory::reload(const MongoDBConnectionManager::MongoDBSettings& settings) + void Memory::reload() { - dbsettings = settings; - std::cout << "Setting connection to: " << settings.uniqueString() << std::endl; + ARMARX_INFO << "(Re)Establishing connection to: " << dbsettings.toString(); + _container.clear(); + + mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); + mongocxx::database db = client[dbsettings.database]; + mongocxx::collection coll = db[MONGO_DB_COLLECTION_PREFIX + id().memoryName]; + + mongocxx::cursor cursor = coll.find({}); + for (auto doc : cursor) + { + nlohmann::json json = nlohmann::json::parse(bsoncxx::to_json(doc)); + ARMARX_INFO << "Memory: Found foreign key: " << json.at("foreign_key"); + + MemoryID i((std::string) json.at("foreign_key")); + if (i.memoryName != id().memoryName) + { + throw error::InvalidMemoryID(i, "A MemoryID in mongodb was invalid. Found the wrong memory name. Expected " + id().memoryName); + } + + std::string k = i.coreSegmentName; + + if (const auto& it = _container.find(k); it != _container.end()) + { + throw error::ArMemError("Somehow after clearing the container a key k = " + k + " was found. Do you have double entries in mongodb?"); + } + else + { + auto wms = _container.emplace(std::make_pair(k, id().withCoreSegmentName(k))); + wms.first->second.reload(dbsettings); + } + } } void Memory::append(const wm::Memory& m) { + ARMARX_INFO << "Appending Memory with name: " << m.name(); + + TIMING_START(LTM_Append); + + mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); + mongocxx::database db = client[dbsettings.database]; + mongocxx::collection coll = db[MONGO_DB_COLLECTION_PREFIX + id().memoryName]; + for (const auto& [k, s] : m.container()) { if (const auto& it = _container.find(k); it != _container.end()) { - it->second.append(s); + // TODO check if foreign key exists + it->second.append(s, dbsettings); } else { + auto builder = bsoncxx::builder::stream::document{}; + bsoncxx::document::value foreign_key = builder + << "foreign_key" << s.id().withCoreSegmentName(k).str() + << bsoncxx::builder::stream::finalize; + coll.insert_one(foreign_key.view()); + auto wms = _container.emplace(std::make_pair(k, id().withCoreSegmentName(k))); - wms.first->second.append(s); + wms.first->second.append(s, dbsettings); } } + + TIMING_END(LTM_Append); } } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.h b/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.h index a381972a8c6670f10f286b5ecee82757c1be87d1..9caa6b795732dc9b0ab82254027519c5e014ae71 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.h +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/Memory.h @@ -5,7 +5,6 @@ #include "CoreSegment.h" #include "../workingmemory/Memory.h" -#include "mongodb/MongoDBConnectionManager.h" namespace armarx::armem::ltm { @@ -22,16 +21,45 @@ namespace armarx::armem::ltm using Base::MemoryBase; using Base::operator=; + enum class PeriodicTransferMode + { + MANUAL, + TRANSFER_PERIODIC_KEEP, + TRANSFER_PERIODIC_DELETE, + }; + + enum class FilledTransferMode + { + TRANSFER_LATEST, + TRANSFER_LEAST_USED + }; + + struct PeriodicTransfer + { + PeriodicTransferMode mode = PeriodicTransferMode::MANUAL; + }; + + struct FilledTransfer + { + FilledTransferMode mode = FilledTransferMode::TRANSFER_LATEST; + }; + // Conversion wm::Memory convert() const; // MongoDB connection - void reload(const MongoDBConnectionManager::MongoDBSettings&); + void reload(); void append(const wm::Memory&); public: MongoDBConnectionManager::MongoDBSettings dbsettings; + + PeriodicTransfer periodic_transfer; + FilledTransferMode filled_transfer; + + private: + static const constexpr char* MONGO_DB_COLLECTION_PREFIX = "Memory__"; }; } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.cpp index 38f2a142989324cab5aa9a47f2f80d7e91fa9b24..d8ca92c97755c4f26f1553d5b98479cb87b19d00 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.cpp +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.cpp @@ -8,28 +8,72 @@ namespace armarx::armem::ltm { - wm::ProviderSegment ProviderSegment::convert() const + wm::ProviderSegment ProviderSegment::convert(const MongoDBConnectionManager::MongoDBSettings& dbsettings) const { - wm::ProviderSegment m; + wm::ProviderSegment m(id()); for (const auto& [_, s] : _container) { - m.addEntity(s.convert()); + m.addEntity(s.convert(dbsettings)); } return m; } - void ProviderSegment::append(const wm::ProviderSegment& m) + void ProviderSegment::reload(const MongoDBConnectionManager::MongoDBSettings& dbsettings) { + _container.clear(); + + mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); + mongocxx::database db = client[dbsettings.database]; + mongocxx::collection coll = db[MONGO_DB_COLLECTION_PREFIX + id().providerSegmentName]; + + mongocxx::cursor cursor = coll.find({}); + for (auto doc : cursor) + { + nlohmann::json json = nlohmann::json::parse(bsoncxx::to_json(doc)); + ARMARX_INFO << "ProviderSegment: Found foreign key: " << json.at("foreign_key"); + + MemoryID i((std::string) json.at("foreign_key")); + if (i.providerSegmentName != id().providerSegmentName) + { + throw error::InvalidMemoryID(i, "A MemoryID in mongodb was invalid. Found the wrong providerSegment name. Expected " + id().providerSegmentName); + } + + std::string k = i.entityName; + + if (const auto& it = _container.find(k); it != _container.end()) + { + throw error::ArMemError("Somehow after clearing the container a key k = " + k + " was found. Do you have double entries in mongodb?"); + } + else + { + auto wms = _container.emplace(std::make_pair(k, id().withEntityName(k))); + wms.first->second.reload(dbsettings); + } + } + } + + void ProviderSegment::append(const wm::ProviderSegment& m, const MongoDBConnectionManager::MongoDBSettings& dbsettings) + { + mongocxx::client& client = MongoDBConnectionManager::EstablishConnection(dbsettings); + mongocxx::database db = client[dbsettings.database]; + mongocxx::collection coll = db[MONGO_DB_COLLECTION_PREFIX + id().providerSegmentName]; + for (const auto& [k, s] : m.container()) { if (const auto& it = _container.find(k); it != _container.end()) { - it->second.append(s); + it->second.append(s, dbsettings); } else { + auto builder = bsoncxx::builder::stream::document{}; + bsoncxx::document::value foreign_key = builder + << "foreign_key" << s.id().withEntityName(k).str() + << bsoncxx::builder::stream::finalize; + coll.insert_one(foreign_key.view()); + auto wms = _container.emplace(std::make_pair(k, id().withEntityName(k))); - wms.first->second.append(s); + wms.first->second.append(s, dbsettings); } } } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.h b/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.h index 4e81db8a9270f58d44845d08f298b37d59424323..3c19ec5816ceb2c629a252e45d0b25d14cb8219e 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.h +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/ProviderSegment.h @@ -25,10 +25,14 @@ namespace armarx::armem::ltm // Conversion - wm::ProviderSegment convert() const; + wm::ProviderSegment convert(const MongoDBConnectionManager::MongoDBSettings&) const; // MongoDB connection - void append(const wm::ProviderSegment&); + void reload(const MongoDBConnectionManager::MongoDBSettings&); + void append(const wm::ProviderSegment&, const MongoDBConnectionManager::MongoDBSettings&); + + private: + static const constexpr char* MONGO_DB_COLLECTION_PREFIX = "ProviderSegment__"; }; } diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/mongodb/MongoDBConnectionManager.cpp b/source/RobotAPI/libraries/armem/core/longtermmemory/mongodb/MongoDBConnectionManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d35c7640cff283349e592dfc3e6d7e616e27516c --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/mongodb/MongoDBConnectionManager.cpp @@ -0,0 +1,30 @@ +#include "MongoDBConnectionManager.h" + +namespace armarx::armem::ltm +{ + bool MongoDBConnectionManager::initialized = false; + std::map<std::string, mongocxx::client> MongoDBConnectionManager::Connections = {}; + + mongocxx::client& MongoDBConnectionManager::EstablishConnection(const MongoDBSettings& settings) + { + if (!initialized) + { + initialized = true; + mongocxx::instance instance{}; // This should be done only once. + } + + const auto uri_str = settings.uri(); + const auto& it = Connections.find(uri_str); + if (it == Connections.end()) + { + mongocxx::uri uri(uri_str); + auto con = Connections.emplace(uri_str, mongocxx::client(uri)); + return con.first->second; + } + else + { + // A connection already exists. We do not need to open another one. + return it->second; + } + } +} diff --git a/source/RobotAPI/libraries/armem/core/longtermmemory/mongodb/MongoDBConnectionManager.h b/source/RobotAPI/libraries/armem/core/longtermmemory/mongodb/MongoDBConnectionManager.h index 02c25965f9c6ae0c12f528c9e2a5c241a10a26d3..0c04151ccd175c410cabc132e45535d624646c2e 100644 --- a/source/RobotAPI/libraries/armem/core/longtermmemory/mongodb/MongoDBConnectionManager.h +++ b/source/RobotAPI/libraries/armem/core/longtermmemory/mongodb/MongoDBConnectionManager.h @@ -5,9 +5,27 @@ #include <map> #include <memory> +#include <bsoncxx/json.hpp> +#include <mongocxx/client.hpp> +#include <mongocxx/stdx.hpp> +#include <mongocxx/uri.hpp> +#include <mongocxx/instance.hpp> +#include <bsoncxx/builder/stream/helpers.hpp> +#include <bsoncxx/builder/stream/document.hpp> +#include <bsoncxx/builder/stream/array.hpp> + + namespace armarx::armem::ltm { + using bsoncxx::builder::stream::close_array; + using bsoncxx::builder::stream::close_document; + using bsoncxx::builder::stream::document; + using bsoncxx::builder::stream::finalize; + using bsoncxx::builder::stream::open_array; + using bsoncxx::builder::stream::open_document; + + /** * @brief Data of a memory consisting of multiple core segments. */ @@ -17,38 +35,35 @@ namespace armarx::armem::ltm struct MongoDBSettings { std::string host = "localhost"; - std::string user = "root"; + unsigned int port = 27017; + std::string user = ""; std::string password = ""; + std::string database = "Test"; + bool isSet() const { // we always need a user and a host - return !host.empty() and !user.empty(); + return !host.empty() and port != 0 and !user.empty(); } - std::string uniqueString() const + std::string uri() const { - return host + "::" + user; + return "mongodb://" + host + ":" + std::to_string(port) + user; } - }; - static int EstablishConnection(const MongoDBSettings& settings) - { - const auto str_rep = settings.uniqueString(); - const auto& it = Connections.find(str_rep); - if (it == Connections.end()) + std::string toString() const { - auto con = Connections.emplace(str_rep, 0); - return con.first->second; + return uri() + ":" + password + "/" + database; } - else - { - // A connection already exists. We do not need to open another one. - return it->second; - } - } + }; + + static mongocxx::client& EstablishConnection(const MongoDBSettings& settings); + private: - static std::map<std::string, int> Connections; + static bool initialized; + static std::map<std::string, mongocxx::client> Connections; + }; } diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/entityInstance_conversions.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/entityInstance_conversions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31538f8d8e2f1eeaf932ed16e50b7040520f0a99 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/workingmemory/entityInstance_conversions.cpp @@ -0,0 +1,64 @@ +#include "json_conversions.h" + +namespace armarx::armem +{ + + constexpr const char* DATA_WRAPPER_DATA_FIELD = "__ARON_DATA"; + constexpr const char* DATA_WRAPPER_TIME_STORED_FIELD = "__WRITER_METADATA__TIME_STORED"; + constexpr const char* DATA_WRAPPER_TIME_CREATED_FIELD = "__ENTITY_METADATA__TIME_CREATED"; + constexpr const char* DATA_WRAPPER_TIME_SENT_FIELD = "__ENTITY_METADATA__TIME_SENT"; + constexpr const char* DATA_WRAPPER_TIME_ARRIVED_FIELD = "__ENTITY_METADATA__TIME_ARRIVED"; + constexpr const char* DATA_WRAPPER_CONFIDENCE_FIELD = "__ENTITY_METADATA__CONFIDENCE"; + + void from_aron(const aron::datanavigator::DictNavigatorPtr& dataWrapped, wm::EntityInstance& e) + { + wm::EntityInstanceMetadata& metadata = e.metadata(); + + if (dataWrapped->hasElement(DATA_WRAPPER_DATA_FIELD)) + { + aron::datanavigator::DictNavigatorPtr data = aron::datanavigator::DictNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_DATA_FIELD)); + e.setData(data); + } + + auto timeCreated = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_CREATED_FIELD)); + metadata.timeCreated = Time::microSeconds(timeCreated->toAronLongPtr()->value); + + auto timeSent = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_SENT_FIELD)); + metadata.timeSent = Time::microSeconds(timeSent->toAronLongPtr()->value); + + auto timeArrived = aron::datanavigator::LongNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_TIME_ARRIVED_FIELD)); + metadata.timeArrived = Time::microSeconds(timeArrived->toAronLongPtr()->value); + + auto confidence = aron::datanavigator::DoubleNavigator::DynamicCastAndCheck(dataWrapped->getElement(DATA_WRAPPER_CONFIDENCE_FIELD)); + metadata.confidence = static_cast<float>(confidence->toAronDoublePtr()->value); + } + + void to_aron(aron::datanavigator::DictNavigatorPtr& a, const wm::EntityInstance& e) + { + if (e.data()) + { + a->addElement(DATA_WRAPPER_DATA_FIELD, e.data()); + } + + auto timeWrapped = std::make_shared<aron::datanavigator::LongNavigator>(); + timeWrapped->setValue(Time::now().toMicroSeconds()); + a->addElement(DATA_WRAPPER_TIME_STORED_FIELD, timeWrapped); + + const wm::EntityInstanceMetadata& metadata = e.metadata(); + auto timeCreated = std::make_shared<aron::datanavigator::LongNavigator>(); + timeCreated->setValue(metadata.timeCreated.toMicroSeconds()); + a->addElement(DATA_WRAPPER_TIME_CREATED_FIELD, timeCreated); + + auto timeSent = std::make_shared<aron::datanavigator::LongNavigator>(); + timeSent->setValue(metadata.timeSent.toMicroSeconds()); + a->addElement(DATA_WRAPPER_TIME_SENT_FIELD, timeSent); + + auto timeArrived = std::make_shared<aron::datanavigator::LongNavigator>(); + timeArrived->setValue(metadata.timeArrived.toMicroSeconds()); + a->addElement(DATA_WRAPPER_TIME_ARRIVED_FIELD, timeArrived); + + auto confidence = std::make_shared<aron::datanavigator::DoubleNavigator>(); + confidence->setValue(static_cast<double>(metadata.confidence)); + a->addElement(DATA_WRAPPER_CONFIDENCE_FIELD, confidence); + } +} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/entityInstance_conversions.h b/source/RobotAPI/libraries/armem/core/workingmemory/entityInstance_conversions.h new file mode 100644 index 0000000000000000000000000000000000000000..f3b25566f110dca844e24dcac4c997f724c74548 --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/workingmemory/entityInstance_conversions.h @@ -0,0 +1,9 @@ +#pragma once + +#include "Memory.h" + +namespace armarx::armem +{ + void from_aron(const aron::datanavigator::DictNavigatorPtr&, wm::EntityInstance&); + void to_aron(aron::datanavigator::DictNavigatorPtr&, const wm::EntityInstance&); +} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/json_conversions.cpp b/source/RobotAPI/libraries/armem/core/workingmemory/json_conversions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e01c69eff1b98b7123a0c15ad97912dfa85521a --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/workingmemory/json_conversions.cpp @@ -0,0 +1,20 @@ +#include "json_conversions.h" + +namespace armarx::armem +{ + + void from_aron(const aron::datanavigator::DictNavigatorPtr& aron, nlohmann::json& j) + { + aron::dataIO::writer::NlohmannJSONWriter dataWriter; + aron::dataIO::Visitor::VisitAndSetup(dataWriter, aron); + j = dataWriter.getResult(); + } + + void to_aron(aron::datanavigator::DictNavigatorPtr& a, const nlohmann::json& e, const aron::typenavigator::NavigatorPtr& expectedStructure) + { + aron::dataIO::reader::NlohmannJSONReader dataReader(e); + aron::dataIO::writer::NavigatorWriter navWriter; + aron::dataIO::Converter::ReadAndConvert(dataReader, navWriter, expectedStructure); + a = aron::datanavigator::DictNavigator::DynamicCastAndCheck(navWriter.getResult()); + } +} diff --git a/source/RobotAPI/libraries/armem/core/workingmemory/json_conversions.h b/source/RobotAPI/libraries/armem/core/workingmemory/json_conversions.h new file mode 100644 index 0000000000000000000000000000000000000000..d132d88f7d7fb694be8b3dc086c87dcafa276e6a --- /dev/null +++ b/source/RobotAPI/libraries/armem/core/workingmemory/json_conversions.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Memory.h" + +#include <RobotAPI/libraries/aron/core/io/dataIO/converter/Converter.h> +#include <RobotAPI/libraries/aron/core/io/dataIO/visitor/Visitor.h> +#include <RobotAPI/libraries/aron/core/io/dataIO/reader/nlohmannJSON/NlohmannJSONReader.h> +#include <RobotAPI/libraries/aron/core/io/dataIO/writer/nlohmannJSON/NlohmannJSONWriter.h> + + +namespace armarx::armem +{ + void from_aron(const aron::datanavigator::DictNavigatorPtr&, nlohmann::json&); + void to_aron(aron::datanavigator::DictNavigatorPtr&, const nlohmann::json&, const aron::typenavigator::NavigatorPtr& expectedStructure = nullptr); +} diff --git a/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp b/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp index 536c72f49d6ccb4c656f37c345dc6a4ec70b4f17..f7046b6b6a5efd30debcc2e31e1125a3e1dc831c 100644 --- a/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp +++ b/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp @@ -19,9 +19,11 @@ namespace armarx::armem::server::plugins ClientPlugin::postCreatePropertyDefinitions(properties); properties->topic(memoryListener, this->parent<ComponentPluginUser>().memoryListenerDefaultName); - properties->optional(longTermMemoryDatabaseHost, this->parent<ComponentPluginUser>().longTermMemoryDatabaseHostDefault); - properties->optional(longTermMemoryDatabaseUser, this->parent<ComponentPluginUser>().longTermMemoryDatabaseUserDefault); - properties->optional(longTermMemoryDatabasePassword, this->parent<ComponentPluginUser>().longTermMemoryDatabasePasswordDefault); + properties->optional(this->parent<ComponentPluginUser>().longtermMemory.dbsettings.host, "Longtermmemoryhost"); + properties->optional(this->parent<ComponentPluginUser>().longtermMemory.dbsettings.port, "Longtermmemoryport"); + properties->optional(this->parent<ComponentPluginUser>().longtermMemory.dbsettings.user, "Longtermmemoryuser"); + properties->optional(this->parent<ComponentPluginUser>().longtermMemory.dbsettings.password, "Longtermmemorypassword"); + properties->optional(this->parent<ComponentPluginUser>().longtermMemory.dbsettings.database, "Longtermmemorydatabase"); } @@ -36,12 +38,7 @@ namespace armarx::armem::server::plugins parent.iceMemory.setMemoryListener(memoryListener); // establishing connection to ltm and mongodb - ltm::MongoDBConnectionManager::MongoDBSettings settings; - settings.host = longTermMemoryDatabaseHost; - settings.user = longTermMemoryDatabaseUser; - settings.password = longTermMemoryDatabasePassword; - - parent.longtermMemory.reload(settings); + parent.longtermMemory.reload(); } diff --git a/source/RobotAPI/libraries/armem/server/ComponentPlugin.h b/source/RobotAPI/libraries/armem/server/ComponentPlugin.h index fc2154f59a0d640a2b6d6e07f5df51465caa2812..4262ee9eba64b29519612cd57505dd9fbe2cc9d1 100644 --- a/source/RobotAPI/libraries/armem/server/ComponentPlugin.h +++ b/source/RobotAPI/libraries/armem/server/ComponentPlugin.h @@ -104,9 +104,6 @@ namespace armarx::armem::server /// property defaults std::string memoryListenerDefaultName = "MemoryUpdates"; - std::string longTermMemoryDatabaseHostDefault = ""; - std::string longTermMemoryDatabaseUserDefault = ""; - std::string longTermMemoryDatabasePasswordDefault = ""; /// Helps connecting `memory` to ice. Used to handle Ice callbacks. MemoryToIceAdapter iceMemory { &workingMemory, &longtermMemory}; diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp index c1ae33fbe624fe2558c8f2dfb11d2ae380fb192a..75e38944378144ee47fe13cbd733445555fbe48f 100644 --- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp +++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp @@ -219,16 +219,14 @@ namespace armarx::armem::server data::StoreResult output; armem::query::data::Result queryResult = this->query(input.query); + output.success = queryResult.success; + if (queryResult.success) { wm::Memory m; fromIce(queryResult.memory, m); longtermMemory->append(m); } - else - { - output.success = false; - } ARMARX_IMPORTANT << "Finsihed"; return output; diff --git a/source/RobotAPI/libraries/armem_gui/CMakeLists.txt b/source/RobotAPI/libraries/armem_gui/CMakeLists.txt index d90a90aa04a3fcc2c3d891bfab8727a991522f44..d381a529fb0bc17c6fc74447a46694b89512d1ef 100644 --- a/source/RobotAPI/libraries/armem_gui/CMakeLists.txt +++ b/source/RobotAPI/libraries/armem_gui/CMakeLists.txt @@ -17,7 +17,7 @@ set(SOURCES MemoryViewer.cpp PeriodicUpdateWidget.cpp - LTMControlWidget.cpp + MemoryControlWidget.cpp gui_utils.cpp lifecycle.cpp @@ -49,7 +49,7 @@ set(HEADERS MemoryViewer.h PeriodicUpdateWidget.h - LTMControlWidget.h + MemoryControlWidget.h TreeWidgetBuilder.h gui_utils.h lifecycle.h diff --git a/source/RobotAPI/libraries/armem_gui/LTMControlWidget.cpp b/source/RobotAPI/libraries/armem_gui/MemoryControlWidget.cpp similarity index 79% rename from source/RobotAPI/libraries/armem_gui/LTMControlWidget.cpp rename to source/RobotAPI/libraries/armem_gui/MemoryControlWidget.cpp index 257e43d3a3f0df224b4632449c97aa4336c9f184..c68673377563e83019640755699187ebee39a418 100644 --- a/source/RobotAPI/libraries/armem_gui/LTMControlWidget.cpp +++ b/source/RobotAPI/libraries/armem_gui/MemoryControlWidget.cpp @@ -1,4 +1,4 @@ -#include "LTMControlWidget.h" +#include "MemoryControlWidget.h" #include <QPushButton> #include <QLineEdit> @@ -11,7 +11,7 @@ namespace armarx::armem::gui { - LTMControlWidget::LTMControlWidget() + MemoryControlWidget::MemoryControlWidget() { setSizePolicy(QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Fixed); @@ -27,8 +27,8 @@ namespace armarx::armem::gui _storeButton = new QPushButton("Store in LTM", this); layout->addWidget(_lineEdit); - layout->addWidget(_storeButton); layout->addWidget(_exportHereButton); + layout->addWidget(_storeButton); // Private connections. @@ -37,22 +37,22 @@ namespace armarx::armem::gui connect(_exportHereButton, &QPushButton::pressed, this, &This::exportHere); } - QLineEdit* LTMControlWidget::pathInputBox() + QLineEdit* MemoryControlWidget::pathInputBox() { return _lineEdit; } - QString LTMControlWidget::getEnteredPath() + QString MemoryControlWidget::getEnteredPath() { return _lineEdit->text(); } - QPushButton* LTMControlWidget::storeButton() + QPushButton* MemoryControlWidget::storeButton() { return _storeButton; } - QPushButton* LTMControlWidget::exportHereButton() + QPushButton* MemoryControlWidget::exportHereButton() { return _exportHereButton; } diff --git a/source/RobotAPI/libraries/armem_gui/LTMControlWidget.h b/source/RobotAPI/libraries/armem_gui/MemoryControlWidget.h similarity index 71% rename from source/RobotAPI/libraries/armem_gui/LTMControlWidget.h rename to source/RobotAPI/libraries/armem_gui/MemoryControlWidget.h index 9c827b01173aa7b724fcfe7e700691d5a093e36e..4f8acc62ac9c8918f887703d9188e76cfc9f8584 100644 --- a/source/RobotAPI/libraries/armem_gui/LTMControlWidget.h +++ b/source/RobotAPI/libraries/armem_gui/MemoryControlWidget.h @@ -8,19 +8,20 @@ class QLineEdit; namespace armarx::armem::gui { - class LTMControlWidget : public QWidget + class MemoryControlWidget : public QWidget { Q_OBJECT - using This = LTMControlWidget; + using This = MemoryControlWidget; public: - LTMControlWidget(); + MemoryControlWidget(); QLineEdit* pathInputBox(); QString getEnteredPath(); QPushButton* storeButton(); + QPushButton* loadButton(); QPushButton* exportHereButton(); public slots: @@ -28,6 +29,7 @@ namespace armarx::armem::gui signals: void store(); + void load(); void exportHere(); private slots: @@ -41,6 +43,7 @@ namespace armarx::armem::gui QLineEdit* _lineEdit; QPushButton* _storeButton; + QPushButton* _loadButton; QPushButton* _exportHereButton; }; diff --git a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp index 447b35332a60a3442b63e07a2c5e129b5b7b83d1..e66191fc6896eec1c7b23a10290285ea4b01c943 100644 --- a/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp +++ b/source/RobotAPI/libraries/armem_gui/MemoryViewer.cpp @@ -28,7 +28,7 @@ namespace armarx::armem::gui { MemoryViewer::MemoryViewer( QBoxLayout* updateWidgetLayout, - QBoxLayout* ltmControlWidgetLayout, + QBoxLayout* memoryControlWidgetLayout, QGroupBox* memoryGroupBox, QLayout* memoryGroupBoxParentLayout, QGroupBox* instanceGroupBox, QLayout* instanceGroupBoxParentLayout, QLabel* statusLabel @@ -45,11 +45,11 @@ namespace armarx::armem::gui updateWidgetLayout->insertWidget(0, updateWidget); // LTM Control - if (ltmControlWidgetLayout) + if (memoryControlWidgetLayout) { - this->ltmControlWidgetLayout = ltmControlWidgetLayout; - ltmControlWidget = new armem::gui::LTMControlWidget(); - ltmControlWidgetLayout->addWidget(ltmControlWidget); + this->memoryControlWidgetLayout = memoryControlWidgetLayout; + memoryControlWidget = new armem::gui::MemoryControlWidget(); + memoryControlWidgetLayout->addWidget(memoryControlWidget); } // Memory View @@ -66,8 +66,8 @@ namespace armarx::armem::gui // Connections //connect(this, &This::connected, this, &This::updateMemory); - connect(ltmControlWidget, &armem::gui::LTMControlWidget::store, this, &This::store); - connect(ltmControlWidget, &armem::gui::LTMControlWidget::exportHere, this, &This::exportHere); + connect(memoryControlWidget, &armem::gui::MemoryControlWidget::exportHere, this, &This::exportHere); + connect(memoryControlWidget, &armem::gui::MemoryControlWidget::store, this, &This::store); connect(this, &This::connected, this, &This::updateMemories); connect(updateWidget, &armem::gui::PeriodicUpdateWidget::update, this, &This::updateMemories); @@ -144,7 +144,7 @@ namespace armarx::armem::gui void MemoryViewer::exportHere() { TIMING_START(MemoryExport); - QString qs = ltmControlWidget->getEnteredPath(); + QString qs = memoryControlWidget->getEnteredPath(); std::string utf8_text = qs.toUtf8().constData(); ARMARX_IMPORTANT << "Exporting all memories at '" << utf8_text << "'."; diff --git a/source/RobotAPI/libraries/armem_gui/MemoryViewer.h b/source/RobotAPI/libraries/armem_gui/MemoryViewer.h index 19ab5000d9d662080b80e621144650fd887a0bcd..9931f6e3523ec8e020a5183da8fb15319d25ae8b 100644 --- a/source/RobotAPI/libraries/armem_gui/MemoryViewer.h +++ b/source/RobotAPI/libraries/armem_gui/MemoryViewer.h @@ -13,7 +13,7 @@ #include <RobotAPI/libraries/armem_gui/instance/GroupBox.h> #include <RobotAPI/libraries/armem_gui/memory/GroupBox.h> #include <RobotAPI/libraries/armem_gui/PeriodicUpdateWidget.h> -#include <RobotAPI/libraries/armem_gui/LTMControlWidget.h> +#include <RobotAPI/libraries/armem_gui/MemoryControlWidget.h> class QBoxLayout; class QDialog; @@ -109,8 +109,8 @@ namespace armarx::armem::gui QLayout* updateWidgetLayout = nullptr; armem::gui::PeriodicUpdateWidget* updateWidget = nullptr; - QLayout* ltmControlWidgetLayout = nullptr; - armem::gui::LTMControlWidget* ltmControlWidget = nullptr; + QLayout* memoryControlWidgetLayout = nullptr; + armem::gui::MemoryControlWidget* memoryControlWidget = nullptr; armem::gui::MemoryGroupBox* memoryGroup = nullptr; diff --git a/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.cpp index 7f46c9b4509c54430eb2ddca0a10426d7ceab227..0e2d95dda06126717c383c9b71f7b1088bacd71a 100644 --- a/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.cpp +++ b/source/RobotAPI/libraries/armem_objects/server/attachments/Segment.cpp @@ -16,14 +16,13 @@ #include <RobotAPI/libraries/armem/client/query/query_fns.h> #include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h> -#include <RobotAPI/libraries/armem_objects/aron/Robot.aron.generated.h> +#include <RobotAPI/libraries/armem_robot/aron/Robot.aron.generated.h> #include <RobotAPI/libraries/armem_objects/aron_conversions.h> #include <RobotAPI/libraries/armem_objects/aron/Attachment.aron.generated.h> namespace armarx::armem::server::obj::attachments { - Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter, std::mutex& memoryMutex) : iceMemory(memoryToIceAdapter), memoryMutex(memoryMutex) @@ -43,7 +42,7 @@ namespace armarx::armem::server::obj::attachments { ARMARX_CHECK_NOT_NULL(iceMemory.workingMemory); - coreSegment = &iceMemory.workingMemory->addCoreSegment(p.coreClassSegmentName, arondto::Robot::toInitialAronType()); + coreSegment = &iceMemory.workingMemory->addCoreSegment(p.coreClassSegmentName, arondto::Robot::toAronType()); coreSegment->setMaxHistorySize(p.maxHistorySize); }