Added support to create arbitrary named lists of shared vars (separate from Engine's global). Added extra functions to shared vars list. Export in javascript.

git-svn-id: http://yate.null.ro/svn/yate/trunk@6521 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2021-09-28 10:55:08 +00:00
parent ca208774e0
commit de95fc5171
3 changed files with 277 additions and 51 deletions

View File

@ -109,6 +109,21 @@ public:
static void doCompletion(Message &msg, const String& partLine, const String& partWord); static void doCompletion(Message &msg, const String& partLine, const String& partWord);
}; };
class EngineSharedPrivate
{
public:
inline EngineSharedPrivate()
: vars(new SharedVars),
varsListMutex(false,"SharedVarsList")
{}
inline ~EngineSharedPrivate()
{ TelEngine::destruct(vars); }
SharedVars* vars;
ObjList varsList;
Mutex varsListMutex;
};
}; };
using namespace TelEngine; using namespace TelEngine;
@ -295,7 +310,7 @@ static int s_maxevents = 25;
static Mutex s_eventsMutex(false,"EventsList"); static Mutex s_eventsMutex(false,"EventsList");
static ObjList s_events; static ObjList s_events;
static String s_startMsg; static String s_startMsg;
static SharedVars s_vars; static EngineSharedPrivate s_vars;
static Mutex s_hooksMutex(true,"HooksList"); static Mutex s_hooksMutex(true,"HooksList");
static ObjList s_hooks; static ObjList s_hooks;
static Semaphore* s_semWorkers = 0; static Semaphore* s_semWorkers = 0;
@ -1449,29 +1464,37 @@ void SharedVars::clear(const String& name)
unlock(); unlock();
} }
void SharedVars::clearAll()
{
if (this == &Engine::sharedVars())
return;
Lock mylock(this);
m_vars.clearParams();
}
bool SharedVars::exists(const String& name) bool SharedVars::exists(const String& name)
{ {
Lock mylock(this); Lock mylock(this);
return m_vars.getParam(name) != 0; return m_vars.getParam(name) != 0;
} }
unsigned int SharedVars::inc(const String& name, unsigned int wrap) uint64_t SharedVars::inc(const String& name, uint64_t wrap)
{ {
Lock mylock(this); Lock mylock(this);
unsigned int val = m_vars.getIntValue(name); uint64_t val = m_vars.getUInt64Value(name);
if (wrap) if (wrap)
val = val % (wrap + 1); val = val % (wrap + 1);
unsigned int nval = val + 1; uint64_t nval = val + 1;
if (wrap) if (wrap)
nval = nval % (wrap + 1); nval = nval % (wrap + 1);
m_vars.setParam(name,String(nval)); m_vars.setParam(name,String(nval));
return val; return val;
} }
unsigned int SharedVars::dec(const String& name, unsigned int wrap) uint64_t SharedVars::dec(const String& name, uint64_t wrap)
{ {
Lock mylock(this); Lock mylock(this);
unsigned int val = m_vars.getIntValue(name); uint64_t val = m_vars.getUInt64Value(name);
if (wrap) if (wrap)
val = val ? ((val - 1) % (wrap + 1)) : wrap; val = val ? ((val - 1) % (wrap + 1)) : wrap;
else else
@ -1480,6 +1503,46 @@ unsigned int SharedVars::dec(const String& name, unsigned int wrap)
return val; return val;
} }
uint64_t SharedVars::add(const String& name, uint64_t value, uint64_t wrap)
{
Lock mylock(this);
uint64_t val = m_vars.getUInt64Value(name);
if (wrap)
val = val % (wrap + 1);
uint64_t nval = val + value;
if (wrap)
nval = nval % (wrap + 1);
m_vars.setParam(name,String(nval));
return val;
}
uint64_t SharedVars::sub(const String& name, uint64_t value, uint64_t wrap)
{
Lock mylock(this);
uint64_t val = m_vars.getUInt64Value(name);
if (wrap)
val = (val >= value) ? ((val - value) % (wrap + 1)) : wrap;
else
val = (val >= value) ? (val - value) : 0;
m_vars.setParam(name,String(val));
return val;
}
bool SharedVars::getList(RefPointer<SharedVars>& dest, const String& name)
{
if (!name)
return false;
Lock lck(s_vars.varsListMutex);
ObjList* o = s_vars.varsList.find(name);
if (o)
dest = static_cast<SharedVars*>(o->get());
else {
dest = new SharedVars(name);
s_vars.varsList.append(dest);
}
return 0 != dest;
}
Engine::Engine() Engine::Engine()
: m_dispatchedLast(0), m_messageRate(0), m_maxMsgRate(0), : m_dispatchedLast(0), m_messageRate(0), m_maxMsgRate(0),
@ -1697,7 +1760,7 @@ int Engine::engineInit()
for (unsigned int i = 0; i < n; i++) { for (unsigned int i = 0; i < n; i++) {
NamedString* v = vars->getParam(i); NamedString* v = vars->getParam(i);
if (v) if (v)
s_vars.set(v->name(),*v); s_vars.vars->set(v->name(),*v);
} }
} }
DDebug(DebugAll,"Engine::run()"); DDebug(DebugAll,"Engine::run()");
@ -2396,7 +2459,7 @@ void Engine::clearEvents(const String& type)
SharedVars& Engine::sharedVars() SharedVars& Engine::sharedVars()
{ {
return s_vars; return *(s_vars.vars);
} }
// Append command line arguments form current config. // Append command line arguments form current config.

