10#include <shared_mutex>
14#include <unordered_map>
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/Optional.h>
26#include <nlohmann/json.hpp>
27#include <nlohmann/json_fwd.hpp>
36#include <RobotAPI/interface/skills/SkillManagerInterface.h>
37#include <RobotAPI/interface/skills/SkillMemoryInterface.h>
47 def->optional(properties.shortcutPath,
49 "Add path of predefined dashboards. Syntax: Package/folderName/fileName");
54 SkillDashboard::getTimeout(
const std::string& skillId)
56 constexpr bool addToDependencies =
false;
57 const auto& managerPrx =
65 const auto& splitIt = skillId.find(
'/');
66 std::string provider =
"";
67 std::string nameSkill =
"";
69 if (splitIt == std::string::npos)
74 provider = skillId.substr(0, splitIt);
75 nameSkill = skillId.substr(splitIt + 1);
76 skills::manager::dto::ProviderID providerId{.providerName = provider};
78 skills::manager::dto::SkillID skillIdDTO{.providerId = providerId, .skillName = nameSkill};
80 IceUtil::Optional<armarx::skills::manager::dto::SkillDescription> skillDescDTO =
81 managerPrx->getSkillDescription(skillIdDTO);
87 const auto& dto = *skillDescDTO;
92 SkillDashboard::updateTimeoutForShortcut(
const SkillShortcut& shortcut)
94 armarx::core::time::Duration timeout = getTimeout(shortcut.skillId);
95 std::unique_lock timeoutsLock(shortcutNameToTimeoutsMutex);
96 this->shortcutNameToTimeouts[shortcut.shortcutName] = timeout;
97 timeoutsLock.unlock();
101 SkillDashboard::loadShortcuts(
const std::string& packagepath)
103 std::scoped_lock l(registeredShortcutsMutex);
104 this->registeredShortcuts = std::vector<SkillShortcut>();
105 std::stringstream ss(packagepath);
107 std::vector<std::string> result;
108 while (std::getline(ss, item,
'/'))
110 result.push_back(item);
112 if (result.size() < 3)
117 this->packageName = result[0];
119 std::string absoluteFilepath;
120 std::string filename;
121 armarx::CMakePackageFinder finder(result[0]);
122 if (finder.packageFound())
126 std::string packageDataDir = finder.getDataDir();
132 std::string relativeFilename;
133 for (
size_t i = 1; i < result.size() - 1; i++)
135 if (!relativeFilename.empty())
137 relativeFilename +=
"/";
139 relativeFilename += result[i];
142 this->pathToDashboard = relativeFilename;
143 this->dahsboardName = result[result.size() - 1];
147 ARMARX_INFO <<
"Located file at:" << absoluteFilepath;
148 filename = result[result.size() - 1] +
".json";
152 std::ifstream file(absoluteFilepath +
"/" + filename);
153 nlohmann::json jsonData;
161 boost::uuids::name_generator generator(boost::uuids::nil_uuid());
163 for (
const auto& item : jsonData[
"shortcuts"])
165 SkillShortcut shortcut;
166 shortcut.skillArgs = item[
"skill_args"].dump(2);
167 shortcut.skillId = item[
"skill_id"];
168 if (item.contains(
"icon_name"))
170 shortcut.iconName = item[
"icon_name"];
174 shortcut.iconName =
"";
176 shortcut.shortcutName = item[
"skill_shortcut_name"];
177 if (item.contains(
"id"))
179 shortcut.id = item[
"id"];
183 shortcut.id = boost::uuids::to_string(generator(shortcut.shortcutName));
186 this->registeredShortcuts.push_back(shortcut);
192 ARMARX_WARNING <<
"Configured ArmarX package not found for '" << result[0] <<
"'.";
203 if (not properties.shortcutPath.empty())
205 loadShortcuts(properties.shortcutPath);
212 ARMARX_DEBUG <<
"Skills dashboard component connected.";
220 ARMARX_DEBUG <<
"Getting shortcuts … (registered are " << this->registeredShortcuts.size()
222 return this->registeredShortcuts;
225 SkillShortcutWithTimeoutList
229 std::vector<SkillShortcutWithTimeout> shortcutsWithTimeout;
230 std::scoped_lock l(registeredShortcutsMutex);
231 for (
const auto& shortcut : this->registeredShortcuts)
233 this->updateTimeoutForShortcut(shortcut);
234 SkillShortcutWithTimeout shortcutWithTimeout;
235 shortcutWithTimeout.shortcutName = shortcut.shortcutName;
236 shortcutWithTimeout.skillId = shortcut.skillId;
237 shortcutWithTimeout.skillArgs = shortcut.skillArgs;
238 shortcutWithTimeout.iconName = shortcut.iconName;
240 std::shared_lock timeoutsLock(shortcutNameToTimeoutsMutex);
241 shortcutWithTimeout.timeout.microSeconds =
242 this->shortcutNameToTimeouts[shortcut.shortcutName].toMicroSeconds();
243 timeoutsLock.unlock();
245 shortcutsWithTimeout.push_back(shortcutWithTimeout);
247 return shortcutsWithTimeout;
253 std::scoped_lock l(registeredShortcutsMutex);
254 for (
const SkillShortcut& shortcut : this->registeredShortcuts)
256 if (shortcut.shortcutName == name)
262 return SkillShortcut();
265 std::optional<SkillShortcut>
266 SkillDashboard::getShortcutWithId(
const std::string&
id)
268 std::scoped_lock l(registeredShortcutsMutex);
269 for (
const SkillShortcut& shortcut : this->registeredShortcuts)
271 if (shortcut.id ==
id)
283 if (newShortcut.shortcutName ==
"")
287 if (newShortcut.id ==
"" || getShortcutWithId(newShortcut.id) == std::nullopt)
289 if (
getShortcut(newShortcut.shortcutName).shortcutName ==
"")
291 boost::uuids::name_generator generator(boost::uuids::nil_uuid());
293 SkillShortcut toAddShortcut;
294 toAddShortcut.shortcutName = newShortcut.shortcutName;
295 toAddShortcut.skillArgs = newShortcut.skillArgs;
296 toAddShortcut.skillId = newShortcut.skillId;
297 toAddShortcut.iconName = newShortcut.iconName;
298 toAddShortcut.id = boost::uuids::to_string(generator(newShortcut.shortcutName));
300 std::unique_lock l(registeredShortcutsMutex);
301 this->registeredShortcuts.push_back(toAddShortcut);
303 this->updateTimeoutForShortcut(toAddShortcut);
304 ARMARX_INFO <<
"Added shortcut " << newShortcut.shortcutName;
313 std::optional<SkillShortcut> updatedShortcut;
314 std::unique_lock l(registeredShortcutsMutex);
315 for (SkillShortcut& shortcut : this->registeredShortcuts)
317 if (shortcut.id == newShortcut.id)
319 shortcut.shortcutName = newShortcut.shortcutName;
320 shortcut.skillId = newShortcut.skillId;
321 shortcut.skillArgs = newShortcut.skillArgs;
322 shortcut.iconName = newShortcut.iconName;
324 updatedShortcut = shortcut;
330 this->updateTimeoutForShortcut(*updatedShortcut);
339 std::scoped_lock l(registeredShortcutsMutex);
340 for (
auto it = this->registeredShortcuts.begin(); it != this->registeredShortcuts.end();
343 if (it->shortcutName == name)
345 this->registeredShortcuts.erase(it);
346 std::unique_lock timeoutsLock(shortcutNameToTimeoutsMutex);
347 this->shortcutNameToTimeouts.erase(name);
348 timeoutsLock.unlock();
358 this->shortcutOrder = order;
364 std::unordered_map<std::string, std::size_t>
index;
365 for (std::size_t i = 0; i < this->shortcutOrder.size(); ++i)
367 index[this->shortcutOrder[i]] = i;
370 std::sort(this->registeredShortcuts.begin(),
371 this->registeredShortcuts.end(),
372 [&](
const auto& a,
const auto& b)
373 { return index[a.shortcutName] < index[b.shortcutName]; });
376 std::vector<std::string>
379 return std::vector<std::string>{
380 this->packageName, this->pathToDashboard, this->dahsboardName};
385 const std::string& folder,
386 const std::string& name,
387 const ::Ice::Current&)
389 std::string path =
package + "/" + folder + "/" + name;
390 return loadShortcuts(path);
395 const std::string& folder,
396 const std::string& name,
397 const ::Ice::Current&)
401 std::unordered_map<std::string, SkillShortcut> lookup;
402 lookup.reserve(registeredShortcuts.size());
403 std::shared_lock shortcutsLock(registeredShortcutsMutex);
404 for (
const auto& s : registeredShortcuts)
406 lookup[s.shortcutName] = s;
408 shortcutsLock.unlock();
411 for (
const auto& name : this->shortcutOrder)
414 auto it = lookup.find(name);
415 if (it == lookup.end())
420 const auto& shortcut = it->second;
422 nlohmann::json skillArgs_json = nlohmann::json::parse(shortcut.skillArgs);
424 j[
"shortcuts"].push_back({
425 {
"skill_shortcut_name", shortcut.shortcutName},
426 {
"skill_id", shortcut.skillId},
427 {
"skill_args", skillArgs_json},
428 {
"icon_name", shortcut.iconName},
432 std::string absoluteFilename;
437 std::string packageDataDir = finder.
getDataDir();
441 std::filesystem::create_directories(packageDataDir +
"/" + folder);
443 std::string relativeFilename(folder);
447 ARMARX_INFO <<
"Located file at:" << absoluteFilename;
448 std::string filename = name +
".json";
449 std::ofstream outFile(absoluteFilename +
"/" + filename);
450 outFile << std::setw(4) << j << std::endl;
452 ARMARX_INFO <<
"Insert " <<
package << "/" << folder << "/" << name
453 << " into the component property.";
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
static bool getAbsolutePath(const std::string &relativeFilename, std::string &storeAbsoluteFilename, const std::vector< std::string > &additionalSearchPaths={}, bool verbose=true)
static void addDataPaths(const std::string &dataPathList)
The CMakePackageFinder class provides an interface to the CMake Package finder capabilities.
std::string getDataDir() const
bool packageFound() const
Returns whether or not this package was found with cmake.
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Property< PropertyType > getProperty(const std::string &name)
void offeringTopic(const std::string &name)
Registers a topic for retrival after initialization.
TopicProxyType getTopic(const std::string &name)
Returns a proxy of the specified topic.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
SkillShortcutWithTimeoutList getShortcutsWithTimeout(const ::Ice::Current &=::Ice::Current()) override
void onInitComponent() override
bool importShortcuts(const std::string &package, const std::string &folder, const std::string &name, const ::Ice::Current &=::Ice::Current()) override
void deleteShortcut(const std::string &name, const ::Ice::Current &=::Ice::Current()) override
void syncOrderedWithDefault(const ::Ice::Current &) override
void addNewShortcut(const SkillShortcut &newShortcut, const ::Ice::Current &=::Ice::Current()) override
void onDisconnectComponent() override
SkillShortcut getShortcut(const std::string &name, const ::Ice::Current &=::Ice::Current()) override
SkillShortcutList getShortcuts(const ::Ice::Current &=::Ice::Current()) override
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
void saveShortcutOrder(const std::vector< std::string > &order, const ::Ice::Current &=::Ice::Current()) override
void exportShortcuts(const std::string &package, const std::string &folder, const std::string &name, const ::Ice::Current &=::Ice::Current()) override
void onConnectComponent() override
std::vector< std::string > getPathStructure(const ::Ice::Current &=::Ice::Current()) override
void onExitComponent() override
static Duration MicroSeconds(std::int64_t microSeconds)
Constructs a duration in microseconds.
static Duration Seconds(std::int64_t seconds)
Constructs a duration in seconds.
#define ARMARX_INFO
The normal logging level.
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#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.
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.