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