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);
};
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;
@ -295,7 +310,7 @@ static int s_maxevents = 25;
static Mutex s_eventsMutex(false,"EventsList");
static ObjList s_events;
static String s_startMsg;
static SharedVars s_vars;
static EngineSharedPrivate s_vars;
static Mutex s_hooksMutex(true,"HooksList");
static ObjList s_hooks;
static Semaphore* s_semWorkers = 0;
@ -1449,29 +1464,37 @@ void SharedVars::clear(const String& name)
unlock();
}
void SharedVars::clearAll()
{
if (this == &Engine::sharedVars())
return;
Lock mylock(this);
m_vars.clearParams();
}
bool SharedVars::exists(const String& name)
{
Lock mylock(this);
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);
unsigned int val = m_vars.getIntValue(name);
uint64_t val = m_vars.getUInt64Value(name);
if (wrap)
val = val % (wrap + 1);
unsigned int nval = val + 1;
uint64_t nval = val + 1;
if (wrap)
nval = nval % (wrap + 1);
m_vars.setParam(name,String(nval));
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);
unsigned int val = m_vars.getIntValue(name);
uint64_t val = m_vars.getUInt64Value(name);
if (wrap)
val = val ? ((val - 1) % (wrap + 1)) : wrap;
else
@ -1480,6 +1503,46 @@ unsigned int SharedVars::dec(const String& name, unsigned int wrap)
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()
: m_dispatchedLast(0), m_messageRate(0), m_maxMsgRate(0),
@ -1697,7 +1760,7 @@ int Engine::engineInit()
for (unsigned int i = 0; i < n; i++) {
NamedString* v = vars->getParam(i);
if (v)
s_vars.set(v->name(),*v);
s_vars.vars->set(v->name(),*v);
}
}
DDebug(DebugAll,"Engine::run()");
@ -2396,7 +2459,7 @@ void Engine::clearEvents(const String& type)
SharedVars& Engine::sharedVars()
{
return s_vars;
return *(s_vars.vars);
}
// Append command line arguments form current config.

View File

@ -190,17 +190,50 @@ class JsShared : public JsObject
YCLASS(JsShared,JsObject)
public:
inline JsShared(ScriptMutex* mtx)
: JsObject("Shared",mtx,true)
: JsObject("SharedVars",mtx,true)
{
params().addParam(new ExpFunction("inc"));
params().addParam(new ExpFunction("dec"));
params().addParam(new ExpFunction("get"));
params().addParam(new ExpFunction("set"));
params().addParam(new ExpFunction("add"));
params().addParam(new ExpFunction("sub"));
params().addParam(new ExpFunction("clear"));
params().addParam(new ExpFunction("clearAll"));
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:
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);
private:
RefPointer<SharedVars> m_vars;
String m_varsName;
};
class JsTimeEvent : public RefObject
@ -459,9 +492,10 @@ public:
params().addParam(new ExpFunction("htoa"));
params().addParam(new ExpFunction("btoh"));
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(),"URI",new JsURI(mtx));
addConstructor(params(),"SharedVars",new JsShared(mtx));
}
static void initialize(ScriptContext* context, const char* name = 0);
inline void resetWorker()
@ -1076,6 +1110,7 @@ static void contextInit(ScriptRun* runner, const char* name = 0, JsAssist* assis
JsHasher::initialize(ctx);
JsJSON::initialize(ctx);
JsDNS::initialize(ctx);
JsShared::initialize(ctx);
if (s_autoExt)
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());
if (oper.name() == YSTRING("inc")) {
ObjList args;
switch (extractArgs(stack,oper,context,args)) {
case 1:
case 2:
break;
default:
return false;
}
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--;
ExpOperation* param = 0;
ExpOperation* mod = 0;
if (!extractStackArgs(1,this,stack,oper,context,args,&param,&mod))
return false;
if (m_vars)
ExpEvaluator::pushOne(stack,new ExpOperation((int64_t)m_vars->inc(*param,modulo(mod))));
else
mod = 0;
ExpEvaluator::pushOne(stack,new ExpOperation((int64_t)Engine::sharedVars().inc(*param,mod)));
ExpEvaluator::pushOne(stack,JsParser::nullClone());
}
else if (oper.name() == YSTRING("dec")) {
ObjList args;
switch (extractArgs(stack,oper,context,args)) {
case 1:
case 2:
break;
default:
return false;
}
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--;
ExpOperation* param = 0;
ExpOperation* mod = 0;
if (!extractStackArgs(1,this,stack,oper,context,args,&param,&mod))
return false;
if (m_vars)
ExpEvaluator::pushOne(stack,new ExpOperation((int64_t)m_vars->dec(*param,modulo(mod))));
else
mod = 0;
ExpEvaluator::pushOne(stack,new ExpOperation((int64_t)Engine::sharedVars().dec(*param,mod)));
ExpEvaluator::pushOne(stack,JsParser::nullClone());
}
else if (oper.name() == YSTRING("get")) {
if (oper.number() != 1)
@ -2187,7 +2204,8 @@ bool JsShared::runNative(ObjList& stack, const ExpOperation& oper, GenObject* co
if (!param)
return false;
String buf;
Engine::sharedVars().get(*param,buf);
if (m_vars)
m_vars->get(*param,buf);
TelEngine::destruct(param);
ExpEvaluator::pushOne(stack,new ExpOperation(buf));
}
@ -2202,33 +2220,123 @@ bool JsShared::runNative(ObjList& stack, const ExpOperation& oper, GenObject* co
TelEngine::destruct(val);
return false;
}
Engine::sharedVars().set(*param,*val);
if (m_vars)
m_vars->set(*param,*val);
TelEngine::destruct(param);
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")) {
if (oper.number() != 1)
return false;
ExpOperation* param = popValue(stack,context);
if (!param)
return false;
Engine::sharedVars().clear(*param);
if (m_vars)
m_vars->clear(*param);
TelEngine::destruct(param);
}
else if (oper.name() == YSTRING("clearAll")) {
if (m_vars)
m_vars->clearAll();
}
else if (oper.name() == YSTRING("exists")) {
if (oper.number() != 1)
return false;
ExpOperation* param = popValue(stack,context);
if (!param)
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);
}
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
return JsObject::runNative(stack,oper,context);
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
{

View File

@ -236,14 +236,15 @@ private:
* Class that implements atomic / locked access and operations to its 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:
/**
* Constructor
* @param name Optional name
*/
inline SharedVars()
: Mutex(false,"SharedVars"), m_vars("")
inline SharedVars(const char* name = 0)
: Mutex(false,"SharedVars"), m_vars(name)
{ }
/**
@ -274,6 +275,11 @@ public:
*/
void clear(const String& name);
/**
* Clear all variables. Does nothing for Engine (global shared list)
*/
void clearAll();
/**
* Check if a variable exists
* @param name Name of the variable
@ -287,7 +293,7 @@ public:
* @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
*/
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
@ -295,7 +301,56 @@ public:
* @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
*/
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:
NamedList m_vars;