SkillManagerWrapper.cpp
Go to the documentation of this file.
1 #include "SkillManagerWrapper.h"
2 
3 #include <mutex>
4 
6 
7 namespace armarx::skills::gui
8 {
9  using StatusMap = std::map<skills::SkillExecutionID, skills::SkillStatusUpdate>;
10  using SkillMap =
11  std::map<skills::ProviderID, std::map<skills::SkillID, skills::SkillDescription>>;
12 
13  StatusMap
14  SkillManagerWrapper::fetchExecutionsFromMemory()
15  {
16  if (!memory)
17  {
18  // check if null
19  return {};
20  }
21 
22  try
23  {
24  std::scoped_lock l(mutex_memory);
25 
26  // we return this map
27  StatusMap statusMap;
28 
29  auto currentManagerStatuses = memory->getSkillExecutionStatuses();
30 
31  // iterate over raw data and convert to common types
32  for (const auto& [k, v] : currentManagerStatuses)
33  {
34  auto executionId = skills::SkillExecutionID::FromIce(k);
35  auto statusUpdate = skills::SkillStatusUpdate::FromIce(v);
36 
37  // update maps
38  statusMap[executionId] = statusUpdate;
39  }
40  return statusMap;
41  }
42  catch (Ice::Exception const& e)
43  {
45  << "Unhandled Ice exception encountered while updating executions. Exception was: "
46  << e;
47  emit connectionUpdate("Could not fetch executions", e.what());
48  return {};
49  }
50  catch (...)
51  {
52  ARMARX_WARNING << "Unknown exception encountered while updating executions.";
53  return {};
54  }
55  }
56 
57  // check if search strings occur in the skill name in order
58  bool
59  matches(std::string skillName, std::vector<std::string>& searches)
60  {
61  size_t index = 0;
62  for (std::string& substring : searches)
63  {
64  size_t occurance = skillName.find(substring, index);
65  if (occurance == std::string::npos)
66  {
67  return false;
68  }
69 
70 
71  // we found an occurance
72  index = occurance;
73  }
74  return true;
75  }
76 
77  SkillManagerWrapper::Snapshot
78  SkillManagerWrapper::filterUpdate(Snapshot update)
79  {
80  // empty search => do not filter
81  if (this->currentSkillSearch.empty())
82  {
83  return update;
84  }
85 
86  Snapshot filtered;
87 
88  // for now we don't change the executions
89  filtered.statuses = update.statuses;
90 
91  std::vector<std::string> substrings;
92 
93  {
94  std::vector<std::string> rawSubstrings = simox::alg::split(currentSkillSearch);
95  for (auto& string : rawSubstrings)
96  {
97  substrings.push_back(simox::alg::to_lower(string));
98  }
99  }
100 
101 
102  for (auto& provider_and_descrMap : update.skills)
103  {
104  using DescriptionMap = std::map<skills::SkillID, skills::SkillDescription>;
105 
106  DescriptionMap& descriptionMap = provider_and_descrMap.second;
107  skills::ProviderID provider = provider_and_descrMap.first;
108 
109  for (auto& skill_and_description : descriptionMap)
110  {
111  skills::SkillID sid = skill_and_description.first;
112  skills::SkillDescription descr = skill_and_description.second;
113 
114  if (matches(simox::alg::to_lower(sid.skillName), substrings))
115  {
116  // add to map
117  filtered.skills[provider][sid] = descr;
118  }
119  }
120  }
121 
122  return filtered;
123  }
124 
125  SkillMap
126  SkillManagerWrapper::fetchSkillsFromMemory()
127  {
128  if (!memory)
129  {
130  return {};
131  }
132 
133  try
134  {
135  std::scoped_lock l(mutex_memory);
136 
138 
139  auto managerSkills = memory->getSkillDescriptions();
140 
141  for (const auto& [sid, desc] : managerSkills)
142  {
143  auto description = skills::SkillDescription::FromIce(desc);
144  auto skillId = skills::SkillID::FromIce(sid);
145  auto providerId = skillId.providerId.value_or(
146  skills::ProviderID{.providerName = "UNKNOWN PROVIDER NAME"});
147 
148  ARMARX_CHECK(skillId.isFullySpecified());
149 
150  auto& providedSkillsMap = skills[providerId]; // create new if not existing
151  providedSkillsMap.insert({skillId, description});
152  }
153 
154  return skills;
155  }
156  catch (Ice::Exception const& e)
157  {
159  << "Unhandled Ice exception encountered while updating skills. Exception was: "
160  << e;
161  emit connectionUpdate("Could not fetch skills", e.what());
162  return {};
163  }
164  catch (...)
165  {
166  ARMARX_WARNING << "Unknown exception encountered while updating skills.";
167  return {};
168  }
169  }
170 
171  void
173  skills::manager::dti::SkillManagerInterfacePrx const& updatedMemory)
174  {
175  std::scoped_lock l(mutex_memory);
176  this->memory = updatedMemory;
177  }
178 
179  void
181  {
182  // clear memory
183 
184  std::scoped_lock l(mutex_memory);
185  this->memory = nullptr;
186  }
187 
188  void
189  SkillManagerWrapper::acceptSearchRequest(std::string const& search)
190  {
191  this->currentSkillSearch = search;
192  emit searchAccepted();
193  }
194 
195  void
197  {
198  ARMARX_IMPORTANT << "Stopping all running executions.";
199 
200  StatusMap executions;
201 
202  // we ALWAYS want the newest information when stopping all!
203  // e.g. there is some new skill not known to the GUI which we explicitely want to stop too.
204  // the stop-all function is often used in an emergency, so we'll live with the extra call...
205  try
206  {
207  executions = this->fetchExecutionsFromMemory();
208  }
209  catch (...) // if any error occurs, we use the snapshot as backup. better to miss a skill
210  // than to not do anything.
211  {
212  executions = this->getExecutions();
213  }
214 
215  for (auto& [executionId, status] : executions)
216  {
217  // select all running executions...
218  if (!status.hasBeenTerminated())
219  {
220  // ... and kill them.
221  this->stopExecution(executionId, 3);
222  }
223  }
224  }
225 
226  void
228  {
229  std::scoped_lock l(mutex_snapshot);
230 
231  snapshot.statuses = fetchExecutionsFromMemory();
232  snapshot.skills = fetchSkillsFromMemory();
233 
234  // notify registered widgets of update
235  emit updateAvailable(filterUpdate(snapshot));
236  }
237 
238  const std::optional<ProviderID>
240  {
241  // check if id already contains a provider. If so, this function should not have been called!
242  if (skillId.isProviderSpecified())
243  {
244  ARMARX_WARNING << "The memory snapshot was searched for any provider, when a provider "
245  "was specified.";
246  // we continue, but this might result in unexpected behaviour...
247  }
248 
249  for (auto& [prov, skillMap] : map)
250  {
251  for (auto& [skill, desc] : skillMap)
252  {
253  if (skill == skillId)
254  {
255  return prov;
256  }
257  }
258  }
259  return std::nullopt;
260  }
261 
262  SkillMap
264  {
265  std::scoped_lock l(mutex_snapshot);
266 
267  Snapshot filtered = filterUpdate(snapshot);
268 
269  return filtered.skills;
270  }
271 
272  StatusMap
274  {
275  std::scoped_lock l(mutex_snapshot);
276  return snapshot.statuses;
277  }
278 
279  void
281  const unsigned int max_retries)
282  {
283  // memory???
284  if (!memory)
285  {
286  return;
287  }
288 
289  unsigned int retries = max_retries;
290  bool retry = false;
291 
292  do
293  {
294  try
295  {
296  ARMARX_INFO << "Aborting skill '" << executionId.skillId.skillName << "'...";
297  std::scoped_lock l(mutex_memory);
298  this->memory->abortSkillAsync(executionId.toManagerIce());
299  }
300  catch (Ice::Exception const& e)
301  {
302  retry = true;
303  ARMARX_ERROR << "Unhandeled Ice exception while aborting skill '"
304  << executionId.skillId.skillName << "'.";
305  emit connectionUpdate("Could not abort skill " + executionId.skillId.skillName,
306  e.what());
307  }
308  catch (...)
309  {
310  retry = true;
311  ARMARX_ERROR << "Unhandled error while aborting skill '"
312  << executionId.skillId.skillName << "'.";
313  }
314 
315  if (retry)
316  {
317  retries -= 1;
318 
319  if (retries > 0)
320  {
321  ARMARX_WARNING << "There where errors aborting skills. Retrying...";
322  }
323  else
324  {
325  ARMARX_ERROR << "Couldn't abort all skills after " << max_retries
326  << " tries. Giving up.";
327  retry = false;
328  }
329  }
330  } while (retry);
331  }
332 
333  void
335  aron::data::DictPtr const params)
336  {
337  // Memory???
338  if (!memory)
339  {
340  return;
341  }
342 
343  auto providerId = skillId.providerId;
344  if (!providerId.has_value())
345  {
346  ARMARX_IMPORTANT << "The skill: '" << skillId.skillName
347  << "' has been requested to be executed, but no provider was "
348  "given. Aborting...";
349  return;
350  }
351 
352  std::map<skills::SkillID, skills::SkillDescription> skillDescriptions;
353  if (this->UPDATE_ON_EXECUTION_REQUEST)
354  {
355  skillDescriptions = this->fetchSkillsFromMemory().at(providerId.value());
356  }
357  else
358  {
359  skillDescriptions = this->getSkills().at(providerId.value());
360  }
361 
362  if (skillDescriptions.find(skillId) == skillDescriptions.end())
363  {
364  ARMARX_IMPORTANT << "The Skill: '" << skillId.skillName
365  << "' has been requested to be executed, but no skill description was "
366  "found. Aborting...";
367  return;
368  }
369 
370  char hostname[HOST_NAME_MAX];
371  gethostname(hostname, HOST_NAME_MAX);
372 
374  .skillId = skillId,
375  .executorName = "Skills.Manager GUI (hostname: " + std::string(hostname) + ")",
376  .parameters = params};
377 
378  ARMARX_CHECK(skillId.isFullySpecified()); // sanity check
379  ARMARX_IMPORTANT << "Executing skill from GUI: " << skillId << ".";
380 
381  try
382  {
383  std::scoped_lock l(mutex_memory);
384  memory->executeSkillAsync(req.toManagerIce());
385  }
386  catch (Ice::Exception const& e)
387  {
388  ARMARX_ERROR << "Unhandeled Ice exception while executing skill '" << skillId.skillName
389  << "'. Aborting...";
390  emit connectionUpdate("Execution failed of skill " + skillId.skillName, e.what());
391  }
392  catch (...)
393  {
394  ARMARX_ERROR << "Unhandled error while executing skill '" << skillId.skillName
395  << "'. Aborting...";
396  }
397  }
398 
399 
400 } // namespace armarx::skills::gui
armarx::skills::SkillExecutionID
Definition: SkillExecutionID.h:19
skills
This file is part of ArmarX.
armarx::skills::gui::SkillManagerWrapper::startExecutionWithParams
void startExecutionWithParams(skills::SkillID &skillId, aron::data::DictPtr const params)
Attempts to start an execution with given parameters.
Definition: SkillManagerWrapper.cpp:334
armarx::skills::gui::SkillManagerWrapper::updateAvailable
void updateAvailable(Snapshot update)
ARMARX_IMPORTANT
#define ARMARX_IMPORTANT
Definition: Logging.h:183
armarx::skills::SkillStatusUpdate::FromIce
static SkillStatusUpdate FromIce(const provider::dto::SkillStatusUpdate &update, const std::optional< skills::ProviderID > &providerId=std::nullopt)
Definition: SkillStatusUpdate.cpp:367
armarx::skills::gui::SkillManagerWrapper::updateFromMemory
void updateFromMemory()
Requests this wrapper to overwrite its own state from memory.
Definition: SkillManagerWrapper.cpp:227
armarx::skills::SkillExecutionRequest::skillId
skills::SkillID skillId
Definition: SkillExecutionRequest.h:33
index
uint8_t index
Definition: EtherCATFrame.h:59
armarx::skills::gui::StatusMap
std::map< skills::SkillExecutionID, skills::SkillStatusUpdate > StatusMap
Definition: SkillExecutionTreeWidget.h:12
armarx::skills::SkillID::skillName
std::string skillName
Definition: SkillID.h:60
armarx::skills::gui::SkillManagerWrapper::disconnectMemory
void disconnectMemory()
Disconnects the interface from memory.
Definition: SkillManagerWrapper.cpp:180
armarx::skills::gui::SkillManagerWrapper::connectionUpdate
void connectionUpdate(std::string const &message, std::string const &error)
armarx::skills::SkillID::providerId
std::optional< ProviderID > providerId
Definition: SkillID.h:59
armarx::skills::gui::SkillManagerWrapper::searchAccepted
void searchAccepted()
armarx::memory
Brief description of class memory.
Definition: memory.h:39
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
armarx::skills::gui::SkillManagerWrapper::findFirstProvider
static const std::optional< skills::ProviderID > findFirstProvider(SkillMap const &map, SkillID const &skillId)
Definition: SkillManagerWrapper.cpp:239
armarx::skills::SkillID::isProviderSpecified
bool isProviderSpecified() const
Definition: SkillID.h:41
armarx::skills::SkillExecutionID::toManagerIce
skills::manager::dto::SkillExecutionID toManagerIce() const
Definition: SkillExecutionID.cpp:9
SkillManagerWrapper.h
armarx::skills::gui::SkillManagerWrapper::getExecutions
StatusMap getExecutions()
Returns the latest status snapshot.
Definition: SkillManagerWrapper.cpp:273
armarx::skills::SkillExecutionRequest
Definition: SkillExecutionRequest.h:21
armarx::skills::gui::SkillManagerWrapper::Snapshot
Definition: SkillManagerWrapper.h:70
armarx::status
status
Definition: FiniteStateMachine.h:259
armarx::skills::gui::SkillManagerWrapper::Snapshot::skills
SkillMap skills
Definition: SkillManagerWrapper.h:73
armarx::skills::gui::SkillMap
std::map< skills::ProviderID, std::map< skills::SkillID, skills::SkillDescription > > SkillMap
Definition: SkillManagerWrapper.cpp:11
armarx::skills::SkillID::FromIce
static SkillID FromIce(const manager::dto::SkillID &)
Definition: SkillID.cpp:32
armarx::skills::gui
Definition: PeriodicUpdateWidget.cpp:11
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:189
SkillExecutionRequest.h
armarx::armem::server::ltm::util::mongodb::detail::update
bool update(mongocxx::collection &coll, const nlohmann::json &query, const nlohmann::json &update)
Definition: mongodb.cpp:67
armarx::aron::data::DictPtr
std::shared_ptr< Dict > DictPtr
Definition: Dict.h:41
armarx::ctrlutil::v
double v(double t, double v0, double a0, double j)
Definition: CtrlUtil.h:39
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174
armarx::skills::gui::matches
bool matches(std::string skillName, std::vector< std::string > &searches)
Definition: SkillManagerWrapper.cpp:59
armarx::skills::SkillExecutionID::skillId
SkillID skillId
Definition: SkillExecutionID.h:21
armarx::skills::SkillExecutionID::FromIce
static SkillExecutionID FromIce(const skills::manager::dto::SkillExecutionID &)
Definition: SkillExecutionID.cpp:29
armarx::skills::gui::SkillManagerWrapper::Snapshot::statuses
StatusMap statuses
Definition: SkillManagerWrapper.h:72
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:186
armarx::skills::gui::SkillManagerWrapper::stopAllExecutions
void stopAllExecutions()
Stops all available (and running) executions.
Definition: SkillManagerWrapper.cpp:196
armarx::skills::SkillDescription::FromIce
static SkillDescription FromIce(const provider::dto::SkillDescription &i, const std::optional< ProviderID > &=std::nullopt)
Definition: SkillDescription.cpp:39
armarx::skills::SkillID
Definition: SkillID.h:17
armarx::skills::SkillID::isFullySpecified
bool isFullySpecified() const
Definition: SkillID.h:29
armarx::skills::gui::SkillManagerWrapper::getSkills
SkillMap getSkills()
Returns the latest skills snapshot.
Definition: SkillManagerWrapper.cpp:263
armarx::skills::gui::SkillManagerWrapper::acceptSearchRequest
void acceptSearchRequest(std::string const &search)
Applies the search word to the update filter.
Definition: SkillManagerWrapper.cpp:189
armarx::skills::gui::SkillManagerWrapper::connectMemory
void connectMemory(skills::manager::dti::SkillManagerInterfacePrx const &updatedMemory)
Updates the memory pointer.
Definition: SkillManagerWrapper.cpp:172
armarx::split
std::vector< std::string > split(const std::string &source, const std::string &splitBy, bool trimElements=false, bool removeEmptyElements=false)
Definition: StringHelpers.cpp:36
armarx::skills::gui::SkillManagerWrapper::stopExecution
void stopExecution(skills::SkillExecutionID const &executionId, const unsigned int max_retries=0)
Attempts to stop an execution.
Definition: SkillManagerWrapper.cpp:280