Newer
Older
#include <mutex>
#include "RobotAPI/libraries/skills/core/SkillExecutionRequest.h"
using StatusMap = std::map<skills::SkillExecutionID, skills::SkillStatusUpdate>;
using SkillMap =
std::map<skills::ProviderID, std::map<skills::SkillID, skills::SkillDescription>>;
SkillManagerWrapper::fetchExecutionsFromMemory()
if (!memory)
{
// check if null
return {};
}
try
{
std::scoped_lock l(mutex_memory);
// we return this map
StatusMap statusMap;
auto currentManagerStatuses = memory->ice_invocationTimeout(10000)->getSkillExecutionStatuses();
// iterate over raw data and convert to common types
for (const auto& [k, v] : currentManagerStatuses)
{
auto executionId = skills::SkillExecutionID::FromIce(k);
auto statusUpdate = skills::SkillStatusUpdate::FromIce(v);
// update maps
statusMap[executionId] = statusUpdate;
}
catch (Ice::Exception const& e)
{
ARMARX_WARNING
<< "Unhandled Ice exception encountered while updating executions. Exception was: "
<< e;
emit connectionUpdate("Could not fetch executions", e.what());
emit disableAutoUpdate();
}
catch (...)
{
ARMARX_WARNING << "Unknown exception encountered while updating executions.";
// check if search strings occur in the skill name in order
bool
matches(std::string skillName, std::vector<std::string>& searches)
{
size_t index = 0;
for (std::string& substring : searches)
{
size_t occurance = skillName.find(substring, index);
if (occurance == std::string::npos)
// we found an occurance
index = occurance;
}
return true;
}
SkillManagerWrapper::Snapshot
SkillManagerWrapper::filterUpdate(Snapshot update)
{
// empty search => do not filter
if (this->currentSkillSearch.empty())
{
Snapshot filtered;
// for now we don't change the executions
filtered.statuses = update.statuses;
std::vector<std::string> substrings;
std::vector<std::string> rawSubstrings = simox::alg::split(currentSkillSearch);
for (auto& string : rawSubstrings)
{
substrings.push_back(simox::alg::to_lower(string));
}
for (auto& provider_and_descrMap : update.skills)
using DescriptionMap = std::map<skills::SkillID, skills::SkillDescription>;
DescriptionMap& descriptionMap = provider_and_descrMap.second;
skills::ProviderID provider = provider_and_descrMap.first;
for (auto& skill_and_description : descriptionMap)
skills::SkillID sid = skill_and_description.first;
skills::SkillDescription descr = skill_and_description.second;
if (matches(simox::alg::to_lower(sid.skillName), substrings))
{
// add to map
filtered.skills[provider][sid] = descr;
}
SkillMap
SkillManagerWrapper::fetchSkillsFromMemory()
}
try
{
std::scoped_lock l(mutex_memory);
auto managerSkills = memory->ice_invocationTimeout(5000)->getSkillDescriptions();
for (const auto& [sid, desc] : managerSkills)
{
auto description = skills::SkillDescription::FromIce(desc);
auto skillId = skills::SkillID::FromIce(sid);
auto providerId = skillId.providerId.value_or(
skills::ProviderID{.providerName = "UNKNOWN PROVIDER NAME"});
ARMARX_CHECK(skillId.isFullySpecified());
auto& providedSkillsMap = skills[providerId]; // create new if not existing
providedSkillsMap.insert({skillId, description});
}
}
catch (Ice::Exception const& e)
{
ARMARX_WARNING
<< "Unhandled Ice exception encountered while updating skills. Exception was: "
<< e;
emit connectionUpdate("Could not fetch skills", e.what());
emit disableAutoUpdate();
}
catch (...)
{
ARMARX_WARNING << "Unknown exception encountered while updating skills.";
SkillManagerWrapper::connectMemory(
skills::manager::dti::SkillManagerInterfacePrx const& updatedMemory)
{
std::scoped_lock l(mutex_memory);
this->memory = updatedMemory;
}
void
SkillManagerWrapper::disconnectMemory()
{
std::scoped_lock l(mutex_memory);
this->memory = nullptr;
}
SkillManagerWrapper::acceptSearchRequest(std::string const& search)
void
SkillManagerWrapper::stopAllExecutions()
{
ARMARX_IMPORTANT << "Stopping all running executions.";
StatusMap executions;
// we ALWAYS want the newest information when stopping all!
// e.g. there is some new skill not known to the GUI which we explicitely want to stop too.
// the stop-all function is often used in an emergency, so we'll live with the extra call...
try
{
executions = this->fetchExecutionsFromMemory();
}
catch (...) // if any error occurs, we use the snapshot as backup. better to miss a skill
// than to not do anything.
{
executions = this->getExecutions();
}
for (auto& [executionId, status] : executions)
{
// select all running executions...
if (!status.hasBeenTerminated())
{
// ... and kill them.
this->stopExecution(executionId, 3);
}
}
}
void
SkillManagerWrapper::updateFromMemory()
std::scoped_lock l(mutex_snapshot);
snapshot.skills = fetchSkillsFromMemory();
snapshot.statuses = fetchExecutionsFromMemory();
// notify registered widgets of update
emit updateAvailable(filterUpdate(snapshot));
const std::optional<ProviderID>
SkillManagerWrapper::findFirstProvider(SkillMap const& map, SkillID const& skillId)
{
// check if id already contains a provider. If so, this function should not have been called!
if (skillId.isProviderSpecified())
{
ARMARX_WARNING << "The memory snapshot was searched for any provider, when a provider "
"was specified.";
// we continue, but this might result in unexpected behaviour...
}
for (auto& [prov, skillMap] : map)
{
for (auto& [skill, desc] : skillMap)
{
if (skill == skillId)
{
return prov;
}
}
}
return std::nullopt;
}
SkillMap
SkillManagerWrapper::getSkills()
{
std::scoped_lock l(mutex_snapshot);
Snapshot filtered = filterUpdate(snapshot);
return filtered.skills;
}
StatusMap
SkillManagerWrapper::getExecutions()
{
std::scoped_lock l(mutex_snapshot);
return snapshot.statuses;
}
void
SkillManagerWrapper::stopExecution(skills::SkillExecutionID const& executionId,
{
// memory???
if (!memory)
{
return;
}
unsigned int retries = max_retries;
bool retry = false;
do
{
try
{
ARMARX_INFO << "Aborting skill '" << executionId.skillId.skillName << "'...";
std::scoped_lock l(mutex_memory);
this->memory->ice_invocationTimeout(5000)->abortSkillAsync(executionId.toManagerIce());
}
catch (Ice::Exception const& e)
{
retry = true;
ARMARX_ERROR << "Unhandeled Ice exception while aborting skill '"
<< executionId.skillId.skillName << "'.";
emit connectionUpdate("Could not abort skill " + executionId.skillId.skillName,
e.what());
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
}
catch (...)
{
retry = true;
ARMARX_ERROR << "Unhandled error while aborting skill '"
<< executionId.skillId.skillName << "'.";
}
if (retry)
{
retries -= 1;
if (retries > 0)
{
ARMARX_WARNING << "There where errors aborting skills. Retrying...";
}
else
{
ARMARX_ERROR << "Couldn't abort all skills after " << max_retries
<< " tries. Giving up.";
retry = false;
}
}
} while (retry);
}
void
SkillManagerWrapper::startExecutionWithParams(skills::SkillID& skillId,
aron::data::DictPtr const params)
{
// Memory???
if (!memory)
{
return;
}
auto providerId = skillId.providerId;
if (!providerId.has_value())
{
ARMARX_IMPORTANT << "The skill: '" << skillId.skillName
<< "' has been requested to be executed, but no provider was "
"given. Aborting...";
return;
}
std::map<skills::SkillID, skills::SkillDescription> skillDescriptions;
if (this->UPDATE_ON_EXECUTION_REQUEST)
{
skillDescriptions = this->fetchSkillsFromMemory().at(providerId.value());
}
else
skillDescriptions = this->getSkills().at(providerId.value());
if (skillDescriptions.find(skillId) == skillDescriptions.end())
{
ARMARX_IMPORTANT << "The Skill: '" << skillId.skillName
<< "' has been requested to be executed, but no skill description was "
"found. Aborting...";
return;
}
char hostname[HOST_NAME_MAX];
gethostname(hostname, HOST_NAME_MAX);
skills::SkillExecutionRequest req{
.skillId = skillId,
.executorName = "Skills.Manager GUI (hostname: " + std::string(hostname) + ")",
.parameters = params};
ARMARX_CHECK(skillId.isFullySpecified()); // sanity check
ARMARX_IMPORTANT << "Executing skill from GUI: " << skillId << ".";
try
{
std::scoped_lock l(mutex_memory);
memory->ice_invocationTimeout(5000)->executeSkillAsync(req.toManagerIce());
}
catch (Ice::Exception const& e)
{
ARMARX_ERROR << "Unhandeled Ice exception while executing skill '" << skillId.skillName
<< "'. Aborting...";
emit connectionUpdate("Execution failed of skill " + skillId.skillName, e.what());
}
catch (...)
{
ARMARX_ERROR << "Unhandled error while executing skill '" << skillId.skillName
<< "'. Aborting...";
}
}