3 #include <experimental/memory>
8 #include <shared_mutex>
16 #include <boost/locale.hpp>
17 #include <boost/uuid/name_generator.hpp>
18 #include <boost/uuid/nil_generator.hpp>
19 #include <boost/uuid/string_generator.hpp>
20 #include <boost/uuid/uuid.hpp>
21 #include <boost/uuid/uuid_generators.hpp>
22 #include <boost/uuid/uuid_io.hpp>
24 #include <IceUtil/UUID.h>
26 #include <SimoxUtility/algorithm/string/string_tools.h>
27 #include <SimoxUtility/json/json.hpp>
54 #include <RobotAPI/interface/aron/Aron.h>
55 #include <RobotAPI/interface/skills/SkillManagerInterface.h>
70 root.
description =
"This is the root profile. It is the parent of all other profiles.";
73 std::unique_lock profilesLock(fluxioDC.profilesMutex);
74 fluxioDC.profiles[root.
id] = root;
75 profilesLock.unlock();
78 const auto& baseTypesPtr = std::make_shared<aron::type::Object>();
79 const std::string& keyName =
"BaseTypesNamespace";
80 baseTypesPtr->setObjectName(keyName);
81 const auto& eventTypePtr = std::make_shared<aron::type::Object>();
82 eventTypePtr->setObjectName(
"Event");
83 baseTypesPtr->addMemberType(
"Event", eventTypePtr);
85 std::unique_lock typesLock(fluxioDC.typesMutex);
86 fluxioDC.types[keyName] = baseTypesPtr;
90 template <
typename S,
typename T>
91 std::vector<std::experimental::observer_ptr<const T>>
92 SkillManagerComponentPlugin::convertMapValuesToObserverVector(std::map<S, T>& map)
94 std::vector<std::experimental::observer_ptr<const T>>
ret;
95 for (
const auto& [k,
v] : map)
105 auto& p = parent<SkillManagerComponentPluginUser>();
106 p.getProxy(myPrx, -1);
118 for (
const auto& [providerName, providerPrx] : skillProviderMap)
120 auto allSkills = providerPrx->getSkillDescriptions();
121 for (
const auto& [currentSkillID, skillDesc] : allSkills)
123 if (currentSkillID.skillName == skillId.
skillName)
125 return {providerName};
129 return {
"INVALID PROVIDER NAME"};
135 std::scoped_lock l(skillProviderMapMutex);
136 if (skillProviderMap.find(providerInfo.
providerId) == skillProviderMap.end())
144 ARMARX_INFO <<
"Trying to add a provider with name '"
146 <<
"' but the provider already exists. "
147 <<
"Overwriting the old provider info.";
151 for (
const auto& [skillID, skillDesc] : providerInfo.
providedSkills)
153 descriptionIdToFluxioSkill(skillID, skillDesc);
154 ARMARX_INFO <<
"Adding skill '" << skillID.skillName <<
"' as FluxioSkill.";
161 std::scoped_lock l(skillProviderMapMutex);
162 if (
auto it = skillProviderMap.find(providerId); it != skillProviderMap.end())
165 skillProviderMap.erase(it);
170 <<
"' but it couldn't be found.";
180 std::unique_lock l(skillProviderMapMutex);
190 if (
auto it = skillProviderMap.find(provderId); it != skillProviderMap.end())
192 const auto& provider = it->second;
196 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
197 << provderId <<
"'. Removing it from skills.";
198 skillProviderMap.erase(it);
202 "Skill execution failed. Could not execute a skill of provider '" +
203 provderId.toString() +
"' because the provider does not exist.");
212 .callbackInterface = myPrx};
215 provider->begin_executeSkill(provider_executionRequest.toProviderIce());
217 auto provider_statusUpdate_ice = provider->end_executeSkill(async);
224 catch (
const std::exception& e)
228 handleExceptionNonLockingThrow(__PRETTY_FUNCTION__, e, provderId);
235 "Skill execution failed. Could not execute a skill of provider '" +
236 provderId.
toString() +
"' because the provider does not exist.");
247 std::unique_lock l(skillProviderMapMutex);
257 if (
auto it = skillProviderMap.find(provderId); it != skillProviderMap.end())
259 const auto& provider = it->second;
263 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
264 << provderId <<
"'. Removing it from skills.";
265 skillProviderMap.erase(it);
269 "Skill execution failed. Could not execute a skill of provider '" +
270 provderId.toString() +
"' because the provider does not exist.");
279 .callbackInterface = myPrx};
282 provider->begin_executeSkillAsync(provider_executionRequest.toProviderIce());
284 auto provider_executionID_ice = provider->end_executeSkillAsync(async);
289 executionId.skillId.providerId = provderId;
292 catch (
const std::exception& e)
296 handleExceptionNonLockingThrow(__PRETTY_FUNCTION__, e, provderId);
303 "Skill execution failed. Could not execute a skill of provider '" +
304 provderId.
toString() +
"' because the provider does not exist.");
317 std::unique_lock l(skillProviderMapMutex);
319 it != skillProviderMap.end())
321 const auto& providerId = it->first;
322 const auto& provider = it->second;
326 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
327 << providerId <<
"'. Removing it from skills.";
328 skillProviderMap.erase(it);
334 auto async = provider->begin_updateSkillParameters(executionId.
toProviderIce(),
335 data->toAronDictDTO());
337 auto r = provider->end_updateSkillParameters(async);
340 catch (
const std::exception& e)
344 handleExceptionNonLocking(__PRETTY_FUNCTION__, e, providerId);
363 std::unique_lock l(skillProviderMapMutex);
365 it != skillProviderMap.end())
367 const auto& providerId = it->first;
368 const auto& provider = it->second;
372 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
373 << providerId <<
"'. Removing it from skills.";
374 skillProviderMap.erase(it);
380 auto async = provider->begin_abortSkill(executionId.
toProviderIce());
382 auto r = provider->end_abortSkill(async);
385 catch (
const std::exception& e)
389 handleExceptionNonLocking(__PRETTY_FUNCTION__, e, providerId);
406 std::unique_lock l(skillProviderMapMutex);
408 it != skillProviderMap.end())
410 const auto& providerId = it->first;
411 const auto& provider = it->second;
415 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
416 << providerId <<
"'. Removing it from skills.";
417 skillProviderMap.erase(it);
423 auto async = provider->begin_abortSkillAsync(executionId.
toProviderIce());
425 auto r = provider->end_abortSkillAsync(async);
428 catch (
const std::exception& e)
432 handleExceptionNonLocking(__PRETTY_FUNCTION__, e, providerId);
443 std::optional<skills::SkillDescription>
446 ARMARX_DEBUG <<
"getSkillDescription for skill " << skillId;
448 ARMARX_CHECK(skillId.isFullySpecified()) <<
"Got: " << skillId.toString();
450 std::unique_lock l(skillProviderMapMutex);
451 if (
auto it = skillProviderMap.find(*skillId.providerId); it != skillProviderMap.end())
453 const auto& providerId = it->first;
454 const auto& provider = it->second;
458 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
459 << providerId <<
"'. Removing it from skills.";
460 skillProviderMap.erase(it);
463 "Skill execution failed. Could not query a "
464 "status update of a skill of provider '" +
465 providerId.toString() +
466 "' because the provider does not exist.");
471 auto async = provider->begin_getSkillDescription(skillId.toProviderIce());
473 auto provider_desc_ice = provider->end_getSkillDescription(async);
475 if (not provider_desc_ice)
485 catch (
const std::exception& e)
489 handleExceptionNonLockingThrow(__PRETTY_FUNCTION__, e, providerId);
498 std::map<skills::SkillID, skills::SkillDescription>
501 std::map<skills::SkillID, skills::SkillDescription>
ret;
503 std::unique_lock l(skillProviderMapMutex);
504 for (
auto it = skillProviderMap.cbegin(); it != skillProviderMap.cend();)
506 const auto& providerId = it->first;
507 const auto& provider = it->second;
511 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
512 << providerId <<
"'. Removing it from skills.";
513 it = skillProviderMap.erase(it);
519 auto async = provider->begin_getSkillDescriptions();
521 auto m = provider->end_getSkillDescriptions(async);
524 for (
const auto& [provider_skillId_ice, skillDescription_ice] : m)
533 catch (
const std::exception& e)
537 if (
auto _it = handleExceptionNonLocking(__PRETTY_FUNCTION__, e, providerId))
546 std::optional<skills::SkillStatusUpdate>
553 std::unique_lock l(skillProviderMapMutex);
555 it != skillProviderMap.end())
557 const auto& providerId = it->first;
558 const auto& provider = it->second;
562 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
563 << providerId <<
"'. Removing it from skills.";
564 skillProviderMap.erase(it);
567 "Skill execution failed. Could not query a "
568 "status update of a skill of provider '" +
569 providerId.toString() +
570 "' because the provider does not exist.");
575 auto async = provider->begin_getSkillExecutionStatus(executionId.
toProviderIce());
577 auto provider_statusUpdate_ice = provider->end_getSkillExecutionStatus(async);
579 if (not provider_statusUpdate_ice)
586 provider_statusUpdate_ice.value(), providerId);
591 catch (
const std::exception& e)
595 handleExceptionNonLockingThrow(__PRETTY_FUNCTION__, e, providerId);
604 std::map<skills::SkillExecutionID, skills::SkillStatusUpdate>
607 std::map<skills::SkillExecutionID, skills::SkillStatusUpdate>
ret;
609 std::unique_lock l(skillProviderMapMutex);
610 for (
auto it = skillProviderMap.cbegin(); it != skillProviderMap.cend();)
612 const auto& providerId = it->first;
613 const auto& provider = it->second;
617 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
618 << providerId <<
"'. Removing it from skills.";
619 it = skillProviderMap.erase(it);
625 auto async = provider->begin_getSkillExecutionStatuses();
627 auto m = provider->end_getSkillExecutionStatuses(async);
630 for (
const auto& [provider_executionId_ice, provider_statusUpdate_ice] : m)
639 catch (
const std::exception& e)
641 if (
auto _it = handleExceptionNonLocking(__PRETTY_FUNCTION__, e, providerId))
651 std::map<skills::ProviderID, skills::provider::dti::SkillProviderInterfacePrx>::iterator>
652 SkillManagerComponentPlugin::handleExceptionNonLocking(
const char* funcName,
653 const std::exception& e,
655 bool eraseSkillProvider)
658 if (
auto it = skillProviderMap.find(providerId);
659 eraseSkillProvider and it != skillProviderMap.end())
661 ARMARX_WARNING << funcName <<
": Found disconnected or buggy skill provider '"
662 << providerId <<
"' during execution. Removing it from skills. "
663 <<
"Error: " << e.what();
664 return skillProviderMap.erase(it);
668 ARMARX_WARNING << funcName <<
": Found disconnected or buggy skill provider '"
670 <<
"' during execution. However, it already got removed... "
671 <<
"Error: " << e.what();
677 SkillManagerComponentPlugin::handleExceptionNonLockingThrow(
const char* funcName,
678 const std::exception& e,
679 skills::ProviderID providerId,
680 bool eraseSkillProvider)
683 handleExceptionNonLocking(funcName, e, providerId, eraseSkillProvider);
685 throw skills::error::SkillException(
687 "Skill execution failed. Could not execute a skill of provider '" +
688 providerId.toString() +
"' because the provider does not exist.");
695 skills::Result<std::experimental::observer_ptr<skills::FluxioExecutor>,
696 skills::error::FluxioException>
698 const std::string& profileId,
699 const std::string& executorName,
702 const auto& result =
getSkill(skillId);
703 if (!result.isSuccess())
710 "SkillManagerComponentPlugin",
715 const auto& skill = result.getResult();
716 if (skill ==
nullptr)
718 ARMARX_WARNING <<
"Unexpected nullptr for skill with id '" << skillId <<
"'.";
723 "SkillManagerComponentPlugin",
728 const std::string& executionId = IceUtil::generateUUID();
729 const bool isNative = skill->native;
732 if (parameters ==
nullptr)
734 ARMARX_WARNING <<
"No parameters supplied for skill '" << skill->name <<
"(" << skillId
735 <<
")'. Using profile values instead.";
737 parameters = std::make_shared<aron::data::Dict>();
741 <<
"Initializing skill execution with the following parameter values (overrides): "
746 const auto& executeFluxioSkillFunc =
747 [
this](
const std::string& skillId,
748 const std::string& profileId,
749 const std::string& executorName,
759 const auto& addMergerExecutorToDCFunc =
760 [
this](
const std::vector<std::string>& parameterIds)
762 const auto& executorId = IceUtil::generateUUID();
763 std::unique_lock l(this->fluxioDC.fluxioExecutorsMutex);
765 this->fluxioDC.fluxioExecutors[executorId] =
766 std::make_unique<skills::FluxioMergerExecutor>(executorId, parameterIds);
769 this->fluxioDC.fluxioExecutors[executorId].get());
774 std::shared_lock skillLock(fluxioDC.skillsMutex);
775 const auto& skillRef = fluxioDC.skills[skillId];
778 std::unique_lock l(fluxioDC.fluxioExecutorsMutex);
779 fluxioDC.fluxioExecutors[executionId] =
780 std::make_unique<skills::FluxioCompositeExecutor>(
784 std::move(executeFluxioSkillFunc),
785 std::move(addMergerExecutorToDCFunc));
791 const auto& profilePtr =
794 std::thread([executorPtr, executorName, parameters, profilePtr]()
795 { executorPtr->run(executorName, parameters, profilePtr); })
802 .skillName = skill->name};
805 if (!skillDescr.has_value())
807 ARMARX_WARNING <<
"Skill description for skill with id '" << skillId
808 <<
"' not found. Aborting execution." << sID.
toString();
814 "SkillManagerComponentPlugin",
825 const auto& getSkillExecutionStatusFunc =
829 std::unique_lock l(fluxioDC.fluxioExecutorsMutex);
830 fluxioDC.fluxioExecutors[executionId] = std::make_unique<skills::FluxioNativeExecutor>(
834 std::move(abortSkillFunc),
835 std::move(executeSkillAsyncFunc),
836 std::move(getSkillExecutionStatusFunc));
842 const auto& profilePtr =
845 std::thread([executorPtr, executorName, parameters, profilePtr]()
846 { executorPtr->run(executorName, parameters, profilePtr); })
850 return {executorPtr};
856 std::shared_lock l(fluxioDC.fluxioExecutorsMutex);
857 const auto& executorIt = fluxioDC.fluxioExecutors.find(executionId);
858 if (executorIt == fluxioDC.fluxioExecutors.end())
860 ARMARX_WARNING <<
"Execution with id '" << executionId <<
"' not found.";
867 "SkillManagerComponentPlugin",
874 executorIt->second->abort();
880 std::shared_lock l(fluxioDC.fluxioExecutorsMutex);
881 const auto& executorIt = fluxioDC.fluxioExecutors.find(executionId);
882 if (executorIt == fluxioDC.fluxioExecutors.end())
884 ARMARX_WARNING <<
"Execution with id '" << executionId <<
"' not found.";
891 "SkillManagerComponentPlugin",
897 return {executorIt->second->getStatusUpdate().value()};
907 SkillManagerComponentPlugin::convertAronObjectPtrToFluxioParameters(
908 std::map<std::string, skills::FluxioParameter>&
ret,
911 const boost::uuids::uuid& skillId)
913 for (
const auto& [name, typeInfo] : ptr->getMemberTypes())
917 const auto& seed = name + (isInput ?
"isInput" :
"isOutput");
924 p.
required = (typeInfo->getMaybe() == 0);
928 std::unique_lock l(fluxioDC.typesMutex);
936 SkillManagerComponentPlugin::createUuidWithString(
937 const std::string&
str,
938 std::optional<const boost::uuids::uuid> namespaceUUID)
940 boost::uuids::uuid nameS;
941 if (namespaceUUID.has_value())
943 nameS = namespaceUUID.value();
948 nameS = boost::uuids::nil_uuid();
952 boost::uuids::name_generator generator(nameS);
955 return generator(
str);
964 SkillManagerComponentPlugin::descriptionIdToFluxioSkill(
965 skills::SkillID skillId,
966 skills::SkillDescription skillDescription)
970 const auto& providerId = createUuidWithString(skillId.providerId->providerName);
971 const auto&
id = createUuidWithString(skillId.skillName, providerId);
973 std::unique_lock skillsLock(fluxioDC.skillsMutex);
975 if (skillsEntry != fluxioDC.skills.end())
981 skills::FluxioSkill
s;
984 s.name = skillId.skillName;
985 s.description = skillDescription.description;
986 s.timeout = skillDescription.timeout;
988 s.executable =
false;
991 std::unique_lock providersLock(fluxioDC.providersMutex);
992 const auto& providersEntry =
994 if (providersEntry != fluxioDC.providers.end())
997 providersLock.unlock();
1001 providersLock.unlock();
1003 if (!res.isSuccess())
1006 << skillId.providerId->providerName <<
"'. Skill: '" <<
s.name
1007 <<
" with id: '" <<
s.id <<
"' will not be added.";
1008 skillsLock.unlock();
1011 const auto p = res.getResult();
1012 s.skillProviderPtr = p;
1014 std::unique_lock typesLock(fluxioDC.typesMutex);
1015 const auto& eventTypeIt = fluxioDC.types.find(
"BaseTypesNamespace");
1016 if (eventTypeIt == fluxioDC.types.end())
1018 ARMARX_WARNING <<
"Event type not found. Skill: '" <<
s.name <<
" with id: '"
1019 <<
s.id <<
"' will not be added.";
1021 skillsLock.unlock();
1025 const auto& eventType = eventTypeIt->second->getMemberType(
"Event");
1026 const skills::FluxioTypeIdentificator& eventTypeIdent = {
1027 .skillId =
"BaseTypesNamespace", .parameterId =
"Event"};
1029 skills::FluxioParameter start;
1030 start.name =
"Start";
1031 start.type = eventType;
1032 start.typeIdentificator = eventTypeIdent;
1033 const auto& startIdStr = start.name + start.type->getFullName() +
"isInput";
1035 start.description =
"Start the skill";
1036 start.required =
true;
1037 start.isInput =
true;
1039 skills::FluxioParameter succeeded;
1040 succeeded.name =
"Succeeded";
1041 succeeded.type = eventType;
1042 succeeded.typeIdentificator = eventTypeIdent;
1043 const auto& successIdStr = succeeded.name + succeeded.type->getFullName() +
"isOutput";
1045 succeeded.description =
"Skill has been executed successfully";
1046 succeeded.required =
false;
1047 succeeded.isInput =
false;
1049 skills::FluxioParameter failed;
1050 failed.name =
"Failed";
1051 failed.type = eventType;
1052 failed.typeIdentificator = eventTypeIdent;
1053 const auto& failedIdStr = failed.name + failed.type->getShortName() +
"isOutput";
1055 failed.description =
"Skill has failed";
1056 failed.required =
false;
1057 failed.isInput =
false;
1059 skills::FluxioParameter aborted;
1060 aborted.name =
"Aborted";
1061 aborted.type = eventType;
1062 aborted.typeIdentificator = eventTypeIdent;
1063 const auto& abortedIdStr = aborted.name + aborted.type->getShortName() +
"isOutput";
1065 aborted.description =
"Skill has been aborted";
1066 aborted.required =
false;
1067 aborted.isInput =
false;
1069 s.parameters[start.id] = start;
1070 s.parameters[succeeded.id] = succeeded;
1071 s.parameters[failed.id] = failed;
1072 s.parameters[aborted.id] = aborted;
1074 const auto& parameters = std::make_shared<aron::type::Object>();
1076 if (fluxioDC.types.find(
s.id) == fluxioDC.types.end())
1078 fluxioDC.types[
s.id] = parameters;
1082 if (skillDescription.parametersType !=
nullptr)
1085 convertAronObjectPtrToFluxioParameters(
1086 s.parameters, skillDescription.parametersType,
true,
id);
1089 if (skillDescription.resultType !=
nullptr)
1092 convertAronObjectPtrToFluxioParameters(
1093 s.parameters, skillDescription.resultType,
false,
id);
1096 if (skillDescription.rootProfileDefaults !=
nullptr)
1100 for (
const auto& [k,
v] : skillDescription.rootProfileDefaults->getElements())
1108 skills::FluxioValue val;
1109 val.profilePtr = rootProfilePtr;
1112 for (
const auto& [pId, param] :
s.parameters)
1114 if (param.name == k && param.isInput)
1116 s.parameters[pId].values.push_back(val);
1124 ARMARX_INFO <<
"No root profile defaults found for skill '" <<
s.name <<
"'.";
1127 fluxioDC.skills.emplace(
s.id, std::move(
s));
1128 skillsLock.unlock();
1132 skills::Result<std::vector<std::experimental::observer_ptr<const skills::FluxioSkill>>,
1133 skills::error::FluxioException>
1136 return {convertMapValuesToObserverVector(fluxioDC.skills)};
1143 std::shared_lock l(fluxioDC.skillsMutex);
1144 const auto& skillsEntry = fluxioDC.skills.find(
id);
1145 if (skillsEntry == fluxioDC.skills.end())
1152 "SkillManagerComponentPlugin",
1162 std::optional<std::vector<std::experimental::observer_ptr<const skills::FluxioSkill>>>
1164 const std::string& userId,
1167 std::shared_lock l(fluxioDC.skillsMutex);
1168 const auto& skillIt = fluxioDC.skills.find(skillId);
1169 if (skillIt == fluxioDC.skills.end())
1171 ARMARX_WARNING <<
"Skill with id '" << skillId <<
"' not found.";
1173 return std::nullopt;
1177 if (skillIt->second.native)
1180 <<
"' is a native skill and cannot be deleted.";
1181 return std::nullopt;
1184 const auto& skillMutexResult =
getSkillMutex(skillId, userId);
1186 if (!skillMutexResult.isSuccess())
1188 ARMARX_WARNING <<
"User '" << userId <<
"' needs to acquire the mutex for skill '"
1189 << skillId <<
"' in order to delete it.";
1190 return std::nullopt;
1193 if (!skillMutexResult.getResult())
1195 ARMARX_WARNING <<
"User '" << userId <<
"' needs to acquire the mutex for skill '"
1196 << skillId <<
"' in order to delete it.";
1197 return std::nullopt;
1200 std::vector<std::experimental::observer_ptr<skills::FluxioSkill>> affectedSkills;
1201 std::vector<std::experimental::observer_ptr<const skills::FluxioSkill>>
ret;
1203 for (
auto& [
id,
s] : fluxioDC.skills)
1205 if (
s.native ||
s.id == skillId)
1210 for (
const auto& [nodeId, node] :
s.nodes)
1212 if (node ==
nullptr)
1221 const auto& subSkillNodeptr =
1223 if (subSkillNodeptr ==
nullptr)
1225 ARMARX_WARNING <<
"Error while casting node to FluxioSubSkillNode.";
1229 if (subSkillNodeptr->skillPtr !=
nullptr &&
1230 subSkillNodeptr->skillPtr->id == skillId)
1247 bool mutexesAquired =
true;
1248 for (
const auto& affectedSkill : affectedSkills)
1250 const auto& affectedMutexResult =
getSkillMutex(affectedSkill->id, userId);
1252 if (!affectedMutexResult.isSuccess() || !affectedMutexResult.getResult())
1254 mutexesAquired =
false;
1255 ARMARX_WARNING <<
"Someone else is editing the skill '" << affectedSkill->name
1256 <<
"(" << affectedSkill->id <<
")' right now.";
1263 for (
const auto& affectedSkill : affectedSkills)
1265 affectedSkill->removeSubSkillNodesAndEdges(skillId);
1268 ARMARX_WARNING <<
"Deleting skill '" << skillIt->second.name <<
"' (" << skillId
1270 std::unique_lock skillsLock(fluxioDC.skillsMutex);
1271 fluxioDC.skills.erase(skillId);
1272 skillsLock.unlock();
1277 <<
"Not all Mutexes for affected skills could be aquired. Aborting deletion.";
1281 for (
const auto& affectedSkill : affectedSkills)
1290 return std::nullopt;
1296 const std::string& parameterId,
1297 const std::string& userId,
1300 return updateFluxioParameter(skillId, parameterId, userId, dryRun,
true);
1306 const std::string& skillId,
1307 const skills::manager::dto::FluxioParameter& parameter,
1308 const std::string& userId,
1311 const auto& parameterId = parameter.id;
1312 return updateFluxioParameter(skillId, parameterId, userId, dryRun,
false, parameter);
1317 SkillManagerComponentPlugin::updateFluxioParameter(
1318 const std::string& skillId,
1319 const std::string& parameterId,
1320 const std::string& userId,
1322 bool deleteParameter,
1323 const std::optional<skills::manager::dto::FluxioParameter>& parameterDT)
1325 if (!deleteParameter && parameterDT == std::nullopt)
1327 ARMARX_WARNING <<
"Required parameter data transfer object not provided.";
1330 {
"parameter data transfer object"}),
1332 "SkillManagerComponentPlugin",
1338 const auto& res =
getSkill(skillId);
1339 if (!res.isSuccess())
1345 "SkillManagerComponentPlugin",
1349 const auto& skill = res.getResult();
1352 const auto& parameterIt = skill->parameters.find(parameterId);
1353 if (parameterIt == skill->parameters.end())
1359 "SkillManagerComponentPlugin",
1363 const auto& parameterOld = parameterIt->second;
1367 if (!mutexResult.isSuccess())
1369 return {mutexResult.getError()};
1373 std::vector<std::experimental::observer_ptr<skills::FluxioSkill>> affectedSkills;
1374 std::vector<std::experimental::observer_ptr<const skills::FluxioSkill>>
ret;
1377 if (deleteParameter ||
1378 parameterOld.typeIdentificator.toManagerIce() != parameterDT.value().type ||
1379 parameterOld.isInput != parameterDT.value().isInput)
1381 std::shared_lock l(fluxioDC.skillsMutex);
1382 for (
auto& [
id,
s] : fluxioDC.skills)
1384 if (
s.native ||
s.id == skillId)
1389 for (
const auto& e :
s.edges)
1391 if ((e.fromParameterPtr !=
nullptr && e.fromParameterPtr->id == parameterId) ||
1392 (e.toParameterPtr !=
nullptr && e.toParameterPtr->id == parameterId))
1409 bool mutexesAquired =
true;
1410 for (
const auto& affectedSkill : affectedSkills)
1412 const auto& affectedMutexResult =
getSkillMutex(affectedSkill->id, userId);
1414 if (!affectedMutexResult.isSuccess() || !affectedMutexResult.getResult())
1416 mutexesAquired =
false;
1417 ARMARX_WARNING <<
"Someone else is editing the skill '" << affectedSkill->name
1418 <<
"(" << affectedSkill->id <<
")' right now.";
1426 for (
const auto& affectedSkill : affectedSkills)
1428 affectedSkill->removeEdgesConnectedToParameter(parameterId);
1431 if (deleteParameter)
1433 ARMARX_WARNING <<
"Deleting skill parameter'" << parameterOld.name <<
"' ("
1434 << parameterId <<
").";
1435 std::unique_lock skillsLock(fluxioDC.skillsMutex);
1436 fluxioDC.skills[skillId].deleteParameter(parameterId);
1437 skillsLock.unlock();
1441 ARMARX_WARNING <<
"Updating skill parameter'" << parameterOld.name <<
"' ("
1442 << parameterId <<
").";
1443 std::scoped_lock l(fluxioDC.skillsMutex,
1444 fluxioDC.profilesMutex,
1445 fluxioDC.providersMutex,
1446 fluxioDC.typesMutex);
1447 auto& profilesMap = fluxioDC.profiles;
1448 auto& typesMap = fluxioDC.types;
1449 fluxioDC.skills[skillId].removeParameterNodesAndEdges(parameterId,
true);
1450 fluxioDC.skills[skillId].parameters[parameterId].updateFromIce(
1451 *parameterDT, profilesMap, typesMap);
1456 ARMARX_WARNING <<
"Not all Mutexes for affected skills could be aquired. Aborting "
1457 << (deleteParameter ?
"deletion" :
"update") <<
" of parameter.";
1461 for (
const auto& affectedSkill : affectedSkills)
1475 "SkillManagerComponentPlugin",
1480 skills::Result<bool, skills::error::FluxioException>
1482 const std::string& userId)
1484 return setEditFluxioSkillMutex(
true, userId, skillId);
1489 const std::string& userId)
1491 setEditFluxioSkillMutex(
false, userId,
1499 std::shared_lock l(fluxioDC.profilesMutex);
1500 const auto&
ret = convertMapValuesToObserverVector(fluxioDC.profiles);
1508 std::shared_lock l(fluxioDC.profilesMutex);
1509 const auto& profilesEntry = fluxioDC.profiles.find(
id);
1511 if (profilesEntry == fluxioDC.profiles.end())
1517 "SkillManagerComponentPlugin",
1523 return {profilesEntry->second};
1536 "SkillManagerComponentPlugin",
1541 const auto& parentId = profile.
parentPtr->id;
1542 const auto& nameLowerCase = simox::alg::to_lower(profile.
name);
1544 std::unique_lock l(fluxioDC.profilesMutex);
1545 auto it = std::find_if(
1546 fluxioDC.profiles.begin(),
1547 fluxioDC.profiles.end(),
1548 [&parentId, &nameLowerCase](
const std::pair<std::string, skills::FluxioProfile>& p)
1550 return p.second.parentPtr != nullptr && p.second.parentPtr->id == parentId &&
1551 simox::alg::to_lower(p.second.name) == nameLowerCase;
1554 if (nameLowerCase ==
"root" || it != fluxioDC.profiles.end())
1562 "SkillManagerComponentPlugin",
1567 std::string
id = profile.
id;
1569 bool validId =
false;
1572 const auto& result = boost::uuids::string_generator()(id);
1573 validId = result.version() != boost::uuids::uuid::version_unknown;
1582 id = IceUtil::generateUUID();
1584 else if (fluxioDC.profiles.find(profile.
id) != fluxioDC.profiles.end())
1587 <<
"' is already taken. A new uuid will be generated.";
1588 id = IceUtil::generateUUID();
1595 fluxioDC.profiles[id] = profile;
1596 fluxioDC.profiles[id].id = id;
1597 const auto&
ret = fluxioDC.profiles[id];
1609 if (oldProfile.isSuccess() && oldProfile.getResult().id == profile.
id)
1611 std::unique_lock l(fluxioDC.profilesMutex);
1612 fluxioDC.profiles[profile.
id].name = profile.
name;
1613 fluxioDC.profiles[profile.
id].description = profile.
description;
1614 fluxioDC.profiles[profile.
id].parentPtr = profile.
parentPtr;
1629 std::unique_lock l(fluxioDC.providersMutex);
1630 if (fluxioDC.providers.find(providerId) != fluxioDC.providers.end())
1632 ARMARX_WARNING <<
"Provider with name '" << name <<
"' already exists.";
1641 fluxioDC.providers[p.
id] = p;
1652 for (
const auto& [providerID, providerPrx] : skillProviderMap)
1656 std::shared_lock l(fluxioDC.providersMutex);
1657 const auto& providersEntry = fluxioDC.providers.find(
id);
1659 if (providersEntry != fluxioDC.providers.end())
1669 return {convertMapValuesToObserverVector(fluxioDC.providers)};
1677 std::shared_lock l(fluxioDC.providersMutex);
1678 const auto& providersEntry = fluxioDC.providers.find(
id);
1680 if (providersEntry != fluxioDC.providers.end())
1683 return {providersEntry->second};
1690 "SkillManagerComponentPlugin",
1701 std::shared_lock l(fluxioDC.providersMutex);
1702 const auto& providersEntry = fluxioDC.providers.find(
id);
1704 if (providersEntry == fluxioDC.providers.end())
1710 "SkillManagerComponentPlugin",
1718 if (!res.isSuccess())
1720 auto e = res.getError();
1721 e.addToContext(std::nullopt,
"SkillManagerComponentPlugin", __FUNCTION__, __LINE__);
1725 auto allSkills = res.getResult();
1727 allSkills.erase(std::remove_if(allSkills.begin(),
1729 [
id](
const auto& skillPtr)
1730 { return skillPtr->skillProviderPtr->id != id; }),
1739 const std::string& providerId,
1742 std::shared_lock l(fluxioDC.providersMutex);
1743 const auto& providerIt = fluxioDC.providers.find(providerId);
1744 if (providerIt == fluxioDC.providers.end())
1746 ARMARX_WARNING <<
"Provider with id '" << providerId <<
"' not found.";
1752 "SkillManagerComponentPlugin",
1758 if (skill.id.empty())
1761 skill.id = IceUtil::generateUUID();
1768 boost::uuids::uuid uuid;
1771 boost::uuids::string_generator gen;
1772 uuid = gen(skill.id);
1774 catch (std::runtime_error& e)
1776 ARMARX_WARNING <<
"Could not convert skill id to uuid: " << e.what();
1777 skill.id = IceUtil::generateUUID();
1780 std::unique_lock typesLock(fluxioDC.typesMutex);
1781 const auto& eventType = fluxioDC.types[
"BaseTypesNamespace"]->getMemberType(
"Event");
1784 .parameterId =
"Event"};
1788 start.
name =
"Start";
1791 start.
type = eventType;
1797 succeeded.
name =
"Succeeded";
1799 succeeded.
description =
"Skill has been executed successfully";
1800 succeeded.
type = eventType;
1806 failed.
name =
"Failed";
1809 failed.
type = eventType;
1815 aborted.
name =
"Aborted";
1818 aborted.
type = eventType;
1823 skill.parameters[start.
id] = start;
1824 skill.parameters[succeeded.
id] = succeeded;
1825 skill.parameters[failed.
id] = failed;
1826 skill.parameters[aborted.
id] = aborted;
1831 const auto skillId = skill.id;
1832 std::unique_lock skillsLock(fluxioDC.skillsMutex);
1833 fluxioDC.skills.emplace(skillId, std::move(skill));
1835 skillsLock.unlock();
1838 setEditFluxioSkillMutex(
true, userId, skill.id);
1843 SkillManagerComponentPlugin::setEditFluxioSkillMutex(
bool aquireMutex,
1844 const std::string& userId,
1845 const std::string& skillId)
1847 std::scoped_lock l(fluxioDC.skillMutexMapMutex);
1848 const auto& skillMutexIt = fluxioDC.skillMutexMap.find(skillId);
1853 if (skillMutexIt == fluxioDC.skillMutexMap.end())
1861 if (std::get<0>(fluxioDC.skillMutexMap[skillId]) == userId)
1871 if (elapsedTime.
toMinutes() > fluxioDC.mutexTimeout)
1883 "SkillManagerComponentPlugin",
1890 if (skillMutexIt == fluxioDC.skillMutexMap.end())
1899 if (std::get<0>(fluxioDC.skillMutexMap[skillId]) == userId)
1901 fluxioDC.skillMutexMap.erase(skillId);
1910 "SkillManagerComponentPlugin",
1919 auto ret = std::make_shared<aron::type::Object>();
1921 std::vector<std::experimental::observer_ptr<const skills::FluxioSkill>>,
1924 if (!res.isSuccess())
1930 std::shared_lock l(fluxioDC.typesMutex);
1931 for (
const auto& [skillId, skillTypes] : fluxioDC.types)
1933 if (skillTypes ==
nullptr)
1935 ARMARX_WARNING <<
"SkillTypes with id '" << skillId <<
"' not found.";
1938 ret->addMemberType(skillId, skillTypes);
1941 ret->setObjectName(
"SkillTypes");