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