View File

@ -190,17 +190,50 @@ class JsShared : public JsObject
YCLASS(JsShared,JsObject) YCLASS(JsShared,JsObject)
public: public:
inline JsShared(ScriptMutex* mtx) inline JsShared(ScriptMutex* mtx)
: JsObject("Shared",mtx,true) : JsObject("SharedVars",mtx,true)
{ {
params().addParam(new ExpFunction("inc")); params().addParam(new ExpFunction("inc"));
params().addParam(new ExpFunction("dec")); params().addParam(new ExpFunction("dec"));
params().addParam(new ExpFunction("get")); params().addParam(new ExpFunction("get"));
params().addParam(new ExpFunction("set")); params().addParam(new ExpFunction("set"));
params().addParam(new ExpFunction("add"));
params().addParam(new ExpFunction("sub"));
params().addParam(new ExpFunction("clear")); params().addParam(new ExpFunction("clear"));
params().addParam(new ExpFunction("clearAll"));
params().addParam(new ExpFunction("exists")); params().addParam(new ExpFunction("exists"));
params().addParam(new ExpFunction("getVars"));
setVars(String::empty());
} }
inline JsShared(ScriptMutex* mtx, unsigned int line, const String& varsName = String::empty())
: JsObject(mtx,"[object SharedVars]",line)
{ setVars(varsName); }
virtual JsObject* runConstructor(ObjList& stack, const ExpOperation& oper, GenObject* context);
static void initialize(ScriptContext* context);
static inline uint64_t modulo(ExpOperation* mod) {
if (!(mod && mod->isInteger()))
return 0;
int64_t m = mod->number();
return m > 1 ? --m : 0;
}
protected: protected:
inline void setVars(const String& name) {
if (!name)
m_vars = &Engine::sharedVars();
else
SharedVars::getList(m_vars,name);
m_varsName = name;
}
inline JsShared(ScriptMutex* mtx, const char* name, unsigned int line, const String& varsName = String::empty())
: JsObject(mtx,name,line)
{ setVars(varsName); }
virtual JsObject* clone(const char* name, const ExpOperation& oper) const
{ return new JsShared(mutex(),name,oper.lineNumber(),m_varsName); }
bool runNative(ObjList& stack, const ExpOperation& oper, GenObject* context); bool runNative(ObjList& stack, const ExpOperation& oper, GenObject* context);
private:
RefPointer<SharedVars> m_vars;
String m_varsName;
}; };
class JsTimeEvent : public RefObject class JsTimeEvent : public RefObject
@ -459,9 +492,10 @@ public:
params().addParam(new ExpFunction("htoa")); params().addParam(new ExpFunction("htoa"));
params().addParam(new ExpFunction("btoh")); params().addParam(new ExpFunction("btoh"));
params().addParam(new ExpFunction("htob")); params().addParam(new ExpFunction("htob"));
addConstructor(params(), "Semaphore", new JsSemaphore(mtx)); addConstructor(params(),"Semaphore",new JsSemaphore(mtx));
addConstructor(params(),"HashList",new JsHashList(mtx)); addConstructor(params(),"HashList",new JsHashList(mtx));
addConstructor(params(),"URI",new JsURI(mtx)); addConstructor(params(),"URI",new JsURI(mtx));
addConstructor(params(),"SharedVars",new JsShared(mtx));
} }
static void initialize(ScriptContext* context, const char* name = 0); static void initialize(ScriptContext* context, const char* name = 0);
inline void resetWorker() inline void resetWorker()
@ -1076,6 +1110,7 @@ static void contextInit(ScriptRun* runner, const char* name = 0, JsAssist* assis
JsHasher::initialize(ctx); JsHasher::initialize(ctx);
JsJSON::initialize(ctx); JsJSON::initialize(ctx);
JsDNS::initialize(ctx); JsDNS::initialize(ctx);
JsShared::initialize(ctx);
if (s_autoExt) if (s_autoExt)
contextLoad(ctx,name); contextLoad(ctx,name);
} }
@ -2142,43 +2177,25 @@ bool JsShared::runNative(ObjList& stack, const ExpOperation& oper, GenObject* co
XDebug(&__plugin,DebugAll,"JsShared::runNative '%s'(" FMT64 ")",oper.name().c_str(),oper.number()); XDebug(&__plugin,DebugAll,"JsShared::runNative '%s'(" FMT64 ")",oper.name().c_str(),oper.number());
if (oper.name() == YSTRING("inc")) { if (oper.name() == YSTRING("inc")) {
ObjList args; ObjList args;
switch (extractArgs(stack,oper,context,args)) { ExpOperation* param = 0;
case 1: ExpOperation* mod = 0;
case 2: if (!extractStackArgs(1,this,stack,oper,context,args,&param,&mod))
break; return false;
default: if (m_vars)
return false; ExpEvaluator::pushOne(stack,new ExpOperation((int64_t)m_vars->inc(*param,modulo(mod))));
}
ExpOperation* param = static_cast<ExpOperation*>(args[0]);
ExpOperation* modulo = static_cast<ExpOperation*>(args[1]);
int mod = 0;
if (modulo && modulo->isInteger())
mod = (int)modulo->number();
if (mod > 1)
mod--;
else else
mod = 0; ExpEvaluator::pushOne(stack,JsParser::nullClone());
ExpEvaluator::pushOne(stack,new ExpOperation((int64_t)Engine::sharedVars().inc(*param,mod)));
} }
else if (oper.name() == YSTRING("dec")) { else if (oper.name() == YSTRING("dec")) {
ObjList args; ObjList args;
switch (extractArgs(stack,oper,context,args)) { ExpOperation* param = 0;
case 1: ExpOperation* mod = 0;
case 2: if (!extractStackArgs(1,this,stack,oper,context,args,&param,&mod))
break; return false;
default: if (m_vars)
return false; ExpEvaluator::pushOne(stack,new ExpOperation((int64_t)m_vars->dec(*param,modulo(mod))));
}
ExpOperation* param = static_cast<ExpOperation*>(args[0]);
ExpOperation* modulo = static_cast<ExpOperation*>(args[1]);
int mod = 0;
if (modulo && modulo->isInteger())
mod = (int)modulo->number();
if (mod > 1)
mod--;
else else
mod = 0; ExpEvaluator::pushOne(stack,JsParser::nullClone());
ExpEvaluator::pushOne(stack,new ExpOperation((int64_t)Engine::sharedVars().dec(*param,mod)));
} }
else if (oper.name() == YSTRING("get")) { else if (oper.name() == YSTRING("get")) {
if (oper.number() != 1) if (oper.number() != 1)
@ -2187,7 +2204,8 @@ bool JsShared::runNative(ObjList& stack, const ExpOperation& oper, GenObject* co
if (!param) if (!param)
return false; return false;
String buf; String buf;
Engine::sharedVars().get(*param,buf); if (m_vars)
m_vars->get(*param,buf);
TelEngine::destruct(param); TelEngine::destruct(param);
ExpEvaluator::pushOne(stack,new ExpOperation(buf)); ExpEvaluator::pushOne(stack,new ExpOperation(buf));
} }
@ -2202,33 +2220,123 @@ bool JsShared::runNative(ObjList& stack, const ExpOperation& oper, GenObject* co
TelEngine::destruct(val); TelEngine::destruct(val);
return false; return false;
} }
Engine::sharedVars().set(*param,*val); if (m_vars)
m_vars->set(*param,*val);
TelEngine::destruct(param); TelEngine::destruct(param);
TelEngine::destruct(val); TelEngine::destruct(val);
} }
else if (oper.name() == YSTRING("add") || oper.name() == YSTRING("sub")) {
ObjList args;
ExpOperation* param = 0;
ExpOperation* val = 0;
ExpOperation* mod = 0;
if (!extractStackArgs(2,this,stack,oper,context,args,&param,&val,&mod))
return false;
if (m_vars) {
int64_t value = val->isInteger() ? val->number() : 0;
if (oper.name() == YSTRING("add"))
value = (int64_t)m_vars->add(*param,value > 0 ? value : 0,modulo(mod));
else
value = (int64_t)m_vars->sub(*param,value > 0 ? value : 0,modulo(mod));
ExpEvaluator::pushOne(stack,new ExpOperation(value));
}
else
ExpEvaluator::pushOne(stack,JsParser::nullClone());
}
else if (oper.name() == YSTRING("clear")) { else if (oper.name() == YSTRING("clear")) {
if (oper.number() != 1) if (oper.number() != 1)
return false; return false;
ExpOperation* param = popValue(stack,context); ExpOperation* param = popValue(stack,context);
if (!param) if (!param)
return false; return false;
Engine::sharedVars().clear(*param); if (m_vars)
m_vars->clear(*param);
TelEngine::destruct(param); TelEngine::destruct(param);
} }
else if (oper.name() == YSTRING("clearAll")) {
if (m_vars)
m_vars->clearAll();
}
else if (oper.name() == YSTRING("exists")) { else if (oper.name() == YSTRING("exists")) {
if (oper.number() != 1) if (oper.number() != 1)
return false; return false;
ExpOperation* param = popValue(stack,context); ExpOperation* param = popValue(stack,context);
if (!param) if (!param)
return false; return false;
ExpEvaluator::pushOne(stack,new ExpOperation(Engine::sharedVars().exists(*param))); ExpEvaluator::pushOne(stack,new ExpOperation(m_vars && m_vars->exists(*param)));
TelEngine::destruct(param); TelEngine::destruct(param);
} }
else if (oper.name() == YSTRING("getVars")) {
// getVars([params])
// params:
// js_props: Boolean. Force Javascript ExpOperation in returned result. Default: true
// autonum: Boolean. Force ExpOperation auto number in returned result. Default: false.
// Ignored if not returning ExpOperation
// prefix: String. Optional prefix for variables
// skip_prefix: Boolean. Skip prefix when returned. Default: true. Ignored if prefix is empty
ObjList args;
ExpOperation* pOp = 0;
if (!extractStackArgs(0,this,stack,oper,context,args,&pOp))
return false;
if (m_vars) {
bool expOper = true;
bool autoNum = false;
String prefix;
bool skipPrefix = true;
JsObject* params = YOBJECT(JsObject,pOp);
if (params) {
params->getBoolField(YSTRING("js_props"),expOper);
if (expOper)
params->getBoolField(YSTRING("autonum"),autoNum);
params->getStringField(YSTRING("prefix"),prefix);
if (prefix)
params->getBoolField(YSTRING("skip_prefix"),skipPrefix);
}
JsObject* jso = new JsObject(context,oper.lineNumber(),mutex());
if (expOper) {
NamedList tmp("");
m_vars->copy(tmp,prefix,skipPrefix);
for (ObjList* o = tmp.paramList()->skipNull(); o; o = o->skipNext()) {
NamedString* ns = static_cast<NamedString*>(o->get());
jso->params().addParam(new ExpOperation(*ns,ns->name(),autoNum));
}
}
else
m_vars->copy(jso->params(),prefix,skipPrefix);
ExpEvaluator::pushOne(stack,new ExpWrapper(jso,"vars"));
}
else
ExpEvaluator::pushOne(stack,JsParser::nullClone());
}
else else
return JsObject::runNative(stack,oper,context); return JsObject::runNative(stack,oper,context);
return true; return true;
} }
JsObject* JsShared::runConstructor(ObjList& stack, const ExpOperation& oper, GenObject* context)
{
ObjList args;
ExpOperation* sharedOp = 0;
if (!extractStackArgs(1,this,stack,oper,context,args,&sharedOp))
return 0;
JsShared* obj = new JsShared(mutex(),oper.lineNumber(),*sharedOp);
if (ref())
obj->params().addParam(new ExpWrapper(this,protoName()));
else
TelEngine::destruct(obj);
return obj;
}
void JsShared::initialize(ScriptContext* context)
{
if (!context)
return;
ScriptMutex* mtx = context->mutex();
Lock mylock(mtx);
NamedList& params = context->params();
if (!params.getParam(YSTRING("SharedVars")))
addObject(params,"SharedVars",new JsShared(mtx));
}
void* JsMessage::getObject(const String& name) const void* JsMessage::getObject(const String& name) const
{ {

View File

@ -236,14 +236,15 @@ private:
* Class that implements atomic / locked access and operations to its shared variables * Class that implements atomic / locked access and operations to its shared variables
* @short Atomic access and operations to shared variables * @short Atomic access and operations to shared variables
*/ */
class YATE_API SharedVars : public Mutex class YATE_API SharedVars : public Mutex, public RefObject
{ {
public: public:
/** /**
* Constructor * Constructor
* @param name Optional name
*/ */
inline SharedVars() inline SharedVars(const char* name = 0)
: Mutex(false,"SharedVars"), m_vars("") : Mutex(false,"SharedVars"), m_vars(name)
{ } { }
/** /**
@ -274,6 +275,11 @@ public:
*/ */
void clear(const String& name); void clear(const String& name);
/**
* Clear all variables. Does nothing for Engine (global shared list)
*/
void clearAll();
/** /**
* Check if a variable exists * Check if a variable exists
* @param name Name of the variable * @param name Name of the variable
@ -287,7 +293,7 @@ public:
* @param wrap Value to wrap around at, zero disables * @param wrap Value to wrap around at, zero disables
* @return Value of the variable before increment, zero if it was not defined or not numeric * @return Value of the variable before increment, zero if it was not defined or not numeric
*/ */
unsigned int inc(const String& name, unsigned int wrap = 0); uint64_t inc(const String& name, uint64_t wrap = 0);
/** /**
* Atomically decrement a variable as unsigned integer * Atomically decrement a variable as unsigned integer
@ -295,7 +301,56 @@ public:
* @param wrap Value to wrap around at, zero disables (stucks at zero) * @param wrap Value to wrap around at, zero disables (stucks at zero)
* @return Value of the variable after decrement, zero if it was not defined or not numeric * @return Value of the variable after decrement, zero if it was not defined or not numeric
*/ */
unsigned int dec(const String& name, unsigned int wrap = 0); uint64_t dec(const String& name, uint64_t wrap = 0);
/**
* Atomically add a value to a variable as unsigned integer
* @param name Name of the variable
* @param val Value to add
* @param wrap Value to wrap around at, zero disables
* @return Value of the variable before addition, zero if it was not defined or not numeric
*/
uint64_t add(const String& name, uint64_t val, uint64_t wrap = 0);
/**
* Atomically substract a value from a variable as unsigned integer
* @param name Name of the variable
* @param val Value to substract
* @param wrap Value to wrap around at, zero disables
* @return Value of the variable after substraction, zero if it was not defined or not numeric
*/
uint64_t sub(const String& name, uint64_t val, uint64_t wrap = 0);
/**
* Atomically copy parameters to destination
* @param dest Destination list
* @param prefix Optional prefix to match in parameter names
* @param skipPrefix Skip over the prefix when building new parameter name
* @param replace Set to true to replace list parameter instead of adding a new one
*/
inline void copy(NamedList& dest, const String& prefix = String::empty(),
bool skipPrefix = true, bool replace = false) {
Lock lck(this);
if (prefix)
dest.copySubParams(m_vars,prefix,skipPrefix,replace);
else
dest.copyParams(m_vars);
}
/**
* Retrieve list name
* @return List name
*/
virtual const String& toString() const
{ return m_vars; }
/**
* Retrieve a named list of SharedVars. Create it if not found
* @param dest Destination to be filled with requested list
* @param name Name of the list
* @return True id destination is iset. The function will fail if name is empty
*/
static bool getList(RefPointer<SharedVars>& dest, const String& name);
private: private:
NamedList m_vars; NamedList m_vars;