YARP
Yet Another Robot Platform
MonitorLua.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 #include <yarp/os/Network.h>
7 #include <yarp/os/Log.h>
8 #include <yarp/os/LogStream.h>
9 #include <lua.hpp>
10 #include "MonitorLua.h"
11 #include "MonitorLogComponent.h"
12 
13 using namespace yarp::os;
14 
15 
19 MonitorLua::MonitorLua() : bHasAcceptCallback(false),
20  bHasUpdateCallback(false),
21  bHasUpdateReplyCallback(false),
22  trigger(nullptr)
23 {
24  L = luaL_newstate();
25  luaL_openlibs(L);
26 
35  registerExtraFunctions();
36 }
37 
39 {
40  if(L){
41  // stop trigger thread if it is running
42  if(trigger) {
43  trigger->stop();
44  delete trigger;
45  trigger = nullptr;
46  }
47  // call PortMonitor.destroy if exists
48  if(getLocalFunction("destroy"))
49  {
50  if (lua_pcall(L, 0, 0, 0) != 0) {
51  yCError(PORTMONITORCARRIER, "%s", lua_tostring(L, -1));
52  }
53  }
54  // closing lua state handler
55  lua_close(L);
56  }
57 }
58 
59 bool MonitorLua::load(const Property &options)
60 {
62  if(luaL_loadfile(L, options.find("filename").asString().c_str()))
63  {
64  yCError(PORTMONITORCARRIER, "Cannot load script file");
65  yCError(PORTMONITORCARRIER, "%s", lua_tostring(L, -1));
66  lua_pop(L,1);
67  lua_close(L);
68  L = nullptr;
69  return false;
70  }
71 
72  if(lua_pcall(L,0, LUA_MULTRET, 0))
73  {
74  yCError(PORTMONITORCARRIER, "Cannot run script file");
75  yCError(PORTMONITORCARRIER, "%s", lua_tostring(L, -1));
76  lua_pop(L,1);
77  lua_close(L);
78  L = nullptr;
79  return false;
80  }
81 
85  lua_pushlightuserdata(L, this);
86  lua_setglobal(L, "PortMonitor_Owner");
87 
88  lua_getglobal(L, "PortMonitor");
89  if(lua_istable(L, -1) == 0)
90  {
91  yCError(PORTMONITORCARRIER, "The script file does not contain any valid \'PortMonitor\' object.");
92  lua_pop(L, 1);
93  lua_close(L);
94  L = nullptr;
95  return false;
96  }
97 
98  bool result = true;
99  // call PortMonitor.create if exists
100  luaMutex.lock();
101  if(getLocalFunction("create"))
102  {
103  // mapping to swig type
104  swig_type_info *propType = SWIG_TypeQuery(L, "yarp::os::Property *");
105  if(!propType)
106  {
107  yCError(PORTMONITORCARRIER, "Swig type of Property is not found");
108  lua_pop(L, 1);
109  luaMutex.unlock();
110  return false;
111  }
112  // getting the swig-type pointer
113  SWIG_NewPointerObj(L, &options, propType, 0);
114  if(lua_pcall(L, 1, 1, 0) != 0)
115  {
116  yCError(PORTMONITORCARRIER, "%s", lua_tostring(L, -1));
117  lua_pop(L, 1);
118  lua_close(L);
119  L = nullptr;
120  luaMutex.unlock();
121  return false;
122  } else {
123  result = lua_toboolean(L, -1);
124  }
125  }
126  lua_pop(L,1);
127 
128  // Check if there is accept callback
129  bHasAcceptCallback = getLocalFunction("accept");
130  lua_pop(L,1);
131 
132  // Check if there is update callback
133  bHasUpdateCallback = getLocalFunction("update");
134  lua_pop(L,1);
135 
136  // Check if there is update callback
137  bHasUpdateReplyCallback = getLocalFunction("update_reply");
138  lua_pop(L,1);
139  luaMutex.unlock();
140  return result;
141 }
142 
144 {
145  luaMutex.lock();
146  if(getLocalFunction("accept"))
147  {
148  // mapping to swig type
149  swig_type_info *thingsType = SWIG_TypeQuery(L, "yarp::os::Things *");
150  if(!thingsType)
151  {
152  yCError(PORTMONITORCARRIER, "Swig type of Things is not found");
153  lua_pop(L, 1);
154  luaMutex.unlock();
155  return false;
156  }
157 
158  // getting the swig-type pointer
159  SWIG_NewPointerObj(L, &thing, thingsType, 0);
160  if(lua_pcall(L, 1, 1, 0) != 0)
161  {
162  yCError(PORTMONITORCARRIER, "%s", lua_tostring(L, -1));
163  lua_pop(L, 1);
164  luaMutex.unlock();
165  return false;
166  }
167 
168  // converting the results
169  bool result = lua_toboolean(L, -1);
170  lua_pop(L, 1);
171  luaMutex.unlock();
172  return result;
173  }
174 
175  lua_pop(L, 1);
176  luaMutex.unlock();
177  return true;
178 }
179 
180 
182 {
183  luaMutex.lock();
184  if(getLocalFunction("update"))
185  {
186  // mapping to swig type
187  swig_type_info *thingsType = SWIG_TypeQuery(L, "yarp::os::Things *");
188  if(!thingsType)
189  {
190  yCError(PORTMONITORCARRIER, "Swig type of Things is not found");
191  lua_pop(L, 1);
192  luaMutex.unlock();
193  return thing;
194  }
195 
196  // getting the swig-type pointer
197  SWIG_NewPointerObj(L, &thing, thingsType, 0);
198  if(lua_pcall(L, 1, 1, 0) != 0)
199  {
200  yCError(PORTMONITORCARRIER, "%s", lua_tostring(L, -1));
201  lua_pop(L, 1);
202  luaMutex.unlock();
203  return thing;
204  }
205 
206  // converting the results
207  yarp::os::Things* result;
208  if(SWIG_Lua_ConvertPtr(L, -1, (void**)(&result), thingsType, 0) != SWIG_OK )
209  {
210  yCError(PORTMONITORCARRIER, "Cannot get a valid return value from PortMonitor.update");
211  lua_pop(L, 1);
212  luaMutex.unlock();
213  return thing;
214  }
215  else
216  {
217  lua_pop(L, 1);
218  luaMutex.unlock();
219  return *result;
220  }
221  }
222 
223  lua_pop(L,1);
224  luaMutex.unlock();
225  return thing;
226 }
227 
229 {
230  luaMutex.lock();
231  if(getLocalFunction("update_reply"))
232  {
233  // mapping to swig type
234  swig_type_info *thingsType = SWIG_TypeQuery(L, "yarp::os::Things *");
235  if(!thingsType)
236  {
237  yCError(PORTMONITORCARRIER, "Swig type of Things is not found");
238  lua_pop(L, 1);
239  luaMutex.unlock();
240  return thing;
241  }
242 
243  // getting the swig-type pointer
244  SWIG_NewPointerObj(L, &thing, thingsType, 0);
245  if(lua_pcall(L, 1, 1, 0) != 0)
246  {
247  yCError(PORTMONITORCARRIER, "%s", lua_tostring(L, -1));
248  lua_pop(L, 1);
249  luaMutex.unlock();
250  return thing;
251  }
252 
253  // converting the results
254  yarp::os::Things* result;
255  if(SWIG_Lua_ConvertPtr(L, -1, (void**)(&result), thingsType, 0) != SWIG_OK )
256  {
257  yCError(PORTMONITORCARRIER, "Cannot get a valid return value from PortMonitor.update_reply");
258  lua_pop(L, 1);
259  luaMutex.unlock();
260  return thing;
261  }
262  else
263  {
264  lua_pop(L, 1);
265  luaMutex.unlock();
266  return *result;
267  }
268  }
269 
270  lua_pop(L,1);
271  luaMutex.unlock();
272  return thing;
273 }
274 
276 {
277  luaMutex.lock();
278  if(getLocalFunction("setparam"))
279  {
280  // mapping to swig type
281  swig_type_info *propType = SWIG_TypeQuery(L, "yarp::os::Property *");
282  if(!propType)
283  {
284  yCError(PORTMONITORCARRIER, "Swig type of Property is not found");
285  lua_pop(L, 1);
286  luaMutex.unlock();
287  return false;
288  }
289 
290  // getting the swig-type pointer
291  SWIG_NewPointerObj(L, &params, propType, 0);
292  if(lua_pcall(L, 1, 0, 0) != 0)
293  {
294  yCError(PORTMONITORCARRIER, "%s", lua_tostring(L, -1));
295  lua_pop(L, 1);
296  luaMutex.unlock();
297  return false;
298  }
299  luaMutex.unlock();
300  return true;
301  }
302 
303  lua_pop(L,1);
304  luaMutex.unlock();
305  return true;
306 }
307 
309 {
310  luaMutex.lock();
311  if(getLocalFunction("getparam"))
312  {
313  // mapping to swig type
314  swig_type_info *propType = SWIG_TypeQuery(L, "yarp::os::Property *");
315  if(!propType)
316  {
317  yCError(PORTMONITORCARRIER, "Swig type of Property is not found");
318  lua_pop(L, 1);
319  luaMutex.unlock();
320  return false;
321  }
322 
323  // calling PortMonitor.getparam from lua
324  if(lua_pcall(L, 0, 1, 0) != 0)
325  {
326  yCError(PORTMONITORCARRIER, "%s", lua_tostring(L, -1));
327  lua_pop(L, 1);
328  luaMutex.unlock();
329  return false;
330  }
331 
332  // converting the results
333  yarp::os::Property* result;
334  if(SWIG_Lua_ConvertPtr(L, -1, (void**)(&result), propType, 0) != SWIG_OK )
335  {
336  yCError(PORTMONITORCARRIER, "Cannot get a valid return value from PortMonitor.getparam");
337  lua_pop(L, 1);
338  luaMutex.unlock();
339  return false;
340  }
341  else
342  {
343  params = *result;
344  lua_pop(L, 1);
345  luaMutex.unlock();
346  return true;
347  }
348  }
349 
350  lua_pop(L,1);
351  luaMutex.unlock();
352  return true;
353 }
354 
356 {
357  luaMutex.lock();
358  if(getLocalFunction("trig"))
359  {
360  if(lua_pcall(L, 0, 0, 0) != 0)
361  {
362  yCError(PORTMONITORCARRIER, "%s", lua_tostring(L, -1));
363  lua_pop(L, 1);
364  luaMutex.unlock();
365  return false;
366  }
367  luaMutex.unlock();
368  return true;
369  }
370 
371  lua_pop(L, 1);
372  luaMutex.unlock();
373  return true;
374 }
375 
376 
377 bool MonitorLua::getLocalFunction(const char *name)
378 {
379  lua_pushstring(L, name);
380  lua_gettable(L, -2);
381  return (lua_isfunction(L, -1) == 1);
382 }
383 
384 
385 bool MonitorLua::registerExtraFunctions()
386 {
387 #if LUA_VERSION_NUM > 501
388  lua_newtable(L);
389  luaL_setfuncs (L, MonitorLua::portMonitorLib, 0);
390  lua_pushvalue(L, -1);
391  lua_setglobal(L, "PortMonitor");
392 #else
393  // deprecated
394  //luaL_openlib(L, "PortMonitor", MonitorLua::portMonitorLib, 0);
395  luaL_register(L, "PortMonitor", MonitorLua::portMonitorLib);
396 #endif
397  return true;
398 }
399 
400 
402 {
403  if (constraint == "") {
404  return true;
405  }
406 
408 
413  std::string strConstraint = constraint;
414  std::string strDummy = strConstraint;
415  searchReplace(strDummy, "(", " ");
416  searchReplace(strDummy, ")", " ");
417  // wrap it with some guard space
418  strDummy = " " + strDummy + " ";
419  std::string delimiter = " ";
420  size_t pos = 0;
421  std::string token;
422  while ((pos = strDummy.find(delimiter)) != std::string::npos)
423  {
424  token = strDummy.substr(0, pos);
425  if(token.size() && !isKeyword(token.c_str()))
426  {
427  record.lock();
428  std::string value = (record.hasEvent(token.c_str())) ? "true" : "false";
429  record.unlock();
430  searchReplace(strConstraint, token, value);
431  }
432  strDummy.erase(0, pos + delimiter.length());
433  }
434  yCTrace(PORTMONITORCARRIER, "constraint = \'%s\'", strConstraint.c_str());
435 
436  /*
437  * Using lua to evaluate the boolean expression
438  * Note: this can be replaced by a homebrew boolean
439  * expression validator (e.g., BinNodeType from libyarpmanager)
440  */
441  strConstraint = "return " + strConstraint;
442 
443  if(luaL_dostring(L, strConstraint.c_str()) != 0)
444  {
445  yCError(PORTMONITORCARRIER, "%s", lua_tostring(L, -1));
446  return false;
447  }
448 
449  if(!lua_isboolean(L, -1))
450  {
451  yCError(PORTMONITORCARRIER, "%s", lua_tostring(L, -1));
452  return false;
453  }
454 
455  bool accepted = (lua_toboolean(L,-1) == 1);
456  lua_pop(L, 1);
457  return accepted;
458 }
459 
460 
461 inline void MonitorLua::searchReplace(std::string& str, const std::string& oldStr, const std::string& newStr)
462 {
463  size_t pos = 0;
464  while((pos = str.find(oldStr, pos)) != std::string::npos)
465  {
466  str.replace(pos, oldStr.length(), newStr);
467  pos += newStr.length();
468  }
469 }
470 
471 inline void MonitorLua::trimString(std::string& str)
472 {
473  std::string::size_type pos = str.find_last_not_of(' ');
474  if(pos != std::string::npos) {
475  str.erase(pos + 1);
476  pos = str.find_first_not_of(' ');
477  if (pos != std::string::npos) {
478  str.erase(0, pos);
479  }
480  } else {
481  str.erase(str.begin(), str.end());
482  }
483 }
484 
485 inline bool MonitorLua::isKeyword(const char* str)
486 {
487  if (!str) {
488  return false;
489  }
490 
491  std::string token = str;
492  if ((token == "true") || (token == "false") || (token == "and") || (token == "or") || (token == "not")) {
493  return true;
494  }
495  return false;
496 }
497 
498 
503 int MonitorLua::setConstraint(lua_State* L)
504 {
505  const char *cst = luaL_checkstring(L, 1);
506  if(cst)
507  {
508  lua_getglobal(L, "PortMonitor_Owner");
509  if(!lua_islightuserdata(L, -1))
510  {
511  yCError(PORTMONITORCARRIER, "Cannot get PortMonitor_Owner");
512  return 0;
513  }
514 
515  auto* owner = static_cast<MonitorLua*>(lua_touserdata(L, -1));
517  owner->setAcceptConstraint(cst);
518  }
519  return 0;
520 }
521 
522 int MonitorLua::getConstraint(lua_State* L)
523 {
524  lua_getglobal(L, "PortMonitor_Owner");
525  if(!lua_islightuserdata(L, -1))
526  {
527  yCError(PORTMONITORCARRIER, "Cannot get PortMonitor_Owner");
528  return 0;
529  }
530 
531  auto* owner = static_cast<MonitorLua*>(lua_touserdata(L, -1));
533  lua_pushstring(L, owner->getAcceptConstraint());
534  return 0;
535 }
536 
537 
538 int MonitorLua::setEvent(lua_State* L)
539 {
540  double lifetime = -1.0;
541  int n_args = lua_gettop(L);
542  const char *event_name = luaL_checkstring(L, 1);
543  if(event_name)
544  {
545  // check if the event's lifetime is given as argument
546  if(n_args > 1)
547  {
548  if (lua_isnumber(L, 2)) {
549  lifetime = (double) luaL_checknumber(L,2);
550  } else {
551  yCError(PORTMONITORCARRIER, "The second arguemnt of setEvent() must be number");
552  return 0;
553  }
554  }
555 
556  lua_getglobal(L, "PortMonitor_Owner");
557  if(!lua_islightuserdata(L, -1))
558  {
559  yCError(PORTMONITORCARRIER, "Cannot get PortMonitor_Owner");
560  return 0;
561  }
562  auto* owner = static_cast<MonitorLua*>(lua_touserdata(L, -1));
564  if (owner->isKeyword(event_name)) {
565  return 0;
566  }
568  record.lock();
569  record.setEvent(event_name, owner, lifetime);
570  record.unlock();
571  }
572  return 0;
573 }
574 
575 int MonitorLua::unsetEvent(lua_State* L)
576 {
577  const char *event_name = luaL_checkstring(L, 1);
578  if(event_name)
579  {
580  lua_getglobal(L, "PortMonitor_Owner");
581  if(!lua_islightuserdata(L, -1))
582  {
583  yCError(PORTMONITORCARRIER, "Cannot get PortMonitor_Owner");
584  return 0;
585  }
586  auto* owner = static_cast<MonitorLua*>(lua_touserdata(L, -1));
588  if (owner->isKeyword(event_name)) {
589  return 0;
590  }
592  record.lock();
593  record.unsetEvent(event_name, owner);
594  record.unlock();
595  }
596  return 0;
597 }
598 
599 int MonitorLua::setTrigInterval(lua_State* L)
600 {
601  double period = 0.0;
602  int n_args = lua_gettop(L);
603  if(n_args > 0) {
604  if (lua_isnumber(L, 1)) {
605  period = (double) luaL_checknumber(L,1);
606  } else {
607  yCError(PORTMONITORCARRIER, "The arguemnt of setTrigInterval() must be number");
608  return 0;
609  }
610  } else {
611  yCError(PORTMONITORCARRIER, "The setTrigInterval() require the interval number as the parameter");
612  return 0;
613  }
614 
615 
616  lua_getglobal(L, "PortMonitor_Owner");
617  if(!lua_islightuserdata(L, -1))
618  {
619  yCError(PORTMONITORCARRIER, "Cannot get PortMonitor_Owner");
620  return 0;
621  }
622 
623  auto* owner = static_cast<MonitorLua*>(lua_touserdata(L, -1));
625 
626  // start the trigger thread (MonitorTrigger) if it is not running
627  if(owner->trigger == nullptr) {
628  owner->trigger = new MonitorTrigger(owner, (int)(period*1000));
629  owner->trigger->start();
630  }
631  return 0;
632 }
633 
634 
635 #if LUA_VERSION_NUM > 501
636 const struct luaL_Reg MonitorLua::portMonitorLib [] = {
637 #else
638 const struct luaL_reg MonitorLua::portMonitorLib [] = {
639 #endif
640  {"setConstraint", MonitorLua::setConstraint},
641  {"getConstraint", MonitorLua::getConstraint},
642  {"setEvent", MonitorLua::setEvent},
643  {"unsetEvent", MonitorLua::unsetEvent},
644  {"setTrigInterval", MonitorLua::setTrigInterval},
645  {nullptr, nullptr}
646 };
const yarp::os::LogComponent & PORTMONITORCARRIER()
A singleton class to record the port monitor events.
Definition: MonitorEvent.h:39
void setEvent(const char *name, MonitorBinding *owner, double lifetime=-1.0)
Definition: MonitorEvent.h:45
void unsetEvent(const char *name, MonitorBinding *owner)
Definition: MonitorEvent.h:58
static MonitorEventRecord & getInstance()
Definition: MonitorEvent.h:96
bool hasEvent(const char *name)
Definition: MonitorEvent.h:67
void stop()
Call this to stop the thread, this call blocks until the thread is terminated (and releaseThread() ca...
A class for storing options and configuration information.
Definition: Property.h:34
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Property.cpp:1051
Base class for generic things.
Definition: Things.h:19
virtual std::string asString() const
Get string value.
Definition: Value.cpp:234
#define yCError(component,...)
Definition: LogComponent.h:154
#define yCAssert(component, x)
Definition: LogComponent.h:169
#define yCTrace(component,...)
Definition: LogComponent.h:85
An interface to the operating system, including Port based communication.
~MonitorLua() override
Definition: MonitorLua.cpp:38
MonitorLua()
Class MonitorLua.
Definition: MonitorLua.cpp:19
bool getParams(yarp::os::Property &params) override
Definition: MonitorLua.cpp:308
bool setParams(const yarp::os::Property &params) override
Definition: MonitorLua.cpp:275
bool canAccept() override
Definition: MonitorLua.cpp:401
bool acceptData(yarp::os::Things &thing) override
Definition: MonitorLua.cpp:143
yarp::os::Things & updateReply(yarp::os::Things &thing) override
Definition: MonitorLua.cpp:228
bool peerTrigged() override
Definition: MonitorLua.cpp:355
MonitorTrigger * trigger
Definition: MonitorLua.h:70
yarp::os::Things & updateData(yarp::os::Things &thing) override
Definition: MonitorLua.cpp:181
bool load(const yarp::os::Property &options) override
Definition: MonitorLua.cpp:59
static int SWIG_Lua_ConvertPtr(lua_State *L, int index, void **ptr, swig_type_info *type, int flags)
Definition: swigluarun.h:2481
#define SWIG_NewPointerObj(L, ptr, type, owner)
Definition: swigluarun.h:1019
static swig_type_info * SWIG_TypeQuery(lua_State *clientdata, const char *name)
Definition: swigluarun.h:2674
#define SWIG_OK
Definition: swigluarun.h:280