3#include <experimental/memory>
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>
55#include <RobotAPI/interface/aron/Aron.h>
56#include <RobotAPI/interface/skills/SkillManagerInterface.h>
71 root.
description =
"This is the root profile. It is the parent of all other profiles.";
74 std::unique_lock profilesLock(fluxioDC.profilesMutex);
75 fluxioDC.profiles[root.
id] = root;
76 profilesLock.unlock();
79 const auto& baseTypesPtr = std::make_shared<aron::type::Object>();
80 const std::string& keyName =
"BaseTypesNamespace";
81 baseTypesPtr->setObjectName(keyName);
82 const auto& eventTypePtr = std::make_shared<aron::type::Object>();
83 eventTypePtr->setObjectName(
"Event");
84 baseTypesPtr->addMemberType(
"Event", eventTypePtr);
86 std::unique_lock typesLock(fluxioDC.typesMutex);
87 fluxioDC.types[keyName] = baseTypesPtr;
91 template <
typename S,
typename T>
92 std::vector<std::experimental::observer_ptr<const T>>
93 SkillManagerComponentPlugin::convertMapValuesToObserverVector(std::map<S, T>& map)
95 std::vector<std::experimental::observer_ptr<const T>> ret;
96 for (
const auto& [k, v] : map)
107 p.getProxy(myPrx, -1);
119 for (
const auto& [providerName, providerPrx] : skillProviderMap)
121 auto allSkills = providerPrx->getSkillDescriptions();
122 for (
const auto& [currentSkillID, skillDesc] : allSkills)
124 if (currentSkillID.skillName == skillId.
skillName)
126 return {providerName};
130 return {
"INVALID PROVIDER NAME"};
136 std::scoped_lock l(skillProviderMapMutex);
137 if (skillProviderMap.find(providerInfo.
providerId) == skillProviderMap.end())
145 ARMARX_INFO <<
"Trying to add a provider with name '"
147 <<
"' but the provider already exists. "
148 <<
"Overwriting the old provider info.";
152 for (
const auto& [skillID, skillDesc] : providerInfo.
providedSkills)
154 descriptionIdToFluxioSkill(skillID, skillDesc);
155 ARMARX_INFO <<
"Adding skill '" << skillID.skillName <<
"' as FluxioSkill.";
162 std::scoped_lock l(skillProviderMapMutex);
163 if (
auto it = skillProviderMap.find(providerId); it != skillProviderMap.end())
166 skillProviderMap.erase(it);
171 <<
"' but it couldn't be found.";
181 std::unique_lock l(skillProviderMapMutex);
191 if (
auto it = skillProviderMap.find(provderId); it != skillProviderMap.end())
193 const auto& provider = it->second;
197 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
198 << provderId <<
"'. Removing it from skills.";
199 skillProviderMap.erase(it);
203 "Skill execution failed. Could not execute a skill of provider '" +
204 provderId.toString() +
"' because the provider does not exist.");
210 .skillId = executionRequest.
skillId,
213 .callbackInterface = myPrx};
216 provider->begin_executeSkill(provider_executionRequest.toProviderIce());
218 auto provider_statusUpdate_ice = provider->end_executeSkill(async);
225 catch (
const std::exception& e)
229 handleExceptionNonLockingThrow(__PRETTY_FUNCTION__, e, provderId);
236 "Skill execution failed. Could not execute a skill of provider '" +
237 provderId.
toString() +
"' because the provider does not exist.");
248 std::unique_lock l(skillProviderMapMutex);
258 if (
auto it = skillProviderMap.find(provderId); it != skillProviderMap.end())
260 const auto& provider = it->second;
264 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
265 << provderId <<
"'. Removing it from skills.";
266 skillProviderMap.erase(it);
270 "Skill execution failed. Could not execute a skill of provider '" +
271 provderId.toString() +
"' because the provider does not exist.");
277 .skillId = executionRequest.
skillId,
280 .callbackInterface = myPrx};
283 provider->begin_executeSkillAsync(provider_executionRequest.toProviderIce());
285 auto provider_executionID_ice = provider->end_executeSkillAsync(async);
290 executionId.skillId.providerId = provderId;
293 catch (
const std::exception& e)
297 handleExceptionNonLockingThrow(__PRETTY_FUNCTION__, e, provderId);
304 "Skill execution failed. Could not execute a skill of provider '" +
305 provderId.
toString() +
"' because the provider does not exist.");
318 std::unique_lock l(skillProviderMapMutex);
320 it != skillProviderMap.end())
322 const auto& providerId = it->first;
323 const auto& provider = it->second;
327 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
328 << providerId <<
"'. Removing it from skills.";
329 skillProviderMap.erase(it);
335 auto async = provider->begin_updateSkillParameters(executionId.
toProviderIce(),
336 data->toAronDictDTO());
338 auto r = provider->end_updateSkillParameters(async);
341 catch (
const std::exception& e)
345 handleExceptionNonLocking(__PRETTY_FUNCTION__, e, providerId);
364 std::unique_lock l(skillProviderMapMutex);
366 it != skillProviderMap.end())
368 const auto& providerId = it->first;
369 const auto& provider = it->second;
373 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
374 << providerId <<
"'. Removing it from skills.";
375 skillProviderMap.erase(it);
381 auto async = provider->begin_abortSkill(executionId.
toProviderIce());
383 auto r = provider->end_abortSkill(async);
386 catch (
const std::exception& e)
390 handleExceptionNonLocking(__PRETTY_FUNCTION__, e, providerId);
407 std::unique_lock l(skillProviderMapMutex);
409 it != skillProviderMap.end())
411 const auto& providerId = it->first;
412 const auto& provider = it->second;
416 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
417 << providerId <<
"'. Removing it from skills.";
418 skillProviderMap.erase(it);
424 auto async = provider->begin_abortSkillAsync(executionId.
toProviderIce());
426 auto r = provider->end_abortSkillAsync(async);
429 catch (
const std::exception& e)
433 handleExceptionNonLocking(__PRETTY_FUNCTION__, e, providerId);
444 std::optional<skills::SkillDescription>
447 ARMARX_DEBUG <<
"getSkillDescription for skill " << skillId;
451 std::unique_lock l(skillProviderMapMutex);
452 if (
auto it = skillProviderMap.find(*skillId.
providerId); it != skillProviderMap.end())
454 const auto& providerId = it->first;
455 const auto& provider = it->second;
459 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
460 << providerId <<
"'. Removing it from skills.";
461 skillProviderMap.erase(it);
464 "Skill execution failed. Could not query a "
465 "status update of a skill of provider '" +
466 providerId.toString() +
467 "' because the provider does not exist.");
472 auto async = provider->begin_getSkillDescription(skillId.
toProviderIce());
474 auto provider_desc_ice = provider->end_getSkillDescription(async);
476 if (not provider_desc_ice)
486 catch (
const std::exception& e)
490 handleExceptionNonLockingThrow(__PRETTY_FUNCTION__, e, providerId);
499 std::map<skills::SkillID, skills::SkillDescription>
502 std::map<skills::SkillID, skills::SkillDescription> ret;
504 std::unique_lock l(skillProviderMapMutex);
505 for (
auto it = skillProviderMap.cbegin(); it != skillProviderMap.cend();)
507 const auto& providerId = it->first;
508 const auto& provider = it->second;
512 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
513 << providerId <<
"'. Removing it from skills.";
514 it = skillProviderMap.erase(it);
520 auto async = provider->begin_getSkillDescriptions();
522 auto m = provider->end_getSkillDescriptions(async);
525 for (
const auto& [provider_skillId_ice, skillDescription_ice] : m)
534 catch (
const std::exception& e)
538 if (
auto _it = handleExceptionNonLocking(__PRETTY_FUNCTION__, e, providerId))
547 std::optional<skills::SkillStatusUpdate>
554 std::unique_lock l(skillProviderMapMutex);
556 it != skillProviderMap.end())
558 const auto& providerId = it->first;
559 const auto& provider = it->second;
563 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
564 << providerId <<
"'. Removing it from skills.";
565 skillProviderMap.erase(it);
568 "Skill execution failed. Could not query a "
569 "status update of a skill of provider '" +
570 providerId.toString() +
571 "' because the provider does not exist.");
576 auto async = provider->begin_getSkillExecutionStatus(executionId.
toProviderIce());
578 auto provider_statusUpdate_ice = provider->end_getSkillExecutionStatus(async);
580 if (not provider_statusUpdate_ice)
587 provider_statusUpdate_ice.value(), providerId);
592 catch (
const std::exception& e)
596 handleExceptionNonLockingThrow(__PRETTY_FUNCTION__, e, providerId);
605 std::map<skills::SkillExecutionID, skills::SkillStatusUpdate>
608 std::map<skills::SkillExecutionID, skills::SkillStatusUpdate> ret;
610 std::unique_lock l(skillProviderMapMutex);
611 for (
auto it = skillProviderMap.cbegin(); it != skillProviderMap.cend();)
613 const auto& providerId = it->first;
614 const auto& provider = it->second;
618 ARMARX_WARNING << __PRETTY_FUNCTION__ <<
": Found disconnected skill provider '"
619 << providerId <<
"'. Removing it from skills.";
620 it = skillProviderMap.erase(it);
626 auto async = provider->begin_getSkillExecutionStatuses();
628 auto m = provider->end_getSkillExecutionStatuses(async);
631 for (
const auto& [provider_executionId_ice, provider_statusUpdate_ice] : m)
640 catch (
const std::exception& e)
642 if (
auto _it = handleExceptionNonLocking(__PRETTY_FUNCTION__, e, providerId))
652 std::map<skills::ProviderID, skills::provider::dti::SkillProviderInterfacePrx>::iterator>
653 SkillManagerComponentPlugin::handleExceptionNonLocking(
const char* funcName,
654 const std::exception& e,
656 bool eraseSkillProvider)
659 if (
auto it = skillProviderMap.find(providerId);
660 eraseSkillProvider and it != skillProviderMap.end())
662 ARMARX_WARNING << funcName <<
": Found disconnected or buggy skill provider '"
663 << providerId <<
"' during execution. Removing it from skills. "
664 <<
"Error: " << e.what();
665 return skillProviderMap.erase(it);
669 ARMARX_WARNING << funcName <<
": Found disconnected or buggy skill provider '"
671 <<
"' during execution. However, it already got removed... "
672 <<
"Error: " << e.what();
678 SkillManagerComponentPlugin::handleExceptionNonLockingThrow(
const char* funcName,
679 const std::exception& e,
680 skills::ProviderID providerId,
681 bool eraseSkillProvider)
684 handleExceptionNonLocking(funcName, e, providerId, eraseSkillProvider);
686 throw skills::error::SkillException(
688 "Skill execution failed. Could not execute a skill of provider '" +
689 providerId.toString() +
"' because the provider does not exist.");
696 skills::Result<std::experimental::observer_ptr<skills::FluxioExecutor>,
697 skills::error::FluxioException>
699 const std::string& profileId,
700 const std::string& executorName,
703 const auto& result =
getSkill(skillId);
704 if (!result.isSuccess())
711 "SkillManagerComponentPlugin",
716 const auto& skill = result.getResult();
717 if (skill ==
nullptr)
719 ARMARX_WARNING <<
"Unexpected nullptr for skill with id '" << skillId <<
"'.";
724 "SkillManagerComponentPlugin",
729 const std::string& executionId = IceUtil::generateUUID();
730 const bool isNative = skill->native;
733 if (parameters ==
nullptr)
735 ARMARX_WARNING <<
"No parameters supplied for skill '" << skill->name <<
"(" << skillId
736 <<
")'. Using profile values instead.";
738 parameters = std::make_shared<aron::data::Dict>();
742 <<
"Initializing skill execution with the following parameter values (overrides): "
747 const auto& executeFluxioSkillFunc =
748 [
this](
const std::string& skillId,
749 const std::string& profileId,
750 const std::string& executorName,
757 const auto& executeFluxioSkillFunc2 =
758 [
this](
const std::string& skillId,
759 const std::string& profileId,
760 const std::string& executorName,
767 const auto& addMergerExecutorToDCFunc =
768 [
this](
const std::vector<std::string>& parameterIds)
770 const auto& executorId = IceUtil::generateUUID();
771 std::unique_lock l(this->fluxioDC.fluxioExecutorsMutex);
773 this->fluxioDC.fluxioExecutors[executorId] =
774 std::make_unique<skills::FluxioMergerExecutor>(executorId, parameterIds);
777 this->fluxioDC.fluxioExecutors[executorId].get());
782 const auto& addLoopExecutorToDCFunc =
783 [
this, executeFluxioSkillFunc2](
786 const auto& executorId = IceUtil::generateUUID();
787 std::unique_lock l(this->fluxioDC.fluxioExecutorsMutex);
789 this->fluxioDC.fluxioExecutors[executorId] =
790 std::make_unique<skills::FluxioLoopExecutor>(
791 id, skill, isRetry, std::move(executeFluxioSkillFunc2));
794 this->fluxioDC.fluxioExecutors[executorId].get());
799 std::shared_lock skillLock(fluxioDC.skillsMutex);
800 const auto& skillRef = fluxioDC.skills[skillId];
803 std::unique_lock l(fluxioDC.fluxioExecutorsMutex);
804 fluxioDC.fluxioExecutors[executionId] =
805 std::make_unique<skills::FluxioCompositeExecutor>(
808 std::move(executeFluxioSkillFunc),
809 std::move(addMergerExecutorToDCFunc),
810 std::move(addLoopExecutorToDCFunc));
816 const auto& profilePtr =
819 std::thread([executorPtr, executorName, parameters, profilePtr]()
820 { executorPtr->run(executorName, parameters, profilePtr); })
827 .skillName = skill->name};
830 if (!skillDescr.has_value())
832 ARMARX_WARNING <<
"Skill description for skill with id '" << skillId
833 <<
"' not found. Aborting execution." << sID.
toString();
839 "SkillManagerComponentPlugin",
850 const auto& getSkillExecutionStatusFunc =
854 std::unique_lock l(fluxioDC.fluxioExecutorsMutex);
855 fluxioDC.fluxioExecutors[executionId] = std::make_unique<skills::FluxioNativeExecutor>(
859 std::move(abortSkillFunc),
860 std::move(executeSkillAsyncFunc),
861 std::move(getSkillExecutionStatusFunc));
867 const auto& profilePtr =
870 std::thread([executorPtr, executorName, parameters, profilePtr]()
871 { executorPtr->run(executorName, parameters, profilePtr); })
875 return {executorPtr};
881 std::shared_lock l(fluxioDC.fluxioExecutorsMutex);
882 const auto& executorIt = fluxioDC.fluxioExecutors.find(executionId);
883 if (executorIt == fluxioDC.fluxioExecutors.end())
885 ARMARX_WARNING <<
"Execution with id '" << executionId <<
"' not found.";
892 "SkillManagerComponentPlugin",
899 executorIt->second->abort();
905 std::shared_lock l(fluxioDC.fluxioExecutorsMutex);
906 const auto& executorIt = fluxioDC.fluxioExecutors.find(executionId);
907 if (executorIt == fluxioDC.fluxioExecutors.end())
909 ARMARX_WARNING <<
"Execution with id '" << executionId <<
"' not found.";
916 "SkillManagerComponentPlugin",
922 return {executorIt->second->getStatusUpdate().value()};
932 SkillManagerComponentPlugin::convertAronObjectPtrToFluxioParameters(
933 std::map<std::string, skills::FluxioParameter>& ret,
936 const boost::uuids::uuid& skillId)
938 for (
const auto& [name, typeInfo] : ptr->getMemberTypes())
942 const auto& seed = name + (isInput ?
"isInput" :
"isOutput");
943 p.
id = boost::uuids::to_string(createUuidWithString(seed, skillId));
949 p.
required = (typeInfo->getMaybe() == 0);
953 std::unique_lock l(fluxioDC.typesMutex);
954 fluxioDC.types[boost::uuids::to_string(skillId)]->addMemberType(p.
id, typeInfo);
961 SkillManagerComponentPlugin::createUuidWithString(
962 const std::string&
str,
963 std::optional<const boost::uuids::uuid> namespaceUUID)
965 boost::uuids::uuid nameS;
966 if (namespaceUUID.has_value())
968 nameS = namespaceUUID.value();
973 nameS = boost::uuids::nil_uuid();
977 boost::uuids::name_generator generator(nameS);
980 return generator(
str);
989 SkillManagerComponentPlugin::descriptionIdToFluxioSkill(
990 skills::SkillID skillId,
991 skills::SkillDescription skillDescription)
995 const auto& providerId = createUuidWithString(skillId.providerId->providerName);
996 const auto&
id = createUuidWithString(skillId.skillName, providerId);
998 std::unique_lock skillsLock(fluxioDC.skillsMutex);
999 auto skillsEntry = fluxioDC.skills.find(boost::uuids::to_string(
id));
1000 if (skillsEntry != fluxioDC.skills.end())
1002 skillsLock.unlock();
1006 skills::FluxioSkill
s;
1008 s.id = boost::uuids::to_string(
id);
1009 s.name = skillId.skillName;
1010 s.description = skillDescription.description;
1011 s.timeout = skillDescription.timeout;
1013 s.executable =
false;
1016 std::unique_lock providersLock(fluxioDC.providersMutex);
1017 const auto& providersEntry =
1018 fluxioDC.providers.find(boost::uuids::to_string(providerId));
1019 if (providersEntry != fluxioDC.providers.end())
1022 providersLock.unlock();
1026 providersLock.unlock();
1028 if (!res.isSuccess())
1031 << skillId.providerId->providerName <<
"'. Skill: '" <<
s.name
1032 <<
" with id: '" <<
s.id <<
"' will not be added.";
1033 skillsLock.unlock();
1036 const auto p = res.getResult();
1037 s.skillProviderPtr = p;
1039 std::unique_lock typesLock(fluxioDC.typesMutex);
1040 const auto& eventTypeIt = fluxioDC.types.find(
"BaseTypesNamespace");
1041 if (eventTypeIt == fluxioDC.types.end())
1043 ARMARX_WARNING <<
"Event type not found. Skill: '" <<
s.name <<
" with id: '"
1044 <<
s.id <<
"' will not be added.";
1046 skillsLock.unlock();
1050 const auto& eventType = eventTypeIt->second->getMemberType(
"Event");
1051 const skills::FluxioTypeIdentificator& eventTypeIdent = {
1052 .skillId =
"BaseTypesNamespace", .parameterId =
"Event"};
1054 skills::FluxioParameter start;
1055 start.name =
"Start";
1056 start.type = eventType;
1057 start.typeIdentificator = eventTypeIdent;
1058 const auto& startIdStr = start.name + start.type->getFullName() +
"isInput";
1059 start.id = boost::uuids::to_string(createUuidWithString(startIdStr,
id));
1060 start.description =
"Start the skill";
1061 start.required =
true;
1062 start.isInput =
true;
1064 skills::FluxioParameter succeeded;
1065 succeeded.name =
"Succeeded";
1066 succeeded.type = eventType;
1067 succeeded.typeIdentificator = eventTypeIdent;
1068 const auto& successIdStr = succeeded.name + succeeded.type->getFullName() +
"isOutput";
1069 succeeded.id = boost::uuids::to_string(createUuidWithString(successIdStr,
id));
1070 succeeded.description =
"Skill has been executed successfully";
1071 succeeded.required =
false;
1072 succeeded.isInput =
false;
1074 skills::FluxioParameter failed;
1075 failed.name =
"Failed";
1076 failed.type = eventType;
1077 failed.typeIdentificator = eventTypeIdent;
1078 const auto& failedIdStr = failed.name + failed.type->getShortName() +
"isOutput";
1079 failed.id = boost::uuids::to_string(createUuidWithString(failedIdStr,
id));
1080 failed.description =
"Skill has failed";
1081 failed.required =
false;
1082 failed.isInput =
false;
1084 skills::FluxioParameter aborted;
1085 aborted.name =
"Aborted";
1086 aborted.type = eventType;
1087 aborted.typeIdentificator = eventTypeIdent;
1088 const auto& abortedIdStr = aborted.name + aborted.type->getShortName() +
"isOutput";
1089 aborted.id = boost::uuids::to_string(createUuidWithString(abortedIdStr,
id));
1090 aborted.description =
"Skill has been aborted";
1091 aborted.required =
false;
1092 aborted.isInput =
false;
1094 s.parameters[start.id] = start;
1095 s.parameters[succeeded.id] = succeeded;
1096 s.parameters[failed.id] = failed;
1097 s.parameters[aborted.id] = aborted;
1099 const auto& parameters = std::make_shared<aron::type::Object>();
1101 if (fluxioDC.types.find(
s.id) == fluxioDC.types.end())
1103 fluxioDC.types[
s.id] = parameters;
1107 if (skillDescription.parametersType !=
nullptr)
1110 convertAronObjectPtrToFluxioParameters(
1111 s.parameters, skillDescription.parametersType,
true,
id);
1114 if (skillDescription.resultType !=
nullptr)
1117 convertAronObjectPtrToFluxioParameters(
1118 s.parameters, skillDescription.resultType,
false,
id);
1121 if (skillDescription.rootProfileDefaults !=
nullptr)
1125 for (
const auto& [k, v] : skillDescription.rootProfileDefaults->getElements())
1133 skills::FluxioValue val;
1134 val.profilePtr = rootProfilePtr;
1137 for (
const auto& [pId, param] :
s.parameters)
1139 if (param.name == k && param.isInput)
1141 s.parameters[pId].values.push_back(val);
1149 ARMARX_INFO <<
"No root profile defaults found for skill '" <<
s.name <<
"'.";
1152 fluxioDC.skills.emplace(
s.id, std::move(s));
1153 skillsLock.unlock();
1157 skills::Result<std::vector<std::experimental::observer_ptr<const skills::FluxioSkill>>,
1158 skills::error::FluxioException>
1161 return {convertMapValuesToObserverVector(fluxioDC.skills)};
1168 std::shared_lock l(fluxioDC.skillsMutex);
1169 const auto& skillsEntry = fluxioDC.skills.find(
id);
1170 if (skillsEntry == fluxioDC.skills.end())
1177 "SkillManagerComponentPlugin",
1187 std::optional<std::vector<std::experimental::observer_ptr<const skills::FluxioSkill>>>
1189 const std::string& userId,
1192 std::shared_lock l(fluxioDC.skillsMutex);
1193 const auto& skillIt = fluxioDC.skills.find(skillId);
1194 if (skillIt == fluxioDC.skills.end())
1196 ARMARX_WARNING <<
"Skill with id '" << skillId <<
"' not found.";
1198 return std::nullopt;
1202 if (skillIt->second.native)
1205 <<
"' is a native skill and cannot be deleted.";
1206 return std::nullopt;
1209 const auto& skillMutexResult =
getSkillMutex(skillId, userId);
1211 if (!skillMutexResult.isSuccess())
1213 ARMARX_WARNING <<
"User '" << userId <<
"' needs to acquire the mutex for skill '"
1214 << skillId <<
"' in order to delete it.";
1215 return std::nullopt;
1218 if (!skillMutexResult.getResult())
1220 ARMARX_WARNING <<
"User '" << userId <<
"' needs to acquire the mutex for skill '"
1221 << skillId <<
"' in order to delete it.";
1222 return std::nullopt;
1225 std::vector<std::experimental::observer_ptr<skills::FluxioSkill>> affectedSkills;
1226 std::vector<std::experimental::observer_ptr<const skills::FluxioSkill>> ret;
1228 for (
auto& [
id, s] : fluxioDC.skills)
1230 if (s.native || s.id == skillId)
1235 for (
const auto& [nodeId, node] : s.nodes)
1237 if (node ==
nullptr)
1246 const auto& subSkillNodeptr =
1248 if (subSkillNodeptr ==
nullptr)
1250 ARMARX_WARNING <<
"Error while casting node to FluxioSubSkillNode.";
1254 if (subSkillNodeptr->skillPtr !=
nullptr &&
1255 subSkillNodeptr->skillPtr->id == skillId)
1272 bool mutexesAquired =
true;
1273 for (
const auto& affectedSkill : affectedSkills)
1275 const auto& affectedMutexResult =
getSkillMutex(affectedSkill->id, userId);
1277 if (!affectedMutexResult.isSuccess() || !affectedMutexResult.getResult())
1279 mutexesAquired =
false;
1280 ARMARX_WARNING <<
"Someone else is editing the skill '" << affectedSkill->name
1281 <<
"(" << affectedSkill->id <<
")' right now.";
1288 for (
const auto& affectedSkill : affectedSkills)
1290 affectedSkill->removeSubSkillNodesAndEdges(skillId);
1293 ARMARX_WARNING <<
"Deleting skill '" << skillIt->second.name <<
"' (" << skillId
1295 std::unique_lock skillsLock(fluxioDC.skillsMutex);
1296 fluxioDC.skills.erase(skillId);
1297 skillsLock.unlock();
1302 <<
"Not all Mutexes for affected skills could be aquired. Aborting deletion.";
1306 for (
const auto& affectedSkill : affectedSkills)
1315 return std::nullopt;
1321 const std::string& parameterId,
1322 const std::string& userId,
1325 return updateFluxioParameter(skillId, parameterId, userId, dryRun,
true);
1331 const std::string& skillId,
1332 const skills::manager::dto::FluxioParameter& parameter,
1333 const std::string& userId,
1336 const auto& parameterId = parameter.id;
1337 return updateFluxioParameter(skillId, parameterId, userId, dryRun,
false, parameter);
1342 SkillManagerComponentPlugin::updateFluxioParameter(
1343 const std::string& skillId,
1344 const std::string& parameterId,
1345 const std::string& userId,
1347 bool deleteParameter,
1348 const std::optional<skills::manager::dto::FluxioParameter>& parameterDT)
1350 if (!deleteParameter && parameterDT == std::nullopt)
1352 ARMARX_WARNING <<
"Required parameter data transfer object not provided.";
1355 {
"parameter data transfer object"}),
1357 "SkillManagerComponentPlugin",
1363 const auto& res =
getSkill(skillId);
1364 if (!res.isSuccess())
1370 "SkillManagerComponentPlugin",
1374 const auto& skill = res.getResult();
1377 const auto& parameterIt = skill->parameters.find(parameterId);
1378 if (parameterIt == skill->parameters.end())
1384 "SkillManagerComponentPlugin",
1388 const auto& parameterOld = parameterIt->second;
1392 if (!mutexResult.isSuccess())
1394 return {mutexResult.getError()};
1398 std::vector<std::experimental::observer_ptr<skills::FluxioSkill>> affectedSkills;
1399 std::vector<std::experimental::observer_ptr<const skills::FluxioSkill>> ret;
1402 if (deleteParameter ||
1403 parameterOld.typeIdentificator.toManagerIce() != parameterDT.value().type ||
1404 parameterOld.isInput != parameterDT.value().isInput)
1406 std::shared_lock l(fluxioDC.skillsMutex);
1407 for (
auto& [
id, s] : fluxioDC.skills)
1409 if (
s.native ||
s.id == skillId)
1414 for (
const auto& e :
s.edges)
1416 if ((e.fromParameterPtr !=
nullptr && e.fromParameterPtr->id == parameterId) ||
1417 (e.toParameterPtr !=
nullptr && e.toParameterPtr->id == parameterId))
1434 bool mutexesAquired =
true;
1435 for (
const auto& affectedSkill : affectedSkills)
1437 const auto& affectedMutexResult =
getSkillMutex(affectedSkill->id, userId);
1439 if (!affectedMutexResult.isSuccess() || !affectedMutexResult.getResult())
1441 mutexesAquired =
false;
1442 ARMARX_WARNING <<
"Someone else is editing the skill '" << affectedSkill->name
1443 <<
"(" << affectedSkill->id <<
")' right now.";
1451 for (
const auto& affectedSkill : affectedSkills)
1453 affectedSkill->removeEdgesConnectedToParameter(parameterId);
1456 if (deleteParameter)
1458 ARMARX_WARNING <<
"Deleting skill parameter'" << parameterOld.name <<
"' ("
1459 << parameterId <<
").";
1460 std::unique_lock skillsLock(fluxioDC.skillsMutex);
1461 fluxioDC.skills[skillId].deleteParameter(parameterId);
1462 skillsLock.unlock();
1466 ARMARX_WARNING <<
"Updating skill parameter'" << parameterOld.name <<
"' ("
1467 << parameterId <<
").";
1468 std::scoped_lock l(fluxioDC.skillsMutex,
1469 fluxioDC.profilesMutex,
1470 fluxioDC.providersMutex,
1471 fluxioDC.typesMutex);
1472 auto& profilesMap = fluxioDC.profiles;
1473 auto& typesMap = fluxioDC.types;
1474 fluxioDC.skills[skillId].removeParameterNodesAndEdges(parameterId,
true);
1475 fluxioDC.skills[skillId].parameters[parameterId].updateFromIce(
1476 *parameterDT, profilesMap, typesMap);
1481 ARMARX_WARNING <<
"Not all Mutexes for affected skills could be aquired. Aborting "
1482 << (deleteParameter ?
"deletion" :
"update") <<
" of parameter.";
1486 for (
const auto& affectedSkill : affectedSkills)
1500 "SkillManagerComponentPlugin",
1505 skills::Result<bool, skills::error::FluxioException>
1507 const std::string& userId)
1509 return setEditFluxioSkillMutex(
true, userId, skillId);
1514 const std::string& userId)
1516 setEditFluxioSkillMutex(
false, userId,
1524 std::shared_lock l(fluxioDC.profilesMutex);
1525 const auto& ret = convertMapValuesToObserverVector(fluxioDC.profiles);
1533 std::shared_lock l(fluxioDC.profilesMutex);
1534 const auto& profilesEntry = fluxioDC.profiles.find(
id);
1536 if (profilesEntry == fluxioDC.profiles.end())
1542 "SkillManagerComponentPlugin",
1548 return {profilesEntry->second};
1561 "SkillManagerComponentPlugin",
1566 const auto& parentId = profile.
parentPtr->id;
1567 const auto& nameLowerCase = simox::alg::to_lower(profile.
name);
1569 std::unique_lock l(fluxioDC.profilesMutex);
1570 auto it = std::find_if(
1571 fluxioDC.profiles.begin(),
1572 fluxioDC.profiles.end(),
1573 [&parentId, &nameLowerCase](
const std::pair<std::string, skills::FluxioProfile>& p)
1575 return p.second.parentPtr != nullptr && p.second.parentPtr->id == parentId &&
1576 simox::alg::to_lower(p.second.name) == nameLowerCase;
1579 if (nameLowerCase ==
"root" || it != fluxioDC.profiles.end())
1587 "SkillManagerComponentPlugin",
1592 std::string
id = profile.
id;
1594 bool validId =
false;
1597 const auto& result = boost::uuids::string_generator()(id);
1598 validId = result.version() != boost::uuids::uuid::version_unknown;
1607 id = IceUtil::generateUUID();
1609 else if (fluxioDC.profiles.find(profile.
id) != fluxioDC.profiles.end())
1612 <<
"' is already taken. A new uuid will be generated.";
1613 id = IceUtil::generateUUID();
1620 fluxioDC.profiles[id] = profile;
1621 fluxioDC.profiles[id].
id = id;
1622 const auto& ret = fluxioDC.profiles[id];
1634 if (oldProfile.isSuccess() && oldProfile.getResult().id == profile.
id)
1636 std::unique_lock l(fluxioDC.profilesMutex);
1637 fluxioDC.profiles[profile.
id].name = profile.
name;
1638 fluxioDC.profiles[profile.
id].description = profile.
description;
1639 fluxioDC.profiles[profile.
id].parentPtr = profile.
parentPtr;
1652 const std::string& providerId = boost::uuids::to_string(createUuidWithString(name));
1654 std::unique_lock l(fluxioDC.providersMutex);
1655 if (fluxioDC.providers.find(providerId) != fluxioDC.providers.end())
1657 ARMARX_WARNING <<
"Provider with name '" << name <<
"' already exists.";
1666 fluxioDC.providers[p.
id] = p;
1677 for (
const auto& [providerID, providerPrx] : skillProviderMap)
1679 const auto&
id = boost::uuids::to_string(createUuidWithString(providerID.providerName));
1681 std::shared_lock l(fluxioDC.providersMutex);
1682 const auto& providersEntry = fluxioDC.providers.find(
id);
1684 if (providersEntry != fluxioDC.providers.end())
1694 return {convertMapValuesToObserverVector(fluxioDC.providers)};
1702 std::shared_lock l(fluxioDC.providersMutex);
1703 const auto& providersEntry = fluxioDC.providers.find(
id);
1705 if (providersEntry != fluxioDC.providers.end())
1708 return {providersEntry->second};
1715 "SkillManagerComponentPlugin",
1726 std::shared_lock l(fluxioDC.providersMutex);
1727 const auto& providersEntry = fluxioDC.providers.find(
id);
1729 if (providersEntry == fluxioDC.providers.end())
1735 "SkillManagerComponentPlugin",
1743 if (!res.isSuccess())
1745 auto e = res.getError();
1746 e.addToContext(std::nullopt,
"SkillManagerComponentPlugin", __FUNCTION__, __LINE__);
1750 auto allSkills = res.getResult();
1752 allSkills.erase(std::remove_if(allSkills.begin(),
1754 [
id](
const auto& skillPtr)
1755 { return skillPtr->skillProviderPtr->id != id; }),
1764 const std::string& providerId,
1767 std::shared_lock l(fluxioDC.providersMutex);
1768 const auto& providerIt = fluxioDC.providers.find(providerId);
1769 if (providerIt == fluxioDC.providers.end())
1771 ARMARX_WARNING <<
"Provider with id '" << providerId <<
"' not found.";
1777 "SkillManagerComponentPlugin",
1783 if (skill.id.empty())
1786 skill.id = IceUtil::generateUUID();
1793 boost::uuids::uuid uuid;
1796 boost::uuids::string_generator gen;
1797 uuid = gen(skill.id);
1799 catch (std::runtime_error& e)
1801 ARMARX_WARNING <<
"Could not convert skill id to uuid: " << e.what();
1802 skill.id = IceUtil::generateUUID();
1805 std::unique_lock typesLock(fluxioDC.typesMutex);
1806 const auto& eventType = fluxioDC.types[
"BaseTypesNamespace"]->getMemberType(
"Event");
1809 .parameterId =
"Event"};
1813 start.
name =
"Start";
1814 start.
id = boost::uuids::to_string(createUuidWithString(start.
name, uuid));
1816 start.
type = eventType;
1822 succeeded.
name =
"Succeeded";
1823 succeeded.
id = boost::uuids::to_string(createUuidWithString(succeeded.
name, uuid));
1824 succeeded.
description =
"Skill has been executed successfully";
1825 succeeded.
type = eventType;
1831 failed.
name =
"Failed";
1832 failed.
id = boost::uuids::to_string(createUuidWithString(failed.
name, uuid));
1834 failed.
type = eventType;
1840 aborted.
name =
"Aborted";
1841 aborted.
id = boost::uuids::to_string(createUuidWithString(aborted.
name, uuid));
1843 aborted.
type = eventType;
1848 skill.parameters[start.
id] = start;
1849 skill.parameters[succeeded.
id] = succeeded;
1850 skill.parameters[failed.
id] = failed;
1851 skill.parameters[aborted.
id] = aborted;
1856 const auto skillId = skill.id;
1857 std::unique_lock skillsLock(fluxioDC.skillsMutex);
1858 fluxioDC.skills.emplace(skillId, std::move(skill));
1860 skillsLock.unlock();
1863 setEditFluxioSkillMutex(
true, userId, skill.id);
1868 SkillManagerComponentPlugin::setEditFluxioSkillMutex(
bool aquireMutex,
1869 const std::string& userId,
1870 const std::string& skillId)
1872 std::scoped_lock l(fluxioDC.skillMutexMapMutex);
1873 const auto& skillMutexIt = fluxioDC.skillMutexMap.find(skillId);
1878 if (skillMutexIt == fluxioDC.skillMutexMap.end())
1886 if (std::get<0>(fluxioDC.skillMutexMap[skillId]) == userId)
1896 if (elapsedTime.
toMinutes() > fluxioDC.mutexTimeout)
1908 "SkillManagerComponentPlugin",
1915 if (skillMutexIt == fluxioDC.skillMutexMap.end())
1924 if (std::get<0>(fluxioDC.skillMutexMap[skillId]) == userId)
1926 fluxioDC.skillMutexMap.erase(skillId);
1935 "SkillManagerComponentPlugin",
1944 auto ret = std::make_shared<aron::type::Object>();
1946 std::vector<std::experimental::observer_ptr<const skills::FluxioSkill>>,
1949 if (!res.isSuccess())
1955 std::shared_lock l(fluxioDC.typesMutex);
1956 for (
const auto& [skillId, skillTypes] : fluxioDC.types)
1958 if (skillTypes ==
nullptr)
1960 ARMARX_WARNING <<
"SkillTypes with id '" << skillId <<
"' not found.";
1963 ret->addMemberType(skillId, skillTypes);
1966 ret->setObjectName(
"SkillTypes");
ManagedIceObject & parent()
static nlohmann::json ConvertToNlohmannJSON(const data::VariantPtr &)
std::string toDateTimeString() const
std::int64_t toMinutes() const
Returns the amount of minutes.
std::map< skills::SkillID, skills::SkillDescription > getSkillDescriptions()
bool abortSkill(const skills::SkillExecutionID &id)
aron::type::ObjectPtr getTypes()
skills::SkillStatusUpdate executeSkill(const skills::SkillExecutionRequest &req)
skills::Result< std::vector< std::experimental::observer_ptr< const skills::FluxioSkill > >, skills::error::FluxioException > getSkillList()
skills::SkillExecutionID executeSkillAsync(const skills::SkillExecutionRequest &req)
skills::Result< std::vector< std::experimental::observer_ptr< const skills::FluxioProfile > >, skills::error::FluxioException > getProfileList()
void preOnInitComponent() override
void updateProfile(const skills::FluxioProfile &profile)
skills::ProviderID getFirstProviderNameThatHasSkill(const skills::SkillID &skillid)
skills::Result< std::vector< std::experimental::observer_ptr< const skills::FluxioSkill > >, skills::error::FluxioException > deleteSkillParameter(const std::string &skillId, const std::string ¶meterId, const std::string &userId, bool dryRun)
skills::Result< std::vector< std::experimental::observer_ptr< const skills::FluxioSkill > >, skills::error::FluxioException > updateSkillParameter(const std::string &skillId, const skills::manager::dto::FluxioParameter ¶meter, const std::string &userId, bool dryRun)
void preOnConnectComponent() override
skills::Result< std::experimental::observer_ptr< skills::FluxioExecutor >, skills::error::FluxioException > executeFluxioSkill(const std::string &skillId, const std::string &profileId, const std::string &executorName, armarx::aron::data::DictPtr parameters=nullptr)
skills::Result< std::experimental::observer_ptr< const skills::FluxioProvider >, skills::error::FluxioException > addFluxioProvider(const std::string &name)
void removeProvider(const skills::ProviderID &id)
void deleteSkillMutex(const std::string &skillId, const std::string &userId)
skills::Result< std::experimental::observer_ptr< const skills::FluxioSkill >, skills::error::FluxioException > addSkillToProvider(const std::string &userId, const std::string &providerId, skills::FluxioSkill &&skill)
skills::Result< std::vector< std::experimental::observer_ptr< const skills::FluxioProvider > >, skills::error::FluxioException > getProviderList()
void postCreatePropertyDefinitions(PropertyDefinitionsPtr &properties) override
skills::Result< std::experimental::observer_ptr< const skills::FluxioSkill >, skills::error::FluxioException > getSkill(const std::string &id)
void addProvider(const skills::ProviderInfo &info)
bool updateSkillParameters(const skills::SkillExecutionID &id, const aron::data::DictPtr &data)
std::optional< skills::SkillStatusUpdate > getSkillExecutionStatus(const skills::SkillExecutionID &id)
skills::Result< std::vector< skills::FluxioSkillStatusUpdate >, skills::error::FluxioException > getFluxioSkillExecutionStatus(const std::string &executionId)
skills::Result< skills::FluxioProvider, skills::error::FluxioException > getProvider(const std::string &id)
bool abortSkillAsync(const skills::SkillExecutionID &id)
skills::Result< skills::FluxioProfile, skills::error::FluxioException > getProfile(const std::string &id)
std::map< skills::SkillExecutionID, skills::SkillStatusUpdate > getSkillExecutionStatuses()
skills::Result< bool, skills::error::FluxioException > getSkillMutex(const std::string &skillId, const std::string &userId)
std::optional< skills::SkillDescription > getSkillDescription(const skills::SkillID &id)
std::optional< std::vector< std::experimental::observer_ptr< const skills::FluxioSkill > > > deleteSkill(const std::string &skillId, const std::string &userId, bool dryRun)
void abortFluxioSkill(const std::string &executionId)
skills::Result< skills::FluxioProfile, skills::error::FluxioException > createProfile(const skills::FluxioProfile &profile)
skills::Result< std::vector< std::experimental::observer_ptr< const skills::FluxioSkill > >, skills::error::FluxioException > getSkillsOfProvider(const std::string &id)
std::string toString() const
provider::dti::SkillProviderInterfacePrx providerInterface
std::map< SkillID, SkillDescription > providedSkills
armarx::aron::data::DictPtr parameters
std::string toString() const
std::optional< ProviderID > providerId
bool isFullySpecified() const
provider::dto::SkillID toProviderIce() const
static SkillID FromIce(const manager::dto::SkillID &)
A base class for skill exceptions.
static FluxioException create(const std::string &message, const FluxioExceptionType &type, const std::string &className, const char *function, int line)
A base class for skill exceptions.
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_INFO
The normal logging level.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
std::shared_ptr< Dict > DictPtr
std::shared_ptr< Object > ObjectPtr
double s(double t, double s0, double v0, double a0, double j)
double v(double t, double v0, double a0, double j)
This file is part of ArmarX.
std::string createErrorMessage(ErrorCode code, const std::vector< std::string > &args)
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
observer_ptr< _Tp > make_observer(_Tp *__p) noexcept
aron::type::VariantPtr type
FluxioTypeIdentificator typeIdentificator
std::experimental::observer_ptr< const FluxioProfile > parentPtr
static SkillDescription FromIce(const provider::dto::SkillDescription &i, const std::optional< ProviderID > &=std::nullopt)
skills::provider::dto::SkillExecutionID toProviderIce() const
static SkillExecutionID FromIce(const skills::manager::dto::SkillExecutionID &)
static SkillStatusUpdate FromIce(const provider::dto::SkillStatusUpdate &update, const std::optional< skills::ProviderID > &providerId=std::nullopt)