SkillDashboard.cpp
Go to the documentation of this file.
1
2#include "SkillDashboard.h"
3
4#include <cstdint>
5#include <fstream>
6#include <iostream>
7#include <mutex>
8#include <optional>
9#include <shared_mutex>
10#include <sstream>
11#include <string>
12#include <thread>
13
14#include <IceUtil/Optional.h>
15
16#include <nlohmann/json.hpp>
17#include <nlohmann/json_fwd.hpp>
18
21
23#include <RobotAPI/interface/skills/SkillManagerInterface.h>
24#include <RobotAPI/interface/skills/SkillMemoryInterface.h>
25
27
28namespace armarx
29{
30
33 {
35 new ::armarx::ComponentPropertyDefinitions(getConfigIdentifier());
36 def->optional(properties.shortcutPath,
37 "ShortcutPath",
38 "Add path of predefined dashboards. Syntax: Package/folderName/fileName");
39 return def;
40 }
41
43 SkillDashboard::getTimeout(const std::string& skillId)
44 {
45 constexpr bool addToDependencies = false;
46 const auto& managerPrx =
47 getProxy<skills::dti::SkillMemoryInterfacePrx>("SkillMemory", addToDependencies);
48
49 if (!managerPrx)
50 {
52 }
53
54 const auto& splitIt = skillId.find('/');
55 std::string provider = "";
56 std::string nameSkill = "";
57
58 if (splitIt == std::string::npos)
59 {
60 // TODO: error handling
62 }
63 provider = skillId.substr(0, splitIt);
64 nameSkill = skillId.substr(splitIt + 1);
65 skills::manager::dto::ProviderID providerId{.providerName = provider};
66
67 skills::manager::dto::SkillID skillIdDTO{.providerId = providerId, .skillName = nameSkill};
68
69 IceUtil::Optional<armarx::skills::manager::dto::SkillDescription> skillDescDTO =
70 managerPrx->getSkillDescription(skillIdDTO);
71
72 if (!skillDescDTO)
73 {
75 }
76 const auto& dto = *skillDescDTO;
77 return armarx::core::time::Duration::MicroSeconds(dto.timeout.microSeconds);
78 }
79
80 void
81 SkillDashboard::updateTimeoutForShortcut(const SkillShortcut& shortcut)
82 {
83 armarx::core::time::Duration timeout = getTimeout(shortcut.skillId);
84 std::unique_lock timeoutsLock(shortcutNameToTimeoutsMutex);
85 this->shortcutNameToTimeouts[shortcut.shortcutName] = timeout;
86 timeoutsLock.unlock();
87 }
88
89 bool
90 SkillDashboard::loadShortcuts(const std::string& packagepath)
91 {
92 std::scoped_lock l(registeredShortcutsMutex);
93 this->registeredShortcuts = std::vector<SkillShortcut>();
94 std::stringstream ss(packagepath);
95 std::string item;
96 std::vector<std::string> result;
97 while (std::getline(ss, item, '/'))
98 {
99 result.push_back(item);
100 }
101 if (result.size() < 3)
102 {
103 ARMARX_ERROR << "Invalid property structure!";
104 return false;
105 }
106 this->packageName = result[0];
107
108 std::string absoluteFilepath;
109 std::string filename;
110 armarx::CMakePackageFinder finder(result[0]);
111 if (finder.packageFound())
112 {
113 ARMARX_INFO << "Found package.";
114
115 std::string packageDataDir = finder.getDataDir();
116
117 // add the data directory to the search list of ArmarXDataPath
118 ArmarXDataPath::addDataPaths(packageDataDir);
119 //std::filesystem::create_directory(packageDataDir + "/" + folder);
120
121 std::string relativeFilename;
122 for (size_t i = 1; i < result.size() - 1; i++)
123 {
124 if (!relativeFilename.empty())
125 {
126 relativeFilename += "/";
127 }
128 relativeFilename += result[i];
129 }
130
131 this->pathToDashboard = relativeFilename;
132 this->dahsboardName = result[result.size() - 1];
133
134 if (ArmarXDataPath::getAbsolutePath(relativeFilename, absoluteFilepath))
135 {
136 ARMARX_INFO << "Located file at:" << absoluteFilepath;
137 filename = result[result.size() - 1] + ".json";
138 }
139
140
141 std::ifstream file(absoluteFilepath + "/" + filename);
142 nlohmann::json jsonData;
143
144 if (!file.is_open())
145 {
146 ARMARX_WARNING << "Could not open file";
147 }
148
149 file >> jsonData;
150
151 for (const auto& item : jsonData["shortcuts"])
152 {
153 SkillShortcut shortcut;
154 shortcut.skillArgs = item["skill_args"].dump(2);
155 shortcut.skillId = item["skill_id"];
156 if (item.contains("icon_name"))
157 {
158 shortcut.iconName = item["icon_name"];
159 }
160 else
161 {
162 shortcut.iconName = "";
163 }
164 shortcut.shortcutName = item["skill_shortcut_name"];
165
166 this->registeredShortcuts.push_back(shortcut);
167 }
168 return true;
169 }
170 else
171 {
172 ARMARX_WARNING << "Configured ArmarX package not found for '" << result[0] << "'.";
173 return false;
174 }
175 }
176
177 void
179 {
180 this->properties.shortcutPath = getProperty<std::string>("ShortcutPath").getValue();
181
182 if (not properties.shortcutPath.empty())
183 {
184 loadShortcuts(properties.shortcutPath);
185 }
186 }
187
188 void
190 {
191 ARMARX_DEBUG << "Skills dashboard component connected.";
192 }
193
194 SkillShortcutList
195 SkillDashboard::getShortcuts(const ::Ice::Current&)
196 {
197 ARMARX_DEBUG << "Getting shortcuts … (registered are " << this->registeredShortcuts.size()
198 << ")";
199 return this->registeredShortcuts;
200 }
201
202 SkillShortcutWithTimeoutList
204 {
205 ARMARX_DEBUG << "Getting shortcuts with timeout …";
206 std::vector<SkillShortcutWithTimeout> shortcutsWithTimeout;
207 std::scoped_lock l(registeredShortcutsMutex);
208 for (const auto& shortcut : this->registeredShortcuts)
209 {
210 this->updateTimeoutForShortcut(shortcut);
211 SkillShortcutWithTimeout shortcutWithTimeout;
212 shortcutWithTimeout.shortcutName = shortcut.shortcutName;
213 shortcutWithTimeout.skillId = shortcut.skillId;
214 shortcutWithTimeout.skillArgs = shortcut.skillArgs;
215 shortcutWithTimeout.iconName = shortcut.iconName;
216
217 std::shared_lock timeoutsLock(shortcutNameToTimeoutsMutex);
218 shortcutWithTimeout.timeout.microSeconds =
219 this->shortcutNameToTimeouts[shortcut.shortcutName].toMicroSeconds();
220 timeoutsLock.unlock();
221
222 shortcutsWithTimeout.push_back(shortcutWithTimeout);
223 }
224 return shortcutsWithTimeout;
225 }
226
227 SkillShortcut
228 SkillDashboard::getShortcut(const std::string& name, const ::Ice::Current&)
229 {
230 std::scoped_lock l(registeredShortcutsMutex);
231 for (const SkillShortcut& shortcut : this->registeredShortcuts)
232 {
233 if (shortcut.shortcutName == name)
234 {
235 return shortcut;
236 }
237 }
238
239 return SkillShortcut();
240 }
241
242 void
243 SkillDashboard::addNewShortcut(const SkillShortcut& newShortcut, const ::Ice::Current&)
244 {
245 if (newShortcut.shortcutName != "")
246 {
247 if (getShortcut(newShortcut.shortcutName).shortcutName == "")
248 {
249 std::unique_lock l(registeredShortcutsMutex);
250 this->registeredShortcuts.push_back(newShortcut);
251 l.unlock();
252 this->updateTimeoutForShortcut(newShortcut);
253 ARMARX_INFO << "Added shortcut " << newShortcut.shortcutName;
254 }
255 else
256 {
257 std::optional<SkillShortcut> updatedShortcut;
258 std::unique_lock l(registeredShortcutsMutex);
259 for (SkillShortcut& shortcut : this->registeredShortcuts)
260 {
261 if (shortcut.shortcutName == newShortcut.shortcutName)
262 {
263 shortcut.skillId = newShortcut.skillId;
264 shortcut.skillArgs = newShortcut.skillArgs;
265 shortcut.iconName = newShortcut.iconName;
266
267 updatedShortcut = shortcut;
268 }
269 }
270 l.unlock();
271 if (updatedShortcut)
272 {
273 this->updateTimeoutForShortcut(*updatedShortcut);
274 }
275 ARMARX_INFO << "changed shortcut";
276 }
277 }
278 }
279
280 void
281 SkillDashboard::deleteShortcut(const std::string& name, const ::Ice::Current&)
282 {
283 std::scoped_lock l(registeredShortcutsMutex);
284 for (auto it = this->registeredShortcuts.begin(); it != this->registeredShortcuts.end();
285 ++it)
286 {
287 if (it->shortcutName == name)
288 {
289 this->registeredShortcuts.erase(it);
290 std::unique_lock timeoutsLock(shortcutNameToTimeoutsMutex);
291 this->shortcutNameToTimeouts.erase(name);
292 timeoutsLock.unlock();
293 break;
294 }
295 }
296 }
297
298 void
299 SkillDashboard::saveShortcutOrder(const std::vector<std::string>& order, const ::Ice::Current&)
300 {
301 ARMARX_IMPORTANT << "Save shortcut order";
302 this->shortcutOrder = order;
303 }
304
305 std::vector<std::string>
306 SkillDashboard::getPathStructure(const ::Ice::Current&)
307 {
308 return std::vector<std::string>{
309 this->packageName, this->pathToDashboard, this->dahsboardName};
310 }
311
312 bool
313 SkillDashboard::importShortcuts(const std::string& package,
314 const std::string& folder,
315 const std::string& name,
316 const ::Ice::Current&)
317 {
318 std::string path = package + "/" + folder + "/" + name;
319 return loadShortcuts(path);
320 }
321
322 void
323 SkillDashboard::exportShortcuts(const std::string& package,
324 const std::string& folder,
325 const std::string& name,
326 const ::Ice::Current&)
327 {
328
329 nlohmann::json j;
330
331 std::unordered_map<std::string, SkillShortcut> lookup;
332 lookup.reserve(registeredShortcuts.size());
333 std::shared_lock shortcutsLock(registeredShortcutsMutex);
334 for (const auto& s : registeredShortcuts)
335 {
336 lookup[s.shortcutName] = s;
337 }
338 shortcutsLock.unlock();
339
340
341 for (const auto& name : this->shortcutOrder)
342 {
343
344 auto it = lookup.find(name);
345 if (it == lookup.end())
346 {
347 ARMARX_IMPORTANT << "Shortcut does not exist.";
348 continue;
349 }
350 const auto& shortcut = it->second;
351
352 nlohmann::json skillArgs_json = nlohmann::json::parse(shortcut.skillArgs);
353
354 j["shortcuts"].push_back({
355 {"skill_shortcut_name", shortcut.shortcutName},
356 {"skill_id", shortcut.skillId},
357 {"skill_args", skillArgs_json},
358 {"icon_name", shortcut.iconName},
359 });
360 }
361
362 std::string absoluteFilename;
363 armarx::CMakePackageFinder finder(package);
364 if (finder.packageFound())
365 {
366
367 std::string packageDataDir = finder.getDataDir();
368
369 // add the data directory to the search list of ArmarXDataPath
370 ArmarXDataPath::addDataPaths(packageDataDir);
371 std::filesystem::create_directories(packageDataDir + "/" + folder);
372
373 std::string relativeFilename(folder);
374
375 if (ArmarXDataPath::getAbsolutePath(relativeFilename, absoluteFilename))
376 {
377 ARMARX_INFO << "Located file at:" << absoluteFilename;
378 std::string filename = name + ".json";
379 std::ofstream outFile(absoluteFilename + "/" + filename);
380 outFile << std::setw(4) << j << std::endl;
381 outFile.close();
382 ARMARX_INFO << "Insert " << package << "/" << folder << "/" << name
383 << " into the component property.";
384 }
385 }
386 }
387
388 void
392
393 void
397
399} // namespace armarx
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
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.
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.
Definition Component.cpp:90
Property< PropertyType > getProperty(const std::string &name)
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 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
Represents a duration.
Definition Duration.h:17
static Duration MicroSeconds(std::int64_t microSeconds)
Constructs a duration in microseconds.
Definition Duration.cpp:24
static Duration Seconds(std::int64_t seconds)
Constructs a duration in seconds.
Definition Duration.cpp:72
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.